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"
29 #include "edlsession.h"
37 #include "pluginvclient.h"
38 #include "pluginserver.h"
39 #include "recordconfig.h"
40 #include "transportque.inc"
42 #include "videodevice.h"
43 #include "videodevice.inc"
48 #define HISTORY_FRAMES 30
50 class LiveVideoWindow;
57 void copy_from(LiveVideoConfig &src);
58 int equivalent(LiveVideoConfig &src);
59 void interpolate(LiveVideoConfig &prev,
60 LiveVideoConfig &next,
63 int64_t current_frame);
68 // Without access to the video device, the ChannelPicker can't
69 // do any of the things it was designed to. Instead, just provide
70 // a list of channels.
71 class LiveChannelList : public BC_ListBox
74 LiveChannelList(LiveVideo *plugin,
85 class LiveChannelSelect : public BC_Button
88 LiveChannelSelect(LiveVideo *plugin,
98 class LiveVideoWindow : public PluginClientWindow
101 LiveVideoWindow(LiveVideo *plugin);
104 void create_objects();
106 int resize_event(int w, int h);
108 ArrayList<BC_ListBoxItem*> channel_list;
110 LiveChannelList *list;
111 LiveChannelSelect *select;
120 class LiveVideo : public PluginVClient
123 LiveVideo(PluginServer *server);
127 PLUGIN_CLASS_MEMBERS(LiveVideoConfig);
129 int process_buffer(VFrame *frame,
130 int64_t start_position,
133 int is_multichannel();
135 void save_data(KeyFrame *keyframe);
136 void read_data(KeyFrame *keyframe);
140 ChannelDB *channeldb;
141 VideoDevice *vdevice;
142 // Colormodel the device generates
144 // Temporary for colormodel conversion
146 // What configuration parameters the device supports
147 Channel master_channel;
148 PictureConfig *picture;
151 // Decompressors for different video drivers
167 LiveVideoConfig::LiveVideoConfig()
172 void LiveVideoConfig::copy_from(LiveVideoConfig &src)
174 this->channel = src.channel;
177 int LiveVideoConfig::equivalent(LiveVideoConfig &src)
179 return (this->channel == src.channel);
182 void LiveVideoConfig::interpolate(LiveVideoConfig &prev,
183 LiveVideoConfig &next,
186 int64_t current_frame)
188 this->channel = prev.channel;
195 LiveVideoWindow::LiveVideoWindow(LiveVideo *plugin)
196 : PluginClientWindow(plugin,
203 this->plugin = plugin;
206 LiveVideoWindow::~LiveVideoWindow()
208 channel_list.remove_all_objects();
211 void LiveVideoWindow::create_objects()
215 EDLSession *session = plugin->PluginClient::get_edlsession();
217 VideoDevice::load_channeldb(plugin->channeldb, session->vconfig_in);
218 for(int i = 0; i < plugin->channeldb->size(); i++)
220 BC_ListBoxItem *current;
221 channel_list.append(current =
222 new BC_ListBoxItem(plugin->channeldb->get(i)->title));
223 if(i == plugin->config.channel) current->set_selected(1);
226 add_subwindow(title = new BC_Title(x, y, _("Channels:")));
227 y += title->get_h() + 5;
228 add_subwindow(list = new LiveChannelList(plugin,
233 get_h() - y - BC_OKButton::calculate_h() - 10 - 10));
234 y += list->get_h() + 10;
235 add_subwindow(select = new LiveChannelSelect(plugin,
244 int LiveVideoWindow::resize_event(int w, int h)
246 int list_bottom = get_h() - list->get_y() - list->get_h();
247 int list_side = get_w() - list->get_x() - list->get_w();
248 int select_top = get_h() - select->get_y();
250 title->reposition_window(title->get_x(), title->get_y());
252 list->reposition_window(list->get_x(),
254 w - list->get_x() - list_side,
255 h - list->get_y() - list_bottom);
256 select->reposition_window(select->get_x(),
266 LiveChannelList::LiveChannelList(LiveVideo *plugin,
267 LiveVideoWindow *gui,
276 LISTBOX_TEXT, // Display text list or icons
277 &gui->channel_list) // Each column has an ArrayList of BC_ListBoxItems.
279 this->plugin = plugin;
283 int LiveChannelList::handle_event()
285 plugin->config.channel = get_selection_number(0, 0);
286 plugin->send_configure_change();
291 LiveChannelSelect::LiveChannelSelect(LiveVideo *plugin,
292 LiveVideoWindow *gui,
296 BC_WindowBase::get_resources()->ok_images)
298 this->plugin = plugin;
302 int LiveChannelSelect::handle_event()
304 plugin->config.channel = gui->list->get_selection_number(0, 0);
305 plugin->send_configure_change();
334 REGISTER_PLUGIN(LiveVideo)
341 LiveVideo::LiveVideo(PluginServer *server)
342 : PluginVClient(server)
346 channeldb = new ChannelDB;
353 this->server = server;
358 LiveVideo::~LiveVideo()
363 vdevice->interrupt_crash();
364 vdevice->close_all();
370 if(dv) dv_delete(dv);
371 if(mjpeg) mjpeg_delete(mjpeg);
377 int LiveVideo::process_buffer(VFrame *frame,
378 int64_t start_position,
381 load_configuration();
382 //printf("LiveVideo::process_buffer 10 start_position=%lld buffer_size=%d size=%d\n",
383 //start_position, get_buffer_size(), size);
385 EDLSession *session = PluginClient::get_edlsession();
390 vdevice = new VideoDevice(server ? server->mwindow : 0);
391 vdevice->open_input(session->vconfig_in,
397 // The color model depends on the asset configured by the user for recording.
398 // Unfortunately, get_best_colormodel returns the best colormodel for displaying
399 // on the record monitor, not the colormodel supported by the device.
400 // Some devices can read directly to the best colormodel and some can't.
401 switch(session->vconfig_in->driver)
403 case CAPTURE_FIREWIRE:
404 case CAPTURE_IEC61883:
405 case VIDEO4LINUX2JPEG:
406 case CAPTURE_JPEG_WEBCAM:
407 input_cmodel = BC_COMPRESSED;
410 input_cmodel = vdevice->get_best_colormodel(session->recording_format);
415 // Load the picture config from the main defaults file.
417 // Load channel table
418 VideoDevice::load_channeldb(channeldb, session->vconfig_in);
422 picture = new PictureConfig;
423 picture->load_defaults();
426 // Picture must have usage from driver before it can load defaults.
427 master_channel.copy_usage(vdevice->channel);
428 picture->copy_usage(vdevice->picture);
429 picture->load_defaults();
431 // Need to load picture defaults but this requires MWindow.
432 vdevice->set_picture(picture);
433 vdevice->set_channel(channeldb->get(config.channel));
435 prev_channel = config.channel;
438 if(session && vdevice)
441 if(prev_channel != config.channel)
443 prev_channel = config.channel;
444 vdevice->set_picture(picture);
445 vdevice->set_channel(channeldb->get(config.channel));
449 (void)vdevice->config_updated();
450 VFrame *input = frame;
451 if(input_cmodel != frame->get_color_model() ||
452 session->vconfig_in->w != frame->get_w() ||
453 session->vconfig_in->h != frame->get_h())
459 session->vconfig_in->w,
460 session->vconfig_in->h,
467 vdevice->read_buffer(input);
471 if(input->get_color_model() != BC_COMPRESSED)
473 int w = MIN(session->vconfig_in->w, frame->get_w());
474 int h = MIN(session->vconfig_in->h, frame->get_h());
475 BC_CModels::transfer(frame->get_rows(), /* Leave NULL if non existent */
477 frame->get_y(), /* Leave NULL if non existent */
480 input->get_y(), /* Leave NULL if non existent */
483 0, /* Dimensions to capture from input frame */
487 0, /* Dimensions to project on output frame */
491 input->get_color_model(),
492 frame->get_color_model(),
493 0, /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
494 input->get_bytes_per_line(), /* For planar use the luma rowspan */
495 frame->get_bytes_per_line()); /* For planar use the luma rowspan */
496 frame->set_opengl_state(VFrame::RAM);
499 if(input->get_compressed_size())
501 switch(session->vconfig_in->driver)
503 case CAPTURE_FIREWIRE:
504 case CAPTURE_IEC61883:
505 // Decompress a DV frame from the driver
508 dv_read_video(((dv_t*)dv),
511 input->get_compressed_size(),
512 frame->get_color_model());
513 frame->set_opengl_state(VFrame::RAM);
516 case VIDEO4LINUX2JPEG:
518 mjpeg = mjpeg_new(frame->get_w(),
521 mjpeg_decompress(mjpeg,
523 input->get_compressed_size(),
524 input->get_field2_offset(),
529 frame->get_color_model(),
530 get_project_smp() + 1);
533 case CAPTURE_JPEG_WEBCAM:
535 mjpeg = mjpeg_new(frame->get_w(),
538 // printf("LiveVideo::process_buffer %d %p %d\n",
540 // input->get_data(),
541 // input->get_compressed_size());
542 mjpeg_decompress(mjpeg,
544 input->get_compressed_size(),
550 frame->get_color_model(),
551 get_project_smp() + 1);
557 printf("LiveVideo::process_buffer %d zero size image\n", __LINE__);
565 void LiveVideo::render_stop()
569 vdevice->interrupt_crash();
570 vdevice->close_all();
579 const char* LiveVideo::plugin_title() { return _("Live Video"); }
580 int LiveVideo::is_realtime() { return 1; }
581 int LiveVideo::is_multichannel() { return 0; }
582 int LiveVideo::is_synthesis() { return 1; }
586 NEW_WINDOW_MACRO(LiveVideo, LiveVideoWindow)
588 LOAD_CONFIGURATION_MACRO(LiveVideo, LiveVideoConfig)
592 void LiveVideo::save_data(KeyFrame *keyframe)
595 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
596 output.tag.set_title("LIVEVIDEO");
597 output.tag.set_property("CHANNEL", config.channel);
599 output.tag.set_title("/LIVEVIDEO");
601 output.append_newline();
602 output.terminate_string();
605 void LiveVideo::read_data(KeyFrame *keyframe)
609 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
615 result = input.read_tag();
619 if(input.tag.title_is("LIVEVIDEO"))
621 config.channel = input.tag.get_property("CHANNEL", config.channel);
627 void LiveVideo::update_gui()
631 if(load_configuration())
633 thread->window->lock_window("LiveVideo::update_gui");
634 ((LiveVideoWindow*)thread->window)->list->set_selected(
635 &((LiveVideoWindow*)thread->window)->channel_list,
638 ((LiveVideoWindow*)thread->window)->list->draw_items(1);
639 thread->window->unlock_window();