-
-/*
- * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "asset.h"
-#include "bcdisplayinfo.h"
-#include "bcsignals.h"
-#include "channel.h"
-#include "channeldb.h"
-#include "clip.h"
-#include "bchash.h"
-#include "edlsession.h"
-#include "filexml.h"
-#include "guicast.h"
-#include "language.h"
-#include "libdv.h"
-#include "libmjpeg.h"
-#include "mwindow.h"
-#include "picture.h"
-#include "pluginvclient.h"
-#include "pluginserver.h"
-#include "recordconfig.h"
-#include "transportque.inc"
-#include "vframe.h"
-#include "videodevice.h"
-#include "videodevice.inc"
-
-#include <string.h>
-#include <stdint.h>
-
-#define HISTORY_FRAMES 30
-class LiveVideo;
-class LiveVideoWindow;
-
-
-class LiveVideoConfig
-{
-public:
- LiveVideoConfig();
- void copy_from(LiveVideoConfig &src);
- int equivalent(LiveVideoConfig &src);
- void interpolate(LiveVideoConfig &prev,
- LiveVideoConfig &next,
- int64_t prev_frame,
- int64_t next_frame,
- int64_t current_frame);
- int channel;
-};
-
-
-// Without access to the video device, the ChannelPicker can't
-// do any of the things it was designed to. Instead, just provide
-// a list of channels.
-class LiveChannelList : public BC_ListBox
-{
-public:
- LiveChannelList(LiveVideo *plugin,
- LiveVideoWindow *gui,
- int x,
- int y,
- int w,
- int h);
- int handle_event();
- LiveVideo *plugin;
- LiveVideoWindow *gui;
-};
-
-class LiveChannelSelect : public BC_Button
-{
-public:
- LiveChannelSelect(LiveVideo *plugin,
- LiveVideoWindow *gui,
- int x,
- int y);
- int handle_event();
- LiveVideo *plugin;
- LiveVideoWindow *gui;
-};
-
-
-class LiveVideoWindow : public PluginClientWindow
-{
-public:
- LiveVideoWindow(LiveVideo *plugin);
- ~LiveVideoWindow();
-
- void create_objects();
-
- int resize_event(int w, int h);
-
- ArrayList<BC_ListBoxItem*> channel_list;
- BC_Title *title;
- LiveChannelList *list;
- LiveChannelSelect *select;
- LiveVideo *plugin;
-};
-
-
-
-
-
-
-class LiveVideo : public PluginVClient
-{
-public:
- LiveVideo(PluginServer *server);
- ~LiveVideo();
-
-
- PLUGIN_CLASS_MEMBERS(LiveVideoConfig);
-
- int process_buffer(VFrame *frame,
- int64_t start_position,
- double frame_rate);
- int is_realtime();
- int is_multichannel();
- int is_synthesis();
- void save_data(KeyFrame *keyframe);
- void read_data(KeyFrame *keyframe);
- void update_gui();
- void render_stop();
-
- ChannelDB *channeldb;
- VideoDevice *vdevice;
-// Colormodel the device generates
- int input_cmodel;
-// Temporary for colormodel conversion
- VFrame *temp;
-// What configuration parameters the device supports
- Channel master_channel;
- PictureConfig *picture;
- int prev_channel;
- int w, h;
-// Decompressors for different video drivers
- dv_t *dv;
- mjpeg_t *mjpeg;
-};
-
-
-
-
-
-
-
-
-
-
-
-
-LiveVideoConfig::LiveVideoConfig()
-{
- channel = 0;
-}
-
-void LiveVideoConfig::copy_from(LiveVideoConfig &src)
-{
- this->channel = src.channel;
-}
-
-int LiveVideoConfig::equivalent(LiveVideoConfig &src)
-{
- return (this->channel == src.channel);
-}
-
-void LiveVideoConfig::interpolate(LiveVideoConfig &prev,
- LiveVideoConfig &next,
- int64_t prev_frame,
- int64_t next_frame,
- int64_t current_frame)
-{
- this->channel = prev.channel;
-}
-
-
-
-
-
-LiveVideoWindow::LiveVideoWindow(LiveVideo *plugin)
- : PluginClientWindow(plugin,
- plugin->w,
- plugin->h,
- 100,
- 100,
- 1)
-{
- this->plugin = plugin;
-}
-
-LiveVideoWindow::~LiveVideoWindow()
-{
- channel_list.remove_all_objects();
-}
-
-void LiveVideoWindow::create_objects()
-{
- int x = 10, y = 10;
-
- EDLSession *session = plugin->PluginClient::get_edlsession();
- if(session)
- VideoDevice::load_channeldb(plugin->channeldb, session->vconfig_in);
- for(int i = 0; i < plugin->channeldb->size(); i++)
- {
- BC_ListBoxItem *current;
- channel_list.append(current =
- new BC_ListBoxItem(plugin->channeldb->get(i)->title));
- if(i == plugin->config.channel) current->set_selected(1);
- }
-
- add_subwindow(title = new BC_Title(x, y, _("Channels:")));
- y += title->get_h() + 5;
- add_subwindow(list = new LiveChannelList(plugin,
- this,
- x,
- y,
- get_w() - x - 10,
- get_h() - y - BC_OKButton::calculate_h() - 10 - 10));
- y += list->get_h() + 10;
- add_subwindow(select = new LiveChannelSelect(plugin,
- this,
- x,
- y));
- show_window();
-}
-
-
-
-int LiveVideoWindow::resize_event(int w, int h)
-{
- int list_bottom = get_h() - list->get_y() - list->get_h();
- int list_side = get_w() - list->get_x() - list->get_w();
- int select_top = get_h() - select->get_y();
-
- title->reposition_window(title->get_x(), title->get_y());
-
- list->reposition_window(list->get_x(),
- list->get_y(),
- w - list->get_x() - list_side,
- h - list->get_y() - list_bottom);
- select->reposition_window(select->get_x(),
- h - select_top);
- plugin->w = w;
- plugin->h = h;
- return 1;
-}
-
-
-
-
-LiveChannelList::LiveChannelList(LiveVideo *plugin,
- LiveVideoWindow *gui,
- int x,
- int y,
- int w,
- int h)
- : BC_ListBox(x,
- y,
- w,
- h,
- LISTBOX_TEXT, // Display text list or icons
- &gui->channel_list) // Each column has an ArrayList of BC_ListBoxItems.
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int LiveChannelList::handle_event()
-{
- plugin->config.channel = get_selection_number(0, 0);
- plugin->send_configure_change();
- return 1;
-}
-
-
-LiveChannelSelect::LiveChannelSelect(LiveVideo *plugin,
- LiveVideoWindow *gui,
- int x,
- int y)
- : BC_Button(x, y,
- BC_WindowBase::get_resources()->ok_images)
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int LiveChannelSelect::handle_event()
-{
- plugin->config.channel = gui->list->get_selection_number(0, 0);
- plugin->send_configure_change();
- return 1;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-REGISTER_PLUGIN(LiveVideo)
-
-
-
-
-
-
-LiveVideo::LiveVideo(PluginServer *server)
- : PluginVClient(server)
-{
- vdevice = 0;
- temp = 0;
- channeldb = new ChannelDB;
- w = 320;
- h = 640;
- prev_channel = 0;
- dv = 0;
- mjpeg = 0;
- picture = 0;
- this->server = server;
-
-}
-
-
-LiveVideo::~LiveVideo()
-{
-
- if(vdevice)
- {
- vdevice->interrupt_crash();
- vdevice->close_all();
- delete vdevice;
- }
-
- delete channeldb;
- delete temp;
- if(dv) dv_delete(dv);
- if(mjpeg) mjpeg_delete(mjpeg);
- delete picture;
-}
-
-
-
-int LiveVideo::process_buffer(VFrame *frame,
- int64_t start_position,
- double frame_rate)
-{
- load_configuration();
-//printf("LiveVideo::process_buffer 10 start_position=%lld buffer_size=%d size=%d\n",
-//start_position, get_buffer_size(), size);
-
- EDLSession *session = PluginClient::get_edlsession();
- if(!vdevice)
- {
- if(session)
- {
- vdevice = new VideoDevice(server ? server->mwindow : 0);
- vdevice->open_input(session->vconfig_in,
- 0,
- 0,
- 1.0,
- frame_rate);
-
-// The color model depends on the asset configured by the user for recording.
-// Unfortunately, get_best_colormodel returns the best colormodel for displaying
-// on the record monitor, not the colormodel supported by the device.
-// Some devices can read directly to the best colormodel and some can't.
- switch(session->vconfig_in->driver)
- {
- case CAPTURE_FIREWIRE:
- case CAPTURE_IEC61883:
- case CAPTURE_BUZ:
- case VIDEO4LINUX2JPEG:
- case CAPTURE_JPEG_WEBCAM:
- input_cmodel = BC_COMPRESSED;
- break;
- default:
- input_cmodel = vdevice->get_best_colormodel(session->recording_format);
- break;
- }
-
-
-// Load the picture config from the main defaults file.
-
-// Load channel table
- VideoDevice::load_channeldb(channeldb, session->vconfig_in);
-
- if(!picture)
- {
- picture = new PictureConfig;
- picture->load_defaults();
- }
-
-// Picture must have usage from driver before it can load defaults.
- master_channel.copy_usage(vdevice->channel);
- picture->copy_usage(vdevice->picture);
- picture->load_defaults();
-
-// Need to load picture defaults but this requires MWindow.
- vdevice->set_picture(picture);
- vdevice->set_channel(channeldb->get(config.channel));
- }
- prev_channel = config.channel;
- }
-
- if(session && vdevice)
- {
-// Update channel
- if(prev_channel != config.channel)
- {
- prev_channel = config.channel;
- vdevice->set_picture(picture);
- vdevice->set_channel(channeldb->get(config.channel));
- }
-
-
- (void)vdevice->config_updated();
- VFrame *input = frame;
- if(input_cmodel != frame->get_color_model() ||
- session->vconfig_in->w != frame->get_w() ||
- session->vconfig_in->h != frame->get_h())
- {
- if(!temp)
- {
- temp = new VFrame(0,
- -1,
- session->vconfig_in->w,
- session->vconfig_in->h,
- input_cmodel,
- -1);
- }
- input = temp;
- }
-
- vdevice->read_buffer(input);
-
- if(input != frame)
- {
- if(input->get_color_model() != BC_COMPRESSED)
- {
- int w = MIN(session->vconfig_in->w, frame->get_w());
- int h = MIN(session->vconfig_in->h, frame->get_h());
- BC_CModels::transfer(frame->get_rows(), /* Leave NULL if non existent */
- input->get_rows(),
- frame->get_y(), /* Leave NULL if non existent */
- frame->get_u(),
- frame->get_v(),
- input->get_y(), /* Leave NULL if non existent */
- input->get_u(),
- input->get_v(),
- 0, /* Dimensions to capture from input frame */
- 0,
- w,
- h,
- 0, /* Dimensions to project on output frame */
- 0,
- w,
- h,
- input->get_color_model(),
- frame->get_color_model(),
- 0, /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
- input->get_bytes_per_line(), /* For planar use the luma rowspan */
- frame->get_bytes_per_line()); /* For planar use the luma rowspan */
- frame->set_opengl_state(VFrame::RAM);
- }
- else
- if(input->get_compressed_size())
- {
- switch(session->vconfig_in->driver)
- {
- case CAPTURE_FIREWIRE:
- case CAPTURE_IEC61883:
-// Decompress a DV frame from the driver
- if(!dv)
- dv = dv_new();
- dv_read_video(((dv_t*)dv),
- frame->get_rows(),
- input->get_data(),
- input->get_compressed_size(),
- frame->get_color_model());
- frame->set_opengl_state(VFrame::RAM);
- break;
-
- case CAPTURE_BUZ:
- case VIDEO4LINUX2JPEG:
- if(!mjpeg)
- mjpeg = mjpeg_new(frame->get_w(),
- frame->get_h(),
- 2); // fields
- mjpeg_decompress(mjpeg,
- input->get_data(),
- input->get_compressed_size(),
- input->get_field2_offset(),
- frame->get_rows(),
- frame->get_y(),
- frame->get_u(),
- frame->get_v(),
- frame->get_color_model(),
- get_project_smp() + 1);
- break;
-
- case CAPTURE_JPEG_WEBCAM:
- if(!mjpeg)
- mjpeg = mjpeg_new(frame->get_w(),
- frame->get_h(),
- 1); // fields
-// printf("LiveVideo::process_buffer %d %p %d\n",
-// __LINE__,
-// input->get_data(),
-// input->get_compressed_size());
- mjpeg_decompress(mjpeg,
- input->get_data(),
- input->get_compressed_size(),
- 0,
- frame->get_rows(),
- frame->get_y(),
- frame->get_u(),
- frame->get_v(),
- frame->get_color_model(),
- get_project_smp() + 1);
- break;
- }
- }
- else
- {
- printf("LiveVideo::process_buffer %d zero size image\n", __LINE__);
- }
- }
- }
-
- return 0;
-}
-
-void LiveVideo::render_stop()
-{
- if(vdevice)
- {
- vdevice->interrupt_crash();
- vdevice->close_all();
- delete vdevice;
- vdevice = 0;
- }
- delete picture;
- picture = 0;
-}
-
-
-const char* LiveVideo::plugin_title() { return _("Live Video"); }
-int LiveVideo::is_realtime() { return 1; }
-int LiveVideo::is_multichannel() { return 0; }
-int LiveVideo::is_synthesis() { return 1; }
-
-
-
-NEW_WINDOW_MACRO(LiveVideo, LiveVideoWindow)
-
-LOAD_CONFIGURATION_MACRO(LiveVideo, LiveVideoConfig)
-
-
-
-void LiveVideo::save_data(KeyFrame *keyframe)
-{
- FileXML output;
- output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
- output.tag.set_title("LIVEVIDEO");
- output.tag.set_property("CHANNEL", config.channel);
- output.append_tag();
- output.tag.set_title("/LIVEVIDEO");
- output.append_tag();
- output.append_newline();
- output.terminate_string();
-}
-
-void LiveVideo::read_data(KeyFrame *keyframe)
-{
- FileXML input;
-
- input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
- int result = 0;
-
- while(!result)
- {
- result = input.read_tag();
-
- if(!result)
- {
- if(input.tag.title_is("LIVEVIDEO"))
- {
- config.channel = input.tag.get_property("CHANNEL", config.channel);
- }
- }
- }
-}
-
-void LiveVideo::update_gui()
-{
- if(thread)
- {
- if(load_configuration())
- {
- thread->window->lock_window("LiveVideo::update_gui");
- ((LiveVideoWindow*)thread->window)->list->set_selected(
- &((LiveVideoWindow*)thread->window)->channel_list,
- config.channel,
- 1);
- ((LiveVideoWindow*)thread->window)->list->draw_items(1);
- thread->window->unlock_window();
- }
- }
-}
-
-
-
-
-