1aa84222d2c8963b40a30e619d26bb4eb958c310
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / livevideo / livevideo.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
25 #include "channel.h"
26 #include "channeldb.h"
27 #include "clip.h"
28 #include "bchash.h"
29 #include "edl.h"
30 #include "edlsession.h"
31 #include "filexml.h"
32 #include "guicast.h"
33 #include "language.h"
34 #include "libdv.h"
35 #include "libmjpeg.h"
36 #include "mwindow.h"
37 #include "picture.h"
38 #include "pluginvclient.h"
39 #include "pluginserver.h"
40 #include "recordconfig.h"
41 #include "transportque.inc"
42 #include "vframe.h"
43 #include "videodevice.h"
44 #include "videodevice.inc"
45
46 #include <string.h>
47 #include <stdint.h>
48
49 #define HISTORY_FRAMES 30
50 class LiveVideo;
51 class LiveVideoWindow;
52
53
54 class LiveVideoConfig
55 {
56 public:
57         LiveVideoConfig();
58         void copy_from(LiveVideoConfig &src);
59         int equivalent(LiveVideoConfig &src);
60         void interpolate(LiveVideoConfig &prev,
61                 LiveVideoConfig &next,
62                 int64_t prev_frame,
63                 int64_t next_frame,
64                 int64_t current_frame);
65         int channel;
66 };
67
68
69 // Without access to the video device, the ChannelPicker can't
70 // do any of the things it was designed to.  Instead, just provide
71 // a list of channels.
72 class LiveChannelList : public BC_ListBox
73 {
74 public:
75         LiveChannelList(LiveVideo *plugin,
76                 LiveVideoWindow *gui,
77                 int x,
78                 int y,
79                 int w,
80                 int h);
81         int handle_event();
82         LiveVideo *plugin;
83         LiveVideoWindow *gui;
84 };
85
86 class LiveChannelSelect : public BC_Button
87 {
88 public:
89         LiveChannelSelect(LiveVideo *plugin,
90                 LiveVideoWindow *gui,
91                 int x,
92                 int y);
93         int handle_event();
94         LiveVideo *plugin;
95         LiveVideoWindow *gui;
96 };
97
98
99 class LiveVideoWindow : public PluginClientWindow
100 {
101 public:
102         LiveVideoWindow(LiveVideo *plugin);
103         ~LiveVideoWindow();
104
105         void create_objects();
106
107         int resize_event(int w, int h);
108
109         ArrayList<BC_ListBoxItem*> channel_list;
110         BC_Title *title;
111         LiveChannelList *list;
112         LiveChannelSelect *select;
113         LiveVideo *plugin;
114 };
115
116
117
118
119
120
121 class LiveVideo : public PluginVClient
122 {
123 public:
124         LiveVideo(PluginServer *server);
125         ~LiveVideo();
126
127
128         PLUGIN_CLASS_MEMBERS(LiveVideoConfig);
129
130         int process_buffer(VFrame *frame,
131                 int64_t start_position,
132                 double frame_rate);
133         int is_realtime();
134         int is_multichannel();
135         int is_synthesis();
136         void save_data(KeyFrame *keyframe);
137         void read_data(KeyFrame *keyframe);
138         void update_gui();
139         void render_stop();
140
141         ChannelDB *channeldb;
142         VideoDevice *vdevice;
143 // Colormodel the device generates
144         int input_cmodel;
145 // Temporary for colormodel conversion
146         VFrame *temp;
147 // What configuration parameters the device supports
148         Channel master_channel;
149         PictureConfig *picture;
150         int prev_channel;
151         int w, h;
152 // Decompressors for different video drivers
153         dv_t *dv;
154         mjpeg_t *mjpeg;
155 };
156
157
158
159
160
161
162
163
164
165
166
167
168 LiveVideoConfig::LiveVideoConfig()
169 {
170         channel = 0;
171 }
172
173 void LiveVideoConfig::copy_from(LiveVideoConfig &src)
174 {
175         this->channel = src.channel;
176 }
177
178 int LiveVideoConfig::equivalent(LiveVideoConfig &src)
179 {
180         return (this->channel == src.channel);
181 }
182
183 void LiveVideoConfig::interpolate(LiveVideoConfig &prev,
184         LiveVideoConfig &next,
185         int64_t prev_frame,
186         int64_t next_frame,
187         int64_t current_frame)
188 {
189         this->channel = prev.channel;
190 }
191
192
193
194
195
196 LiveVideoWindow::LiveVideoWindow(LiveVideo *plugin)
197  : PluginClientWindow(plugin,
198         plugin->w,
199         plugin->h,
200         xS(100),
201         yS(100),
202         1)
203 {
204         this->plugin = plugin;
205 }
206
207 LiveVideoWindow::~LiveVideoWindow()
208 {
209         channel_list.remove_all_objects();
210 }
211
212 void LiveVideoWindow::create_objects()
213 {
214         int xs10 = xS(10);
215         int ys5 = yS(5), ys10 = yS(10);
216         int x = xs10, y = ys10;
217
218         EDLSession *session = plugin->get_edl()->session;
219         if(session)
220                 VideoDevice::load_channeldb(plugin->channeldb, session->vconfig_in);
221         for(int i = 0; i < plugin->channeldb->size(); i++)
222         {
223                 BC_ListBoxItem *current;
224                 channel_list.append(current =
225                         new BC_ListBoxItem(plugin->channeldb->get(i)->title));
226                 if(i == plugin->config.channel) current->set_selected(1);
227         }
228
229         add_subwindow(title = new BC_Title(x, y, _("Channels:")));
230         y += title->get_h() + ys5;
231         add_subwindow(list = new LiveChannelList(plugin,
232                 this,
233                 x,
234                 y,
235                 get_w() - x - xs10,
236                 get_h() - y - BC_OKButton::calculate_h() - ys10 - ys10));
237         y += list->get_h() + ys10;
238         add_subwindow(select = new LiveChannelSelect(plugin,
239                 this,
240                 x,
241                 y));
242         show_window();
243 }
244
245
246
247 int LiveVideoWindow::resize_event(int w, int h)
248 {
249         int list_bottom = get_h() - list->get_y() - list->get_h();
250         int list_side = get_w() - list->get_x() - list->get_w();
251         int select_top = get_h() - select->get_y();
252
253         title->reposition_window(title->get_x(), title->get_y());
254
255         list->reposition_window(list->get_x(),
256                 list->get_y(),
257                 w - list->get_x() - list_side,
258                 h - list->get_y() - list_bottom);
259         select->reposition_window(select->get_x(),
260                 h - select_top);
261         plugin->w = w;
262         plugin->h = h;
263         return 1;
264 }
265
266
267
268
269 LiveChannelList::LiveChannelList(LiveVideo *plugin,
270         LiveVideoWindow *gui,
271         int x,
272         int y,
273         int w,
274         int h)
275  : BC_ListBox(x,
276         y,
277         w,
278         h,
279         LISTBOX_TEXT,                   // Display text list or icons
280         &gui->channel_list) // Each column has an ArrayList of BC_ListBoxItems.
281 {
282         this->plugin = plugin;
283         this->gui = gui;
284 }
285
286 int LiveChannelList::handle_event()
287 {
288         plugin->config.channel = get_selection_number(0, 0);
289         plugin->send_configure_change();
290         return 1;
291 }
292
293
294 LiveChannelSelect::LiveChannelSelect(LiveVideo *plugin,
295         LiveVideoWindow *gui,
296         int x,
297         int y)
298  :  BC_Button(x, y,
299         BC_WindowBase::get_resources()->ok_images)
300 {
301         this->plugin = plugin;
302         this->gui = gui;
303 }
304
305 int LiveChannelSelect::handle_event()
306 {
307         plugin->config.channel = gui->list->get_selection_number(0, 0);
308         plugin->send_configure_change();
309         return 1;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 REGISTER_PLUGIN(LiveVideo)
338
339
340
341
342
343
344 LiveVideo::LiveVideo(PluginServer *server)
345  : PluginVClient(server)
346 {
347         vdevice = 0;
348         temp = 0;
349         channeldb = new ChannelDB;
350         w = xS(320);
351         h = yS(640);
352         prev_channel = 0;
353         dv = 0;
354         mjpeg = 0;
355         picture = 0;
356         this->server = server;
357
358 }
359
360
361 LiveVideo::~LiveVideo()
362 {
363
364         if(vdevice)
365         {
366                 vdevice->interrupt_crash();
367                 vdevice->close_all();
368                 delete vdevice;
369         }
370
371         delete channeldb;
372         delete temp;
373         if(dv) dv_delete(dv);
374         if(mjpeg) mjpeg_delete(mjpeg);
375         delete picture;
376 }
377
378
379
380 int LiveVideo::process_buffer(VFrame *frame,
381         int64_t start_position,
382         double frame_rate)
383 {
384         load_configuration();
385 //printf("LiveVideo::process_buffer 10 start_position=%lld buffer_size=%d size=%d\n",
386 //start_position, get_buffer_size(), size);
387
388         EDLSession *session = get_edl()->session;
389         if(!vdevice)
390         {
391                 if(session)
392                 {
393                         vdevice = new VideoDevice(server ? server->mwindow : 0);
394                         vdevice->open_input(session->vconfig_in,
395                                 0,
396                                 0,
397                                 1.0,
398                                 frame_rate);
399
400 // The color model depends on the asset configured by the user for recording.
401 // Unfortunately, get_best_colormodel returns the best colormodel for displaying
402 // on the record monitor, not the colormodel supported by the device.
403 // Some devices can read directly to the best colormodel and some can't.
404                         switch(session->vconfig_in->driver)
405                         {
406                                 case CAPTURE_FIREWIRE:
407                                 case CAPTURE_IEC61883:
408                                 case VIDEO4LINUX2JPEG:
409                                 case CAPTURE_JPEG_WEBCAM:
410                                         input_cmodel = BC_COMPRESSED;
411                                         break;
412                                 default:
413                                         input_cmodel = vdevice->get_best_colormodel(session->recording_format);
414                                         break;
415                         }
416
417
418 // Load the picture config from the main defaults file.
419
420 // Load channel table
421                         VideoDevice::load_channeldb(channeldb, session->vconfig_in);
422
423                         if(!picture)
424                         {
425                                 picture = new PictureConfig;
426                                 picture->load_defaults();
427                         }
428
429 // Picture must have usage from driver before it can load defaults.
430                         master_channel.copy_usage(vdevice->channel);
431                         picture->copy_usage(vdevice->picture);
432                         picture->load_defaults();
433
434 // Need to load picture defaults but this requires MWindow.
435                         vdevice->set_picture(picture);
436                         vdevice->set_channel(channeldb->get(config.channel));
437                 }
438                 prev_channel = config.channel;
439         }
440
441         if(session && vdevice)
442         {
443 // Update channel
444                 if(prev_channel != config.channel)
445                 {
446                         prev_channel = config.channel;
447                         vdevice->set_picture(picture);
448                         vdevice->set_channel(channeldb->get(config.channel));
449                 }
450
451
452                 (void)vdevice->config_updated();
453                 VFrame *input = frame;
454                 if(input_cmodel != frame->get_color_model() ||
455                         session->vconfig_in->w != frame->get_w() ||
456                         session->vconfig_in->h != frame->get_h())
457                 {
458                         if(!temp)
459                         {
460                                 temp = new VFrame(session->vconfig_in->w, session->vconfig_in->h,
461                                                 input_cmodel, 0);
462                         }
463                         input = temp;
464                 }
465
466                 vdevice->read_buffer(input);
467
468                 if(input != frame)
469                 {
470                         if(input->get_color_model() != BC_COMPRESSED)
471                         {
472                                 int w = MIN(session->vconfig_in->w, frame->get_w());
473                                 int h = MIN(session->vconfig_in->h, frame->get_h());
474                                 BC_CModels::transfer(frame->get_rows(), /* Leave NULL if non existent */
475                                         input->get_rows(),
476                                         frame->get_y(), /* Leave NULL if non existent */
477                                         frame->get_u(),
478                                         frame->get_v(),
479                                         input->get_y(), /* Leave NULL if non existent */
480                                         input->get_u(),
481                                         input->get_v(),
482                                         0,        /* Dimensions to capture from input frame */
483                                         0,
484                                         w,
485                                         h,
486                                         0,       /* Dimensions to project on output frame */
487                                         0,
488                                         w,
489                                         h,
490                                         input->get_color_model(),
491                                         frame->get_color_model(),
492                                         0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
493                                         input->get_bytes_per_line(),       /* For planar use the luma rowspan */
494                                         frame->get_bytes_per_line());     /* For planar use the luma rowspan */
495                                 frame->set_opengl_state(VFrame::RAM);
496                         }
497                         else
498                         if(input->get_compressed_size())
499                         {
500                                 switch(session->vconfig_in->driver)
501                                 {
502                                         case CAPTURE_FIREWIRE:
503                                         case CAPTURE_IEC61883:
504 // Decompress a DV frame from the driver
505                                                 if(!dv)
506                                                         dv = dv_new();
507                                                 dv_read_video(((dv_t*)dv),
508                                                         frame->get_rows(),
509                                                         input->get_data(),
510                                                         input->get_compressed_size(),
511                                                         frame->get_color_model());
512                                                 frame->set_opengl_state(VFrame::RAM);
513                                                 break;
514
515                                         case VIDEO4LINUX2JPEG:
516                                                 if(!mjpeg)
517                                                         mjpeg = mjpeg_new(frame->get_w(),
518                                                                 frame->get_h(),
519                                                                 2);  // fields
520                                                 mjpeg_decompress(mjpeg,
521                                                         input->get_data(),
522                                                         input->get_compressed_size(),
523                                                         input->get_field2_offset(),
524                                                         frame->get_rows(),
525                                                         frame->get_y(),
526                                                         frame->get_u(),
527                                                         frame->get_v(),
528                                                         frame->get_color_model(),
529                                                         get_project_smp() + 1);
530                                                 break;
531
532                                         case CAPTURE_JPEG_WEBCAM:
533                                                 if(!mjpeg)
534                                                         mjpeg = mjpeg_new(frame->get_w(),
535                                                                 frame->get_h(),
536                                                                 1);  // fields
537 // printf("LiveVideo::process_buffer %d %p %d\n",
538 // __LINE__,
539 // input->get_data(),
540 // input->get_compressed_size());
541                                                 mjpeg_decompress(mjpeg,
542                                                         input->get_data(),
543                                                         input->get_compressed_size(),
544                                                         0,
545                                                         frame->get_rows(),
546                                                         frame->get_y(),
547                                                         frame->get_u(),
548                                                         frame->get_v(),
549                                                         frame->get_color_model(),
550                                                         get_project_smp() + 1);
551                                                 break;
552                                 }
553                         }
554                         else
555                         {
556                                 printf("LiveVideo::process_buffer %d zero size image\n", __LINE__);
557                         }
558                 }
559         }
560
561         return 0;
562 }
563
564 void LiveVideo::render_stop()
565 {
566         if(vdevice)
567         {
568                 vdevice->interrupt_crash();
569                 vdevice->close_all();
570                 delete vdevice;
571                 vdevice = 0;
572         }
573         delete picture;
574         picture = 0;
575 }
576
577
578 const char* LiveVideo::plugin_title() { return N_("Live Video"); }
579 int LiveVideo::is_realtime() { return 1; }
580 int LiveVideo::is_multichannel() { return 0; }
581 int LiveVideo::is_synthesis() { return 1; }
582
583
584
585 NEW_WINDOW_MACRO(LiveVideo, LiveVideoWindow)
586
587 LOAD_CONFIGURATION_MACRO(LiveVideo, LiveVideoConfig)
588
589
590
591 void LiveVideo::save_data(KeyFrame *keyframe)
592 {
593         FileXML output;
594         output.set_shared_output(keyframe->xbuf);
595         output.tag.set_title("LIVEVIDEO");
596         output.tag.set_property("CHANNEL", config.channel);
597         output.append_tag();
598         output.tag.set_title("/LIVEVIDEO");
599         output.append_tag();
600         output.append_newline();
601         output.terminate_string();
602 }
603
604 void LiveVideo::read_data(KeyFrame *keyframe)
605 {
606         FileXML input;
607
608         input.set_shared_input(keyframe->xbuf);
609
610         int result = 0;
611
612         while(!result)
613         {
614                 result = input.read_tag();
615
616                 if(!result)
617                 {
618                         if(input.tag.title_is("LIVEVIDEO"))
619                         {
620                                 config.channel = input.tag.get_property("CHANNEL", config.channel);
621                         }
622                 }
623         }
624 }
625
626 void LiveVideo::update_gui()
627 {
628         if(thread)
629         {
630                 if(load_configuration())
631                 {
632                         thread->window->lock_window("LiveVideo::update_gui");
633                         ((LiveVideoWindow*)thread->window)->list->set_selected(
634                                 &((LiveVideoWindow*)thread->window)->channel_list,
635                                 config.channel,
636                                 1);
637                         ((LiveVideoWindow*)thread->window)->list->draw_items(1);
638                         thread->window->unlock_window();
639                 }
640         }
641 }
642
643
644
645
646