r793: Small API addon, so plugins can 'see' camera and projector automation
[cinelerra_cv/mob.git] / cinelerra / videodevice.C
blobaa57dcc8b43b5dca2a65493a6a6d4346b1f42cb3
1 #include "assets.h"
2 #include "bccapture.h"
3 #include "channel.h"
4 #include "chantables.h"
5 #include "mutex.h"
6 #include "picture.h"
7 #include "playbackconfig.h"
8 #include "playbackengine.h"
9 #include "preferences.h"
10 #include "quicktime.h"
11 #include "recordconfig.h"
12 #include "recordmonitor.h"
13 #ifdef HAVE_FIREWIRE
14 #include "vdevice1394.h"
15 #endif
16 #include "vdevicebuz.h"
17 #include "vdevicev4l.h"
18 #include "vdevicev4l2.h"
19 #include "vdevicev4l2jpeg.h"
20 #include "vdevicex11.h"
21 #include "videoconfig.h"
22 #include "videodevice.h"
23 #include "videowindow.h"
24 #include "videowindowgui.h"
25 #include "vframe.h"
27 #include <unistd.h>
28 #include <fcntl.h>
30 KeepaliveThread::KeepaliveThread(VideoDevice *device)
31  : Thread()
33         still_alive = 1;
34         failed = 0;
35         interrupted = 0;
36         set_synchronous(1);
37         this->device = device;
38         capturing = 0;
39         startup_lock = new Mutex("KeepaliveThread::startup_lock");
42 KeepaliveThread::~KeepaliveThread()
44         delete startup_lock;
47 int KeepaliveThread::start_keepalive()
49         startup_lock->lock("KeepaliveThread::start_keepalive 1");
50         start();
51         startup_lock->lock("KeepaliveThread::start_keepalive 2");
52         startup_lock->unlock();
55 void KeepaliveThread::run()
57         startup_lock->unlock();
58         while(!interrupted)
59         {
60                 still_alive = 0;
61 // Give the capture a moment
62 // Should fix the delay in case users want slower frame rates.
63                 timer.delay((long)(KEEPALIVE_DELAY * 1000));
65 // See if a capture happened
66                 if(still_alive == 0 && capturing)
67                 {
68 //                      printf("KeepaliveThread::run: device crashed\n");
69                         failed++;
70                 }
71                 else
72                         failed = 0;
73         }
76 int KeepaliveThread::reset_keepalive()
78         still_alive = 1;
81 int KeepaliveThread::get_failed()
83         if(failed) return 1; else return 0;
86 int KeepaliveThread::stop()
88         interrupted = 1;
90 // Force an immediate exit even if capture_frame worked.
91         Thread::end();
92         Thread::join();
101 VideoDevice::VideoDevice(MWindow *mwindow)
103         this->mwindow = mwindow;
104         in_config = new VideoInConfig;
105         out_config = new VideoOutConfig;
106         channel = new Channel;
107         picture = new PictureConfig(mwindow);
108         sharing_lock = new Mutex("VideoDevice::sharing_lock");
109         channel_lock = new Mutex("VideoDevice::channel_lock");
110         picture_lock = new Mutex("VideoDevice::picture_lock");
111         initialize();
115 VideoDevice::~VideoDevice()
117         input_sources.remove_all_objects();
118         delete in_config;
119         delete out_config;
120         delete channel;
121         delete picture;
122         delete sharing_lock;
123         delete channel_lock;
124         delete picture_lock;
127 int VideoDevice::initialize()
129         sharing = 0;
130         done_sharing = 0;
131         sharing_lock->reset();
132         orate = irate = 0;
133         out_w = out_h = 0;
134         r = w = 0;
135         is_playing_back = is_recording = 0;
136         input_x = 0;
137         input_y = 0;
138         input_z = 1;
139         frame_resized = 0;
140         capturing = 0;
141         keepalive = 0;
142         swap_bytes = 0;
143         input_base = 0;
144         output_base = 0;
145         output_format = 0;
146         interrupt = 0;
147         adevice = 0;
148         quality = 80;
149         cpus = 1;
150         single_frame = 0;
151         channel_changed = 0;
152         picture_changed = 0;
155 int VideoDevice::open_input(VideoInConfig *config, 
156         int input_x, 
157         int input_y, 
158         float input_z,
159         float frame_rate)
161         int result = 0;
163         *this->in_config = *config;
165         r = 1;
166         this->input_z = -1;   // Force initialization.
167         this->frame_rate = frame_rate;
170         switch(in_config->driver)
171         {
172                 case VIDEO4LINUX:
173                         keepalive = new KeepaliveThread(this);
174                         keepalive->start_keepalive();
175                         input_base = new VDeviceV4L(this);
176                         result = input_base->open_input();
177                         break;
180 #ifdef HAVE_VIDEO4LINUX2
181                 case VIDEO4LINUX2:
182                         input_base = new VDeviceV4L2(this);
183                         result = input_base->open_input();
184                         break;
185                 case VIDEO4LINUX2JPEG:
186                         input_base = new VDeviceV4L2JPEG(this);
187                         result = input_base->open_input();
188                         break;
189 #endif
191                 case SCREENCAPTURE:
192                         this->input_x = input_x;
193                         this->input_y = input_y;
194                         input_base = new VDeviceX11(this, 0);
195                         result = input_base->open_input();
196                         break;
197                 case CAPTURE_BUZ:
198 //printf("VideoDevice 1\n");
199                         keepalive = new KeepaliveThread(this);
200                         keepalive->start_keepalive();
201                         input_base = new VDeviceBUZ(this);
202                         result = input_base->open_input();
203                         break;
204 #ifdef HAVE_FIREWIRE
205                 case CAPTURE_FIREWIRE:
206                 case CAPTURE_IEC61883:
207                         input_base = new VDevice1394(this);
208                         result = input_base->open_input();
209                         break;
210 #endif
211         }
212         
213         if(!result) capturing = 1;
214         return 0;
217 int VideoDevice::is_compressed(int driver, int use_file, int use_fixed)
219 // FileMOV needs to have write_frames called so the start codes get scanned.
220         return ((driver == CAPTURE_BUZ && use_fixed) ||
221                 (driver == VIDEO4LINUX2JPEG && use_fixed) || 
222                 driver == CAPTURE_LML || 
223                 driver == CAPTURE_FIREWIRE ||
224                 driver == CAPTURE_IEC61883);
227 int VideoDevice::is_compressed(int use_file, int use_fixed)
229         return is_compressed(in_config->driver, use_file, use_fixed);
233 char* VideoDevice::get_vcodec(int driver)
235         switch(driver)
236         {
237                 case CAPTURE_BUZ:
238                 case CAPTURE_LML:
239                 case VIDEO4LINUX2JPEG:
240                         return QUICKTIME_MJPA;
241                         break;
242                 
243                 case CAPTURE_FIREWIRE:
244                 case CAPTURE_IEC61883:
245                         return QUICKTIME_DVSD;
246                         break;
247         }
248         return "";
252 char* VideoDevice::drivertostr(int driver)
254         switch(driver)
255         {
256                 case PLAYBACK_X11:
257                         return PLAYBACK_X11_TITLE;
258                         break;
259                 case PLAYBACK_X11_XV:
260                         return PLAYBACK_X11_XV_TITLE;
261                         break;
262                 case PLAYBACK_BUZ:
263                         return PLAYBACK_BUZ_TITLE;
264                         break;
265                 case VIDEO4LINUX:
266                         return VIDEO4LINUX_TITLE;
267                         break;
268                 case VIDEO4LINUX2:
269                         return VIDEO4LINUX2_TITLE;
270                         break;
271                 case VIDEO4LINUX2JPEG:
272                         return VIDEO4LINUX2JPEG_TITLE;
273                         break;
274                 case SCREENCAPTURE:
275                         return SCREENCAPTURE_TITLE;
276                         break;
277                 case CAPTURE_BUZ:
278                         return CAPTURE_BUZ_TITLE;
279                         break;
280 #ifdef HAVE_FIREWIRE
281                 case CAPTURE_FIREWIRE:
282                         return CAPTURE_FIREWIRE_TITLE;
283                         break;
284                 case CAPTURE_IEC61883:
285                         return CAPTURE_IEC61883_TITLE;
286                         break;
287 #endif
288         }
289         return "";
292 int VideoDevice::get_best_colormodel(Asset *asset)
294         if(input_base)
295                 return input_base->get_best_colormodel(asset);
296         else
297                 return BC_RGB888;
300 int VideoDevice::close_all()
302         int i;
304 //printf("VideoDevice::close_all 1\n");
305         if(w)
306         {
307                 if(output_base)
308                 {
309                         output_base->close_all();
310                         delete output_base;
311                 }
312         }
314 //printf("VideoDevice::close_all 2\n");
315         if(r && capturing)
316         {
317                 capturing = 0;
318                 if(input_base)
319                 {
320                         input_base->close_all();
321                         delete input_base;
322                         input_base = 0;
323                 }
325                 if(keepalive)
326                 {
327                         keepalive->stop();
328                         delete keepalive;
329                 }
330         }
332 //printf("VideoDevice::close_all 3\n");
333         input_sources.remove_all_objects();
335 //printf("VideoDevice::close_all 4\n");
336         initialize();
338 //printf("VideoDevice::close_all 5\n");
339         return 0;
343 int VideoDevice::set_adevice(AudioDevice *adevice)
345         this->adevice = adevice;
346         return 0;
350 ArrayList<Channel*>* VideoDevice::get_inputs()
352         return &input_sources;
355 Channel* VideoDevice::new_input_source(char *device_name)
357         for(int i = 0; i < input_sources.total; i++)
358         {
359                 if(!strcmp(input_sources.values[i]->device_name, device_name))
360                         return input_sources.values[i];
361         }
362         Channel *item = new Channel;
363         strcpy(item->device_name, device_name);
364         input_sources.append(item);
365         return item;
368 int VideoDevice::get_failed()
370         if(keepalive)
371                 return keepalive->get_failed();
372         else
373                 return 0;
376 int VideoDevice::interrupt_crash()
378         if(input_base) return input_base->interrupt_crash();
379         return 0;
382 int VideoDevice::set_translation(int input_x, int input_y)
384         this->input_x = input_x;
385         this->input_y = input_y;
386         return 0;
389 int VideoDevice::set_field_order(int odd_field_first)
391         this->odd_field_first = odd_field_first;
392         return 0;
395 int VideoDevice::set_channel(Channel *channel)
397         if(channel)
398         {
399                 channel_lock->lock("VideoDevice::set_channel");
400                 this->channel->copy_settings(channel);
401                 channel_changed = 1;
402                 channel_lock->unlock();
404                 if(input_base) return input_base->set_channel(channel);
405                 if(output_base) return output_base->set_channel(channel);
406         }
409 void VideoDevice::set_quality(int quality)
411         this->quality = quality;
414 void VideoDevice::set_cpus(int cpus)
416         this->cpus = cpus;
419 int VideoDevice::set_picture(PictureConfig *picture)
421         if(picture)
422         {
423                 picture_lock->lock("VideoDevice::set_picture");
424                 this->picture->copy_settings(picture);
425                 picture_changed = 1;
426                 picture_lock->unlock();
428                 if(input_base) return input_base->set_picture(picture);
429         }
432 int VideoDevice::update_translation()
434         float frame_in_capture_x1f, frame_in_capture_x2f, frame_in_capture_y1f, frame_in_capture_y2f;
435         float capture_in_frame_x1f, capture_in_frame_x2f, capture_in_frame_y1f, capture_in_frame_y2f;
436         int z_changed = 0;
438         if(frame_resized)
439         {
440                 input_x = new_input_x;
441                 input_y = new_input_y;
443                 if(in_config->driver == VIDEO4LINUX || in_config->driver == VIDEO4LINUX2)
444                 {
445                         if(input_z != new_input_z)
446                         {
447                                 input_z = new_input_z;
448                                 z_changed = 1;
450                                 capture_w = (int)((float)in_config->w * input_z + 0.5);
451                                 capture_h = (int)((float)in_config->h * input_z + 0.5);
453 // Need to align to multiple of 4
454                                 capture_w &= ~3;
455                                 capture_h &= ~3;
456                         }
458                         frame_in_capture_x1f = (float)input_x * input_z + capture_w / 2 - in_config->w / 2;
459                         frame_in_capture_x2f = (float)input_x * input_z  + capture_w / 2 + in_config->w / 2;
460                         frame_in_capture_y1f = (float)input_y * input_z  + capture_h / 2 - in_config->h / 2;
461                         frame_in_capture_y2f = (float)input_y * input_z  + capture_h / 2 + in_config->h / 2;
463                         capture_in_frame_x1f = 0;
464                         capture_in_frame_y1f = 0;
465                         capture_in_frame_x2f = in_config->w;
466                         capture_in_frame_y2f = in_config->h;
468                         if(frame_in_capture_x1f < 0) { capture_in_frame_x1f -= frame_in_capture_x1f; frame_in_capture_x1f = 0; }
469                         if(frame_in_capture_y1f < 0) { capture_in_frame_y1f -= frame_in_capture_y1f; frame_in_capture_y1f = 0; }
470                         if(frame_in_capture_x2f > capture_w) { capture_in_frame_x2f -= frame_in_capture_x2f - capture_w; frame_in_capture_x2f = capture_w; }
471                         if(frame_in_capture_y2f > capture_h) { capture_in_frame_y2f -= frame_in_capture_y2f - capture_h; frame_in_capture_y2f = capture_h; }
473                         frame_in_capture_x1 = (int)frame_in_capture_x1f;
474                         frame_in_capture_y1 = (int)frame_in_capture_y1f;
475                         frame_in_capture_x2 = (int)frame_in_capture_x2f;
476                         frame_in_capture_y2 = (int)frame_in_capture_y2f;
478                         capture_in_frame_x1 = (int)capture_in_frame_x1f;
479                         capture_in_frame_y1 = (int)capture_in_frame_y1f;
480                         capture_in_frame_x2 = (int)capture_in_frame_x2f;
481                         capture_in_frame_y2 = (int)capture_in_frame_y2f;
483                         frame_resized = 0;
484                 }
485         }
486         return 0;
489 int VideoDevice::set_latency_counter(int value)
491         latency_counter = value;
492         return 0;
495 int VideoDevice::has_signal()
497         if(input_base) return input_base->has_signal();
498         return 0;
502 int VideoDevice::read_buffer(VFrame *frame)
504         int result = 0;
505         if(!capturing) return 0;
507 //printf("VideoDevice::read_buffer %p %p\n", frame, input_base);
508         if(input_base)
509         {
510 // Reset the keepalive thread
511                 if(keepalive) keepalive->capturing = 1;
512                 result = input_base->read_buffer(frame);
513                 if(keepalive)
514                 {
515                         keepalive->capturing = 0;
516                         keepalive->reset_keepalive();
517                 }
518                 return result;
519         }
521         return 0;
525 // ================================= OUTPUT ==========================================
528 int VideoDevice::open_output(VideoOutConfig *config, 
529                                         float rate, 
530                                         int out_w, 
531                                         int out_h,
532                                         Canvas *output,
533                                         int single_frame)
535         w = 1;
536 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
537         *this->out_config = *config;
538 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
539         this->out_w = out_w;
540         this->out_h = out_h;
541         this->orate = rate;
542         this->single_frame = single_frame;
544 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
545         switch(out_config->driver)
546         {
547                 case PLAYBACK_BUZ:
548                         output_base = new VDeviceBUZ(this);
549                         break;
550                 case PLAYBACK_X11:
551                 case PLAYBACK_X11_XV:
552                         output_base = new VDeviceX11(this, output);
553                         break;
555 #ifdef HAVE_FIREWIRE
556                 case PLAYBACK_DV1394:
557                 case PLAYBACK_FIREWIRE:
558                 case PLAYBACK_IEC61883:
559                         output_base = new VDevice1394(this);
560                         break;
561 #endif
562         }
563 //printf("VideoDevice::open_output 2 %d\n", out_config->driver);
565         if(output_base->open_output())
566         {
567                 delete output_base;
568                 output_base = 0;
569         }
570 //printf("VideoDevice::open_output 3 %d\n", out_config->driver);
572         if(output_base) 
573                 return 0;
574         else
575                 return 1;
580 int VideoDevice::start_playback()
582 // arm buffer before doing this
583         is_playing_back = 1;
584         interrupt = 0;
586         if(output_base) return output_base->start_playback();
587         return 1;
590 int VideoDevice::stop_playback()
592         if(output_base) output_base->stop_playback();
593         is_playing_back = 0;
594         interrupt = 0;
595         return 0;
598 void VideoDevice::goose_input()
600         if(input_base) input_base->goose_input();
603 void VideoDevice::new_output_buffers(VFrame **outputs, int colormodel)
605         for(int i = 0; i < MAX_CHANNELS; i++)
606                 outputs[i] = 0;
608         if(!output_base) return;
609         output_base->new_output_buffer(outputs, colormodel);
613 int VideoDevice::interrupt_playback()
615         interrupt = 1;
616         return 0;
619 int VideoDevice::write_buffer(VFrame **outputs, EDL *edl)
621 //printf("VideoDevice::write_buffer 1 %p\n", output_base);
622         if(output_base) return output_base->write_buffer(outputs, edl);
623         return 1;
626 int VideoDevice::output_visible()
628         if(output_base) return output_base->output_visible();
631 BC_Bitmap* VideoDevice::get_bitmap()
633         if(output_base) return output_base->get_bitmap();
637 int VideoDevice::set_cloexec_flag(int desc, int value)
639         int oldflags = fcntl(desc, F_GETFD, 0);
640         if(oldflags < 0) return oldflags;
641         if(value != 0) 
642                 oldflags |= FD_CLOEXEC;
643         else
644                 oldflags &= ~FD_CLOEXEC;
645         return fcntl(desc, F_SETFD, oldflags);