Condense the xml-cleanup into a short feature-branch
[cinelerra_cv/mob.git] / plugins / livevideo / livevideo.C
blob1e2476371e42c49983cb7e2801d2e6abbf1f119d
1 #include "asset.h"
2 #include "bcdisplayinfo.h"
3 #include "bcsignals.h"
4 #include "channel.h"
5 #include "channeldb.h"
6 #include "clip.h"
7 #include "bchash.h"
8 #include "edlsession.h"
9 #include "filexml.h"
10 #include "guicast.h"
11 #include "language.h"
12 #include "libdv.h"
13 #include "libmjpeg.h"
14 #include "mwindow.h"
15 #include "picon_png.h"
16 #include "picture.h"
17 #include "pluginvclient.h"
18 #include "recordconfig.h"
19 #include "transportque.inc"
20 #include "vframe.h"
21 #include "videodevice.h"
22 #include "videodevice.inc"
24 #include <string.h>
25 #include <stdint.h>
27 #define HISTORY_FRAMES 30
28 class LiveVideo;
29 class LiveVideoWindow;
32 class LiveVideoConfig
34 public:
35         LiveVideoConfig();
36         void copy_from(LiveVideoConfig &src);
37         int equivalent(LiveVideoConfig &src);
38         void interpolate(LiveVideoConfig &prev, 
39                 LiveVideoConfig &next, 
40                 int64_t prev_frame, 
41                 int64_t next_frame, 
42                 int64_t current_frame);
43         int channel;
47 // Without access to the video device, the ChannelPicker can't
48 // do any of the things it was designed to.  Instead, just provide
49 // a list of channels.
50 class LiveChannelList : public BC_ListBox
52 public:
53         LiveChannelList(LiveVideo *plugin, 
54                 LiveVideoWindow *gui, 
55                 int x, 
56                 int y,
57                 int w,
58                 int h);
59         int handle_event();
60         LiveVideo *plugin;
61         LiveVideoWindow *gui;
64 class LiveChannelSelect : public BC_Button
66 public:
67         LiveChannelSelect(LiveVideo *plugin, 
68                 LiveVideoWindow *gui, 
69                 int x, 
70                 int y);
71         int handle_event();
72         LiveVideo *plugin;
73         LiveVideoWindow *gui;
77 class LiveVideoWindow : public BC_Window
79 public:
80         LiveVideoWindow(LiveVideo *plugin, int x, int y);
81         ~LiveVideoWindow();
83         void create_objects();
84         int close_event();
85         int resize_event(int w, int h);
87         ArrayList<BC_ListBoxItem*> channel_list;
88         BC_Title *title;
89         LiveChannelList *list;
90         LiveChannelSelect *select;
91         LiveVideo *plugin;
95 PLUGIN_THREAD_HEADER(LiveVideo, LiveVideoThread, LiveVideoWindow)
99 class LiveVideo : public PluginVClient
101 public:
102         LiveVideo(PluginServer *server);
103         ~LiveVideo();
106         PLUGIN_CLASS_MEMBERS(LiveVideoConfig, LiveVideoThread);
108         int process_buffer(VFrame *frame,
109                 int64_t start_position,
110                 double frame_rate);
111         int is_realtime();
112         int is_multichannel();
113         int is_synthesis();
114         int load_defaults();
115         int save_defaults();
116         void save_data(KeyFrame *keyframe);
117         void read_data(KeyFrame *keyframe);
118         void update_gui();
119         void render_stop();
121         ChannelDB *channeldb;
122         VideoDevice *vdevice;
123 // Colormodel the device generates
124         int input_cmodel;
125 // Temporary for colormodel conversion
126         VFrame *temp;
127 // What configuration parameters the device supports
128         Channel master_channel;
129         PictureConfig *picture;
130         BC_Hash *picture_defaults;
131         int prev_channel;
132         int w, h;
133 // Decompressors for different video drivers
134         dv_t *dv;
135         mjpeg_t *mjpeg;
149 LiveVideoConfig::LiveVideoConfig()
151         channel = 0;
154 void LiveVideoConfig::copy_from(LiveVideoConfig &src)
156         this->channel = src.channel;
159 int LiveVideoConfig::equivalent(LiveVideoConfig &src)
161         return (this->channel == src.channel);
164 void LiveVideoConfig::interpolate(LiveVideoConfig &prev, 
165         LiveVideoConfig &next, 
166         int64_t prev_frame, 
167         int64_t next_frame, 
168         int64_t current_frame)
170         this->channel = prev.channel;
177 LiveVideoWindow::LiveVideoWindow(LiveVideo *plugin, int x, int y)
178  : BC_Window(plugin->gui_string, 
179         x, 
180         y, 
181         plugin->w, 
182         plugin->h, 
183         100, 
184         100, 
185         1, 
186         0,
187         1)
189         this->plugin = plugin;
192 LiveVideoWindow::~LiveVideoWindow()
194         channel_list.remove_all_objects();
197 void LiveVideoWindow::create_objects()
199         int x = 10, y = 10;
201         for(int i = 0; i < plugin->channeldb->size(); i++)
202         {
203                 BC_ListBoxItem *current;
204                 channel_list.append(current = 
205                         new BC_ListBoxItem(plugin->channeldb->get(i)->title));
206                 if(i == plugin->config.channel) current->set_selected(1);
207         }
209         add_subwindow(title = new BC_Title(x, y, _("Channels:")));
210         y += title->get_h() + 5;
211         add_subwindow(list = new LiveChannelList(plugin, 
212                 this, 
213                 x, 
214                 y,
215                 get_w() - x - 10,
216                 get_h() - y - BC_OKButton::calculate_h() - 10 - 10));
217         y += list->get_h() + 10;
218         add_subwindow(select = new LiveChannelSelect(plugin, 
219                 this, 
220                 x, 
221                 y));
222         show_window();
223         flush();
226 WINDOW_CLOSE_EVENT(LiveVideoWindow)
228 int LiveVideoWindow::resize_event(int w, int h)
230         int list_bottom = get_h() - list->get_y() - list->get_h();
231         int list_side = get_w() - list->get_x() - list->get_w();
232         int select_top = get_h() - select->get_y();
234         title->reposition_window(title->get_x(), title->get_y());
236         list->reposition_window(list->get_x(),
237                 list->get_y(),
238                 w - list->get_x() - list_side,
239                 h - list->get_y() - list_bottom);
240         select->reposition_window(select->get_x(),
241                 h - select_top);
242         plugin->w = w;
243         plugin->h = h;
244         return 1;
250 LiveChannelList::LiveChannelList(LiveVideo *plugin, 
251         LiveVideoWindow *gui, 
252         int x, 
253         int y,
254         int w,
255         int h)
256  : BC_ListBox(x, 
257         y, 
258         w, 
259         h,
260         LISTBOX_TEXT,                   // Display text list or icons
261         &gui->channel_list) // Each column has an ArrayList of BC_ListBoxItems.
263         this->plugin = plugin;
264         this->gui = gui;
267 int LiveChannelList::handle_event()
269         plugin->config.channel = get_selection_number(0, 0);
270         plugin->send_configure_change();
271         return 1;
275 LiveChannelSelect::LiveChannelSelect(LiveVideo *plugin, 
276         LiveVideoWindow *gui, 
277         int x, 
278         int y)
279  :  BC_Button(x, y, 
280         BC_WindowBase::get_resources()->ok_images)
282         this->plugin = plugin;
283         this->gui = gui;
286 int LiveChannelSelect::handle_event()
288         plugin->config.channel = gui->list->get_selection_number(0, 0);
289         plugin->send_configure_change();
290         return 1;
307 PLUGIN_THREAD_OBJECT(LiveVideo, LiveVideoThread, LiveVideoWindow)
318 REGISTER_PLUGIN(LiveVideo)
325 LiveVideo::LiveVideo(PluginServer *server)
326  : PluginVClient(server)
328         vdevice = 0;
329         temp = 0;
330         channeldb = new ChannelDB;
331         w = 320;
332         h = 640;
333         prev_channel = 0;
334         dv = 0;
335         mjpeg = 0;
336         picture = 0;
337         picture_defaults = 0;
338         PLUGIN_CONSTRUCTOR_MACRO
342 LiveVideo::~LiveVideo()
344         PLUGIN_DESTRUCTOR_MACRO
345         if(vdevice)
346         {
347                 vdevice->interrupt_crash();
348                 vdevice->close_all();
349                 delete vdevice;
350         }
352         delete channeldb;
353         delete temp;
354         if(dv) dv_delete(dv);
355         if(mjpeg) mjpeg_delete(mjpeg);
356         delete picture;
357         delete picture_defaults;
362 int LiveVideo::process_buffer(VFrame *frame,
363         int64_t start_position,
364         double frame_rate)
366         load_configuration();
367 //printf("LiveVideo::process_buffer 10 start_position=%lld buffer_size=%d size=%d\n", 
368 //start_position, get_buffer_size(), size);
370         EDLSession *session = PluginClient::get_edlsession();
371         if(!vdevice)
372         {
373                 if(session)
374                 {
375                         vdevice = new VideoDevice;
376                         vdevice->open_input(session->vconfig_in, 
377                                 0, 
378                                 0,
379                                 1.0,
380                                 frame_rate);
382 // The color model depends on the asset configured by the user for recording.
383 // Unfortunately, get_best_colormodel returns the best colormodel for displaying
384 // on the record monitor, not the colormodel supported by the device.
385 // Some devices can read directly to the best colormodel and some can't.
386                         switch(session->vconfig_in->driver)
387                         {
388                                 case CAPTURE_FIREWIRE:
389                                 case CAPTURE_IEC61883:
390                                 case CAPTURE_BUZ:
391                                 case VIDEO4LINUX2JPEG:
392                                         input_cmodel = BC_COMPRESSED;
393                                         break;
394                                 default:
395                                         input_cmodel = vdevice->get_best_colormodel(session->recording_format);
396                                         break;
397                         }
400 // Load the picture config from the main defaults file.
401                         if(!picture_defaults)
402                         {
403                                 char path[BCTEXTLEN];
404                                 MWindow::create_defaults_path(path);
405                                 picture_defaults = new BC_Hash(path);
406                                 picture_defaults->load();
407                         }
409                         if(!picture)
410                         {
411                                 picture = new PictureConfig(picture_defaults);
412                         }
414 // Picture must have usage from driver before it can load defaults.
415                         master_channel.copy_usage(vdevice->channel);
416                         picture->copy_usage(vdevice->picture);
417                         picture->load_defaults();
419 // Need to load picture defaults but this requires MWindow.
420                         vdevice->set_picture(picture);
421                         vdevice->set_channel(channeldb->get(config.channel));
422                 }
423                 prev_channel = config.channel;
424         }
426         if(session && vdevice)
427         {
428 // Update channel
429                 if(prev_channel != config.channel)
430                 {
431                         prev_channel = config.channel;
432                         vdevice->set_picture(picture);
433                         vdevice->set_channel(channeldb->get(config.channel));
434                 }
436         
437                 VFrame *input = frame;
438                 if(input_cmodel != frame->get_color_model() ||
439                         session->vconfig_in->w != frame->get_w() ||
440                         session->vconfig_in->h != frame->get_h())
441                 {
442                         if(!temp)
443                         {
444                                 temp = new VFrame(0, 
445                                         session->vconfig_in->w,
446                                         session->vconfig_in->h,
447                                         input_cmodel);
448                         }
449                         input = temp;
450                 }
451                 vdevice->read_buffer(input);
452                 if(input != frame)
453                 {
454                         if(input->get_color_model() != BC_COMPRESSED)
455                         {
456 SET_TRACE
457                                 int w = MIN(session->vconfig_in->w, frame->get_w());
458                                 int h = MIN(session->vconfig_in->h, frame->get_h());
459                                 cmodel_transfer(frame->get_rows(), /* Leave NULL if non existent */
460                                         input->get_rows(),
461                                         frame->get_y(), /* Leave NULL if non existent */
462                                         frame->get_u(),
463                                         frame->get_v(),
464                                         input->get_y(), /* Leave NULL if non existent */
465                                         input->get_u(),
466                                         input->get_v(),
467                                         0,        /* Dimensions to capture from input frame */
468                                         0, 
469                                         w, 
470                                         h,
471                                         0,       /* Dimensions to project on output frame */
472                                         0, 
473                                         w, 
474                                         h,
475                                         input->get_color_model(), 
476                                         frame->get_color_model(),
477                                         0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
478                                         input->get_bytes_per_line(),       /* For planar use the luma rowspan */
479                                         frame->get_bytes_per_line());     /* For planar use the luma rowspan */
480                                 frame->set_opengl_state(VFrame::RAM);
481 SET_TRACE
482                         }
483                         else
484                         {
485                                 switch(session->vconfig_in->driver)
486                                 {
487                                         case CAPTURE_FIREWIRE:
488                                         case CAPTURE_IEC61883:
489 // Decompress a DV frame from the driver
490                                                 if(!dv)
491                                                         dv = dv_new();
492                                                 dv_read_video(((dv_t*)dv), 
493                                                         frame->get_rows(), 
494                                                         input->get_data(), 
495                                                         input->get_compressed_size(),
496                                                         frame->get_color_model());
497                                                 frame->set_opengl_state(VFrame::RAM);
498 SET_TRACE
499                                                 break;
501                                         case CAPTURE_BUZ:
502                                         case VIDEO4LINUX2JPEG:
503                                                 if(!mjpeg)
504                                                         mjpeg = mjpeg_new(w, 
505                                                                 h, 
506                                                                 2);  // fields
507                                                 mjpeg_decompress(mjpeg, 
508                                                         input->get_data(), 
509                                                         input->get_compressed_size(), 
510                                                         input->get_field2_offset(), 
511                                                         frame->get_rows(), 
512                                                         frame->get_y(), 
513                                                         frame->get_u(), 
514                                                         frame->get_v(),
515                                                         frame->get_color_model(),
516                                                         get_project_smp() + 1);
517                                                 break;
518                                 }
519                         }
520                 }
521         }
523         return 0;
526 void LiveVideo::render_stop()
528         if(vdevice)
529         {
530                 vdevice->interrupt_crash();
531                 vdevice->close_all();
532                 delete vdevice;
533                 vdevice = 0;
534         }
535         delete picture_defaults;
536         picture_defaults = 0;
537         delete picture;
538         picture = 0;
542 char* LiveVideo::plugin_title() { return N_("Live Video"); }
543 int LiveVideo::is_realtime() { return 1; }
544 int LiveVideo::is_multichannel() { return 0; }
545 int LiveVideo::is_synthesis() { return 1; }
548 NEW_PICON_MACRO(LiveVideo) 
550 SHOW_GUI_MACRO(LiveVideo, LiveVideoThread)
552 RAISE_WINDOW_MACRO(LiveVideo)
554 SET_STRING_MACRO(LiveVideo);
556 LOAD_CONFIGURATION_MACRO(LiveVideo, LiveVideoConfig)
558 int LiveVideo::load_defaults()
560         char directory[BCTEXTLEN], string[BCTEXTLEN];
561 // set the default directory
562         sprintf(directory, "%slivevideo.rc", BCASTDIR);
563 // load the defaults
564         defaults = new BC_Hash(directory);
565         defaults->load();
567 // Load channel table
568         EDLSession *session = PluginClient::get_edlsession();
569         if(session)
570                 VideoDevice::load_channeldb(channeldb, session->vconfig_in);
571         config.channel = defaults->get("CHANNEL", 0);
572         w = defaults->get("W", w);
573         h = defaults->get("H", h);
574         return 0;
577 int LiveVideo::save_defaults()
579         defaults->update("CHANNEL", config.channel);
580         defaults->update("W", w);
581         defaults->update("H", h);
582         defaults->save();
583         return 0;
586 void LiveVideo::save_data(KeyFrame *keyframe)
588         FileXML output;
589         output.set_shared_string(keyframe->data, MESSAGESIZE);
590         output.tag.set_title("LIVEVIDEO");
591         output.tag.set_property("CHANNEL", config.channel);
592         output.append_tag();
593         output.tag.set_title("/LIVEVIDEO");
594         output.append_tag();
595         output.terminate_string();
598 void LiveVideo::read_data(KeyFrame *keyframe)
600         FileXML input;
602         input.set_shared_string(keyframe->data, strlen(keyframe->data));
604         int result = 0;
606         while(!result)
607         {
608                 result = input.read_tag();
610                 if(!result)
611                 {
612                         if(input.tag.title_is("LIVEVIDEO"))
613                         {
614                                 config.channel = input.tag.get_property("CHANNEL", config.channel);
615                         }
616                 }
617         }
620 void LiveVideo::update_gui()
622         if(thread)
623         {
624                 if(load_configuration())
625                 {
626                         thread->window->lock_window("LiveVideo::update_gui");
627                         thread->window->list->set_selected(&thread->window->channel_list, 
628                                 config.channel, 
629                                 1);
630                         thread->window->list->draw_items(1);
631                         thread->window->unlock_window();
632                 }
633         }