4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
26 #include "channeldb.h"
30 #include "edlsession.h"
38 #include "pluginvclient.h"
39 #include "pluginserver.h"
40 #include "recordconfig.h"
41 #include "transportque.inc"
43 #include "videodevice.h"
44 #include "videodevice.inc"
49 #define HISTORY_FRAMES 30
51 class LiveVideoWindow;
58 void copy_from(LiveVideoConfig &src);
59 int equivalent(LiveVideoConfig &src);
60 void interpolate(LiveVideoConfig &prev,
61 LiveVideoConfig &next,
64 int64_t current_frame);
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
75 LiveChannelList(LiveVideo *plugin,
86 class LiveChannelSelect : public BC_Button
89 LiveChannelSelect(LiveVideo *plugin,
99 class LiveVideoWindow : public PluginClientWindow
102 LiveVideoWindow(LiveVideo *plugin);
105 void create_objects();
107 int resize_event(int w, int h);
109 ArrayList<BC_ListBoxItem*> channel_list;
111 LiveChannelList *list;
112 LiveChannelSelect *select;
121 class LiveVideo : public PluginVClient
124 LiveVideo(PluginServer *server);
128 PLUGIN_CLASS_MEMBERS(LiveVideoConfig);
130 int process_buffer(VFrame *frame,
131 int64_t start_position,
134 int is_multichannel();
136 void save_data(KeyFrame *keyframe);
137 void read_data(KeyFrame *keyframe);
141 ChannelDB *channeldb;
142 VideoDevice *vdevice;
143 // Colormodel the device generates
145 // Temporary for colormodel conversion
147 // What configuration parameters the device supports
148 Channel master_channel;
149 PictureConfig *picture;
152 // Decompressors for different video drivers
168 LiveVideoConfig::LiveVideoConfig()
173 void LiveVideoConfig::copy_from(LiveVideoConfig &src)
175 this->channel = src.channel;
178 int LiveVideoConfig::equivalent(LiveVideoConfig &src)
180 return (this->channel == src.channel);
183 void LiveVideoConfig::interpolate(LiveVideoConfig &prev,
184 LiveVideoConfig &next,
187 int64_t current_frame)
189 this->channel = prev.channel;
196 LiveVideoWindow::LiveVideoWindow(LiveVideo *plugin)
197 : PluginClientWindow(plugin,
204 this->plugin = plugin;
207 LiveVideoWindow::~LiveVideoWindow()
209 channel_list.remove_all_objects();
212 void LiveVideoWindow::create_objects()
215 int ys5 = yS(5), ys10 = yS(10);
216 int x = xs10, y = ys10;
218 EDLSession *session = plugin->get_edl()->session;
220 VideoDevice::load_channeldb(plugin->channeldb, session->vconfig_in);
221 for(int i = 0; i < plugin->channeldb->size(); i++)
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);
229 add_subwindow(title = new BC_Title(x, y, _("Channels:")));
230 y += title->get_h() + ys5;
231 add_subwindow(list = new LiveChannelList(plugin,
236 get_h() - y - BC_OKButton::calculate_h() - ys10 - ys10));
237 y += list->get_h() + ys10;
238 add_subwindow(select = new LiveChannelSelect(plugin,
247 int LiveVideoWindow::resize_event(int w, int h)
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();
253 title->reposition_window(title->get_x(), title->get_y());
255 list->reposition_window(list->get_x(),
257 w - list->get_x() - list_side,
258 h - list->get_y() - list_bottom);
259 select->reposition_window(select->get_x(),
269 LiveChannelList::LiveChannelList(LiveVideo *plugin,
270 LiveVideoWindow *gui,
279 LISTBOX_TEXT, // Display text list or icons
280 &gui->channel_list) // Each column has an ArrayList of BC_ListBoxItems.
282 this->plugin = plugin;
286 int LiveChannelList::handle_event()
288 plugin->config.channel = get_selection_number(0, 0);
289 plugin->send_configure_change();
294 LiveChannelSelect::LiveChannelSelect(LiveVideo *plugin,
295 LiveVideoWindow *gui,
299 BC_WindowBase::get_resources()->ok_images)
301 this->plugin = plugin;
305 int LiveChannelSelect::handle_event()
307 plugin->config.channel = gui->list->get_selection_number(0, 0);
308 plugin->send_configure_change();
337 REGISTER_PLUGIN(LiveVideo)
344 LiveVideo::LiveVideo(PluginServer *server)
345 : PluginVClient(server)
349 channeldb = new ChannelDB;
356 this->server = server;
361 LiveVideo::~LiveVideo()
366 vdevice->interrupt_crash();
367 vdevice->close_all();
373 if(dv) dv_delete(dv);
374 if(mjpeg) mjpeg_delete(mjpeg);
380 int LiveVideo::process_buffer(VFrame *frame,
381 int64_t start_position,
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);
388 EDLSession *session = get_edl()->session;
393 vdevice = new VideoDevice(server ? server->mwindow : 0);
394 vdevice->open_input(session->vconfig_in,
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)
406 case CAPTURE_FIREWIRE:
407 case CAPTURE_IEC61883:
408 case VIDEO4LINUX2JPEG:
409 case CAPTURE_JPEG_WEBCAM:
410 input_cmodel = BC_COMPRESSED;
413 input_cmodel = vdevice->get_best_colormodel(session->recording_format);
418 // Load the picture config from the main defaults file.
420 // Load channel table
421 VideoDevice::load_channeldb(channeldb, session->vconfig_in);
425 picture = new PictureConfig;
426 picture->load_defaults();
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();
434 // Need to load picture defaults but this requires MWindow.
435 vdevice->set_picture(picture);
436 vdevice->set_channel(channeldb->get(config.channel));
438 prev_channel = config.channel;
441 if(session && vdevice)
444 if(prev_channel != config.channel)
446 prev_channel = config.channel;
447 vdevice->set_picture(picture);
448 vdevice->set_channel(channeldb->get(config.channel));
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())
460 temp = new VFrame(session->vconfig_in->w, session->vconfig_in->h,
466 vdevice->read_buffer(input);
470 if(input->get_color_model() != BC_COMPRESSED)
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 */
476 frame->get_y(), /* Leave NULL if non existent */
479 input->get_y(), /* Leave NULL if non existent */
482 0, /* Dimensions to capture from input frame */
486 0, /* Dimensions to project on output frame */
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);
498 if(input->get_compressed_size())
500 switch(session->vconfig_in->driver)
502 case CAPTURE_FIREWIRE:
503 case CAPTURE_IEC61883:
504 // Decompress a DV frame from the driver
507 dv_read_video(((dv_t*)dv),
510 input->get_compressed_size(),
511 frame->get_color_model());
512 frame->set_opengl_state(VFrame::RAM);
515 case VIDEO4LINUX2JPEG:
517 mjpeg = mjpeg_new(frame->get_w(),
520 mjpeg_decompress(mjpeg,
522 input->get_compressed_size(),
523 input->get_field2_offset(),
528 frame->get_color_model(),
529 get_project_smp() + 1);
532 case CAPTURE_JPEG_WEBCAM:
534 mjpeg = mjpeg_new(frame->get_w(),
537 // printf("LiveVideo::process_buffer %d %p %d\n",
539 // input->get_data(),
540 // input->get_compressed_size());
541 mjpeg_decompress(mjpeg,
543 input->get_compressed_size(),
549 frame->get_color_model(),
550 get_project_smp() + 1);
556 printf("LiveVideo::process_buffer %d zero size image\n", __LINE__);
564 void LiveVideo::render_stop()
568 vdevice->interrupt_crash();
569 vdevice->close_all();
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; }
585 NEW_WINDOW_MACRO(LiveVideo, LiveVideoWindow)
587 LOAD_CONFIGURATION_MACRO(LiveVideo, LiveVideoConfig)
591 void LiveVideo::save_data(KeyFrame *keyframe)
594 output.set_shared_output(keyframe->xbuf);
595 output.tag.set_title("LIVEVIDEO");
596 output.tag.set_property("CHANNEL", config.channel);
598 output.tag.set_title("/LIVEVIDEO");
600 output.append_newline();
601 output.terminate_string();
604 void LiveVideo::read_data(KeyFrame *keyframe)
608 input.set_shared_input(keyframe->xbuf);
614 result = input.read_tag();
618 if(input.tag.title_is("LIVEVIDEO"))
620 config.channel = input.tag.get_property("CHANNEL", config.channel);
626 void LiveVideo::update_gui()
630 if(load_configuration())
632 thread->window->lock_window("LiveVideo::update_gui");
633 ((LiveVideoWindow*)thread->window)->list->set_selected(
634 &((LiveVideoWindow*)thread->window)->channel_list,
637 ((LiveVideoWindow*)thread->window)->list->draw_items(1);
638 thread->window->unlock_window();