+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008-2013 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 "assets.h"
-#include "bccapture.h"
-#include "bcsignals.h"
-#include "channel.h"
-#include "channeldb.h"
-#include "chantables.h"
-#include "edl.h"
-#include "edlsession.h"
-#include "file.inc"
-#include "../hvirtual_config.h"
-#include "libdv.h"
-#include "libmjpeg.h"
-#include "mainmenu.h"
-#include "mutex.h"
-#include "mwindow.h"
-#include "mwindowgui.h"
-#include "picture.h"
-#include "playbackconfig.h"
-#include "playbackengine.h"
-#include "preferences.h"
-#include "recordconfig.h"
-#include "recordgui.h"
-#include "recordmonitor.h"
-#include "record.h"
-#include "vdevice1394.h"
-#include "vdevicebuz.h"
-#include "vdevicedvb.h"
-#include "vdevicev4l.h"
-#include "vdevicev4l2.h"
-#include "vdevicev4l2jpeg.h"
-#include "vdevicev4l2mpeg.h"
-#include "vdevicex11.h"
-#include "videoconfig.h"
-#include "videodevice.h"
-#include "videowindow.h"
-#include "videowindowgui.h"
-#include "vframe.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-
-KeepaliveThread::KeepaliveThread(VideoDevice *device)
- : Thread(1, 0, 0)
-{
- still_alive = 1;
- failed = 0;
- interrupted = 0;
- set_synchronous(1);
- this->device = device;
- capturing = 0;
- startup_lock = new Mutex("KeepaliveThread::startup_lock");
-}
-
-KeepaliveThread::~KeepaliveThread()
-{
- delete startup_lock;
-}
-
-int KeepaliveThread::start_keepalive()
-{
- startup_lock->lock("KeepaliveThread::start_keepalive 1");
- start();
- startup_lock->lock("KeepaliveThread::start_keepalive 2");
- startup_lock->unlock();
- return 0;
-}
-
-void KeepaliveThread::run()
-{
- startup_lock->unlock();
- while(!interrupted)
- {
- still_alive = 0;
-// Give the capture a moment
-// Should fix the delay in case users want slower frame rates.
- timer.delay((long)(KEEPALIVE_DELAY * 1000));
-
-// See if a capture happened
- if(still_alive == 0 && capturing)
- {
-// printf("KeepaliveThread::run: device crashed\n");
- failed++;
- }
- else
- failed = 0;
- }
-}
-
-int KeepaliveThread::reset_keepalive()
-{
- still_alive = 1;
- return 0;
-}
-
-int KeepaliveThread::get_failed()
-{
- if(failed) return 1; else return 0;
-}
-
-int KeepaliveThread::stop()
-{
- interrupted = 1;
-
-// Force an immediate exit even if capture_frame worked.
- Thread::cancel();
- Thread::join();
- return 0;
-}
-
-
-
-
-
-
-
-VideoDevice::VideoDevice(MWindow *mwindow)
-{
- this->mwindow = mwindow;
- in_config = new VideoInConfig;
- out_config = new VideoOutConfig;
- channel = new Channel;
- picture = new PictureConfig();
- sharing_lock = new Mutex("VideoDevice::sharing_lock");
- channel_lock = new Mutex("VideoDevice::channel_lock");
- picture_lock = new Mutex("VideoDevice::picture_lock");
- initialize();
-}
-
-
-VideoDevice::~VideoDevice()
-{
- input_sources.remove_all_objects();
- delete in_config;
- delete out_config;
- delete channel;
- delete picture;
- delete sharing_lock;
- delete channel_lock;
- delete picture_lock;
-}
-
-int VideoDevice::initialize()
-{
- sharing = 0;
- done_sharing = 0;
- sharing_lock->reset();
- orate = irate = 0;
- out_w = out_h = 0;
- r = w = 0;
- is_playing_back = is_recording = 0;
- input_x = 0;
- input_y = 0;
- input_z = 1;
- frame_resized = 0;
- frame_rate = 0;
- timestamp = -1.;
- capturing = 0;
- keepalive = 0;
- swap_bytes = 0;
- in_config_updated = 0;
- input_base = 0;
- output_base = 0;
- output_format = 0;
- interrupt = 0;
- adevice = 0;
- quality = 80;
- cpus = 1;
- single_frame = 0;
- channel_changed = 0;
- picture_changed = 0;
- return 0;
-}
-
-int VideoDevice::open_input(VideoInConfig *config,
- int input_x,
- int input_y,
- float input_z,
- double frame_rate)
-{
- int result = 0;
-
- *this->in_config = *config;
-
- r = 1;
- this->input_z = -1; // Force initialization.
- this->frame_rate = frame_rate;
- if( input_base ) return 1; // device already open
-
- switch(in_config->driver) {
- case VIDEO4LINUX:
- keepalive = new KeepaliveThread(this);
- keepalive->start_keepalive();
- break;
-
-
-#ifdef HAVE_VIDEO4LINUX2
-
- case VIDEO4LINUX2:
- case VIDEO4LINUX2JPEG:
- case VIDEO4LINUX2MPEG:
- case CAPTURE_JPEG_WEBCAM:
- case CAPTURE_YUYV_WEBCAM:
- break;
-
-#endif
-
- case SCREENCAPTURE:
- this->input_x = input_x;
- this->input_y = input_y;
- break;
- case CAPTURE_LML:
- case CAPTURE_BUZ:
-//printf("VideoDevice 1\n");
- keepalive = new KeepaliveThread(this);
- keepalive->start_keepalive();
- break;
-#ifdef HAVE_FIREWIRE
- case CAPTURE_FIREWIRE:
- case CAPTURE_IEC61883:
- break;
-#endif
-
-#ifdef HAVE_DVB
- case CAPTURE_DVB:
- break;
-#endif
-
- default:
- return 1;
- }
-
- new_device_base();
- if( !input_base ) return 1;
- result = input_base->open_input();
- if(!result) capturing = 1;
- in_config_updated = 0;
- return 0;
-}
-
-VDeviceBase* VideoDevice::new_device_base()
-{
- switch(in_config->driver) {
-#ifdef HAVE_VIDEO4LINUX
- case VIDEO4LINUX:
- return input_base = new VDeviceV4L(this);
-#endif
-
-#ifdef HAVE_VIDEO4LINUX2
- case VIDEO4LINUX2:
- case CAPTURE_JPEG_WEBCAM:
- case CAPTURE_YUYV_WEBCAM:
- return input_base = new VDeviceV4L2(this);
- case VIDEO4LINUX2JPEG:
- return input_base = new VDeviceV4L2JPEG(this);
- case VIDEO4LINUX2MPEG:
- return input_base = new VDeviceV4L2MPEG(this);
-#endif
-
- case SCREENCAPTURE:
- return input_base = new VDeviceX11(this, 0);
-
-#ifdef HAVE_VIDEO4LINUX
- case CAPTURE_BUZ:
- return input_base = new VDeviceBUZ(this);
- case CAPTURE_LML:
- return input_base = new VDeviceLML(this);
-#endif
-
-#ifdef HAVE_FIREWIRE
- case CAPTURE_FIREWIRE:
- case CAPTURE_IEC61883:
- return input_base = new VDevice1394(this);
-#endif
-
-#ifdef HAVE_DVB
- case CAPTURE_DVB:
- return input_base = new VDeviceDVB(this);
-#endif
- }
- return 0;
-}
-
-static char* get_channeldb_path(VideoInConfig *vconfig_in)
-{
- char *path = 0;
- switch(vconfig_in->driver)
- {
- case VIDEO4LINUX:
- path = (char*)"channels_v4l";
- break;
- case VIDEO4LINUX2:
- case CAPTURE_JPEG_WEBCAM:
- case CAPTURE_YUYV_WEBCAM:
- path = (char*)"channels_v4l2";
- break;
- case VIDEO4LINUX2JPEG:
- path = (char*)"channels_v4l2jpeg";
- break;
- case VIDEO4LINUX2MPEG:
- path = (char*)"channels_v4l2mpeg";
- break;
- case CAPTURE_BUZ:
- path = (char*)"channels_buz";
- break;
- case CAPTURE_DVB:
- path = (char*)"channels_dvb";
- break;
- }
- return path;
-}
-
-void VideoDevice::load_channeldb(ChannelDB *channeldb, VideoInConfig *vconfig_in)
-{
- channeldb->load(get_channeldb_path(vconfig_in));
-}
-
-void VideoDevice::save_channeldb(ChannelDB *channeldb, VideoInConfig *vconfig_in)
-{
- channeldb->save(get_channeldb_path(vconfig_in));
-}
-
-
-VDeviceBase* VideoDevice::get_input_base()
-{
- return input_base;
-}
-
-VDeviceBase* VideoDevice::get_output_base()
-{
- return output_base;
-}
-
-DeviceMPEGInput *VideoDevice::mpeg_device()
-{
- return !input_base ? 0 : input_base->mpeg_device();
-}
-
-int VideoDevice::is_compressed(int driver, int use_file, int use_fixed)
-{
-// FileMOV needs to have write_frames called so the start codes get scanned.
- return ((driver == CAPTURE_BUZ && use_fixed) ||
- (driver == VIDEO4LINUX2JPEG && use_fixed) ||
- (driver == CAPTURE_JPEG_WEBCAM && use_fixed) ||
- driver == CAPTURE_LML ||
- driver == CAPTURE_FIREWIRE ||
- driver == CAPTURE_IEC61883);
-}
-
-int VideoDevice::is_compressed(int use_file, int use_fixed)
-{
- return is_compressed(in_config->driver, use_file, use_fixed);
-}
-
-
-void VideoDevice::fix_asset(Asset *asset, int driver)
-{
-// Fix asset using legacy routine
- const char *vcodec = 0;
- switch(driver) {
- case CAPTURE_IEC61883:
- case CAPTURE_FIREWIRE:
- vcodec = CODEC_TAG_DVSD;
- break;
-
- case CAPTURE_BUZ:
- case CAPTURE_LML:
- case VIDEO4LINUX2JPEG:
- vcodec = CODEC_TAG_MJPEG;
- break;
-
- case CAPTURE_JPEG_WEBCAM:
- vcodec = CODEC_TAG_JPEG;
- break;
- }
- if( vcodec ) {
- asset->format = FILE_FFMPEG;
- strcpy(asset->vcodec, vcodec);
- return;
- }
-
-// Fix asset using inherited routine
- new_device_base();
-
- if(input_base) input_base->fix_asset(asset);
- delete input_base;
- input_base = 0;
-}
-
-
-const char* VideoDevice::drivertostr(int driver)
-{
- switch(driver) {
- case PLAYBACK_X11: return PLAYBACK_X11_TITLE;
- case PLAYBACK_X11_XV: return PLAYBACK_X11_XV_TITLE;
- case PLAYBACK_X11_GL: return PLAYBACK_X11_GL_TITLE;
- case PLAYBACK_BUZ: return PLAYBACK_BUZ_TITLE;
- case VIDEO4LINUX: return VIDEO4LINUX_TITLE;
- case VIDEO4LINUX2: return VIDEO4LINUX2_TITLE;
- case VIDEO4LINUX2JPEG: return VIDEO4LINUX2JPEG_TITLE;
- case VIDEO4LINUX2MPEG: return VIDEO4LINUX2MPEG_TITLE;
- case CAPTURE_JPEG_WEBCAM: return CAPTURE_JPEG_WEBCAM_TITLE;
- case CAPTURE_YUYV_WEBCAM: return CAPTURE_YUYV_WEBCAM_TITLE;
- case SCREENCAPTURE: return SCREENCAPTURE_TITLE;
- case CAPTURE_BUZ: return CAPTURE_BUZ_TITLE;
- case CAPTURE_LML: return CAPTURE_LML_TITLE;
- case CAPTURE_DVB: return CAPTURE_DVB_TITLE;
- case CAPTURE_FIREWIRE: return CAPTURE_FIREWIRE_TITLE;
- case CAPTURE_IEC61883: return CAPTURE_IEC61883_TITLE;
- }
- return "";
-}
-
-int VideoDevice::get_best_colormodel(Asset *asset)
-{
- return input_base ? input_base->get_best_colormodel(asset) : BC_RGB888;
-}
-
-int VideoDevice::drop_frames(int frames)
-{
- return input_base ? input_base->drop_frames(frames) : 1;
-}
-
-double VideoDevice::device_timestamp()
-{
- return input_base ? input_base->device_timestamp() : -1.;
-}
-
-double VideoDevice::get_timestamp()
-{
- return timestamp;
-}
-
-int VideoDevice::close_all()
-{
- if(w) {
- if( output_base ) {
- output_base->close_all();
- delete output_base;
- output_base = 0;
- }
- }
-
- if(r && capturing) {
- capturing = 0;
- if(input_base) {
- input_base->close_all();
- delete input_base;
- input_base = 0;
- }
- if(keepalive) {
- keepalive->stop();
- delete keepalive;
- }
- }
-
- input_sources.remove_all_objects();
- initialize();
- return 0;
-}
-
-
-int VideoDevice::set_adevice(AudioDevice *adev)
-{
- adevice = adev;
- return 0;
-}
-
-
-ArrayList<Channel*>* VideoDevice::get_inputs()
-{
- return &input_sources;
-}
-
-Channel* VideoDevice::new_input_source(char *device_name)
-{
- for( int i=0; i<input_sources.total; ++i ) {
- if(!strcmp(input_sources.values[i]->device_name, device_name))
- return input_sources.values[i];
- }
- Channel *item = new Channel;
- strcpy(item->device_name, device_name);
- input_sources.append(item);
- return item;
-}
-
-int VideoDevice::get_failed()
-{
- return keepalive ? keepalive->get_failed() : 0;
-}
-
-int VideoDevice::interrupt_crash()
-{
- return input_base ? input_base->interrupt_crash() : 0;
-}
-
-int VideoDevice::set_translation(int in_x, int in_y)
-{
- input_x = in_x;
- input_y = in_y;
- return 0;
-}
-
-int VideoDevice::set_field_order(int odd_field_first)
-{
- this->odd_field_first = odd_field_first;
- return 0;
-}
-
-int VideoDevice::set_channel(Channel *channel)
-{
- int result = 0;
- if( channel ) {
- channel_lock->lock("VideoDevice::set_channel");
- this->channel->copy_settings(channel);
- channel_changed = 1;
- channel_lock->unlock();
- result = input_base ? input_base->set_channel(channel) :
- output_base ? output_base->set_channel(channel) :
- 1;
- }
- return result;
-}
-
-int VideoDevice::set_captioning(int mode)
-{
- if( input_base )
- input_base->set_captioning(mode);
- return 0;
-}
-
-void VideoDevice::set_quality(int quality)
-{
- this->quality = quality;
-}
-
-void VideoDevice::set_cpus(int cpus)
-{
- this->cpus = cpus;
-}
-
-int VideoDevice::set_picture(PictureConfig *picture)
-{
- if( picture ) {
- picture_lock->lock("VideoDevice::set_picture");
- this->picture->copy_settings(picture);
- picture_changed = 1;
- picture_lock->unlock();
-
- if(input_base) return input_base->set_picture(picture);
- }
- return 0;
-}
-
-int VideoDevice::update_translation()
-{
- float frame_in_capture_x1f, frame_in_capture_x2f, frame_in_capture_y1f, frame_in_capture_y2f;
- float capture_in_frame_x1f, capture_in_frame_x2f, capture_in_frame_y1f, capture_in_frame_y2f;
- //int z_changed = 0;
-
- if(frame_resized) {
- input_x = new_input_x;
- input_y = new_input_y;
- if( in_config->driver == VIDEO4LINUX ||
- in_config->driver == VIDEO4LINUX2 ) {
- if(input_z != new_input_z) {
- input_z = new_input_z;
- //z_changed = 1;
-
- capture_w = (int)((float)in_config->w * input_z + 0.5);
- capture_h = (int)((float)in_config->h * input_z + 0.5);
-
-// Need to align to multiple of 4
- capture_w &= ~3;
- capture_h &= ~3;
- }
-
- frame_in_capture_x1f = (float)input_x * input_z + capture_w / 2 - in_config->w / 2;
- frame_in_capture_x2f = (float)input_x * input_z + capture_w / 2 + in_config->w / 2;
- frame_in_capture_y1f = (float)input_y * input_z + capture_h / 2 - in_config->h / 2;
- frame_in_capture_y2f = (float)input_y * input_z + capture_h / 2 + in_config->h / 2;
-
- capture_in_frame_x1f = 0;
- capture_in_frame_y1f = 0;
- capture_in_frame_x2f = in_config->w;
- capture_in_frame_y2f = in_config->h;
-
- if(frame_in_capture_x1f < 0) { capture_in_frame_x1f -= frame_in_capture_x1f; frame_in_capture_x1f = 0; }
- if(frame_in_capture_y1f < 0) { capture_in_frame_y1f -= frame_in_capture_y1f; frame_in_capture_y1f = 0; }
- if(frame_in_capture_x2f > capture_w) { capture_in_frame_x2f -= frame_in_capture_x2f - capture_w; frame_in_capture_x2f = capture_w; }
- if(frame_in_capture_y2f > capture_h) { capture_in_frame_y2f -= frame_in_capture_y2f - capture_h; frame_in_capture_y2f = capture_h; }
-
- frame_in_capture_x1 = (int)frame_in_capture_x1f;
- frame_in_capture_y1 = (int)frame_in_capture_y1f;
- frame_in_capture_x2 = (int)frame_in_capture_x2f;
- frame_in_capture_y2 = (int)frame_in_capture_y2f;
-
- capture_in_frame_x1 = (int)capture_in_frame_x1f;
- capture_in_frame_y1 = (int)capture_in_frame_y1f;
- capture_in_frame_x2 = (int)capture_in_frame_x2f;
- capture_in_frame_y2 = (int)capture_in_frame_y2f;
-
- frame_resized = 0;
- }
- }
- return 0;
-}
-
-int VideoDevice::set_latency_counter(int value)
-{
- latency_counter = value;
- return 0;
-}
-
-int VideoDevice::has_signal()
-{
- return input_base ? input_base->has_signal() : 0;
-}
-
-int VideoDevice::create_channeldb(ArrayList<Channel*> *channeldb)
-{
- return input_base ? input_base->create_channeldb(channeldb) : 1;
-}
-
-
-int VideoDevice::read_buffer(VFrame *frame)
-{
- int result = 0;
- if(!capturing) return 0;
-
-//printf("VideoDevice::read_buffer %p %p\n", frame, input_base);
- if(input_base) {
-// Reset the keepalive thread
- if(keepalive) keepalive->capturing = 1;
- result = input_base->read_buffer(frame);
- timestamp = frame->get_timestamp();
- if( timestamp < 0 ) {
- struct timeval tv; gettimeofday(&tv, 0);
- timestamp = tv.tv_sec + tv.tv_usec / 1000000.0;
- }
- if(keepalive) {
- keepalive->capturing = 0;
- keepalive->reset_keepalive();
- }
- return result;
- }
-
- return 0;
-}
-
-
-// ================================= OUTPUT ==========================================
-
-
-int VideoDevice::open_output(VideoOutConfig *config, float rate,
- int out_w, int out_h, Canvas *output, int single_frame)
-{
- w = 1;
-//printf("VideoDevice::open_output 1 %d\n", out_config->driver);
- *this->out_config = *config;
-//printf("VideoDevice::open_output 1 %d\n", out_config->driver);
- this->out_w = out_w;
- this->out_h = out_h;
- this->orate = rate;
- this->single_frame = single_frame;
-
-//printf("VideoDevice::open_output 1 %d\n", out_config->driver);
- switch(out_config->driver) {
-#ifdef HAVE_VIDEO4LINUX
- case PLAYBACK_BUZ:
- output_base = new VDeviceBUZ(this);
- break;
- case PLAYBACK_LML:
- output_base = new VDeviceLML(this);
- break;
-#endif
- case PLAYBACK_X11:
- case PLAYBACK_X11_XV:
- case PLAYBACK_X11_GL:
- output_base = new VDeviceX11(this, output);
- break;
-
- case PLAYBACK_DV1394:
- case PLAYBACK_FIREWIRE:
- case PLAYBACK_IEC61883:
- output_base = new VDevice1394(this);
- break;
- }
-//printf("VideoDevice::open_output 2 %d\n", out_config->driver);
-
- if(output_base->open_output()) {
- delete output_base;
- output_base = 0;
- }
-//printf("VideoDevice::open_output 3 %d\n", out_config->driver);
- return output_base ? 0 : 1;
-}
-
-
-
-int VideoDevice::start_playback()
-{
-// arm buffer before doing this
- is_playing_back = 1;
- interrupt = 0;
- return output_base ? output_base->start_playback() : 1;
-}
-
-int VideoDevice::stop_playback()
-{
- if( output_base ) output_base->stop_playback();
- is_playing_back = 0;
- interrupt = 0;
- return 0;
-}
-
-void VideoDevice::goose_input()
-{
- if(input_base) input_base->goose_input();
-}
-
-void VideoDevice::new_output_buffer(VFrame **output, int colormodel)
-{
- if(!output_base) return;
- output_base->new_output_buffer(output, colormodel);
-}
-
-
-int VideoDevice::interrupt_playback()
-{
- interrupt = 1;
- return 0;
-}
-
-int VideoDevice::write_buffer(VFrame *output, EDL *edl)
-{
- return output_base ? output_base->write_buffer(output, edl) : 1;
-}
-
-int VideoDevice::output_visible()
-{
- return output_base ? output_base->output_visible() : 0;
-}
-
-BC_Bitmap* VideoDevice::get_bitmap()
-{
- return output_base ? output_base->get_bitmap() : 0;
-}
-
-
-int VideoDevice::set_cloexec_flag(int desc, int value)
-{
- int oldflags = fcntl(desc, F_GETFD, 0);
- if( oldflags < 0 ) return oldflags;
- if( value != 0 )
- oldflags |= FD_CLOEXEC;
- else
- oldflags &= ~FD_CLOEXEC;
- return fcntl(desc, F_SETFD, oldflags);
-}
-
-
-void VideoDevice::auto_update(double rate, int width, int height)
-{
- if( !in_config || !in_config->follow_video ) return;
- capture_w = width;
- capture_h = height;
- frame_rate = rate;
- in_config_updated = 1;
-}
-
-int VideoDevice::config_updated()
-{
- if( !in_config || !in_config->follow_video ) return 0;
- return in_config_updated;
-}
-
-void VideoDevice::config_update()
-{
- in_config_updated = 0;
- VideoInConfig *vconfig_in = mwindow->edl->session->vconfig_in;
- vconfig_in->w = capture_w;
- vconfig_in->h = capture_h;
- vconfig_in->in_framerate = frame_rate;
-}
-
-
-int VideoDevice::start_toc(const char *path, const char *toc_path)
-{
- return input_base ? input_base->start_toc(path, toc_path) : -1;
-}
-
-int VideoDevice::start_record(int fd, int bsz)
-{
- return input_base ? input_base->start_record(fd, bsz) : -1;
-}
-
-int VideoDevice::stop_record()
-{
- return input_base ? input_base->stop_record() : -1;
-}
-
-
-int VideoDevice::total_video_streams()
-{
- return input_base ? input_base->total_video_streams() : 0;
-}
-
-
-// skimming
-int VideoDevice::get_video_pid(int track)
-{
- return !input_base ? -1 : input_base->get_video_pid(track);
-
-}
-
-int VideoDevice::get_video_info(int track, int &pid,
- double &framerate, int &width, int &height, char *title)
-{
- return !input_base ? 1 : input_base->
- get_video_info(track, pid, framerate, width, height, title);
-}
-
-int VideoDevice::get_thumbnail(int stream, int64_t &position,
- unsigned char *&thumbnail, int &ww, int &hh)
-{
- return !input_base ? 1 :
- input_base->get_thumbnail(stream, position, thumbnail, ww, hh);
-}
-
-int VideoDevice::set_skimming(int track, int skim, skim_fn fn, void *vp)
-{
- return !input_base ? 1 :
- input_base->set_skimming(track, skim, fn, vp);
-}
-