r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / cinelerra / videodevice.C
blob933aab475383d963aa8affccd0f96dd75582c2f6
1 #include "assets.h"
2 #include "bccapture.h"
3 #include "channel.h"
4 #include "chantables.h"
5 #include "../hvirtual_config.h"
6 #include "mutex.h"
7 #include "picture.h"
8 #include "playbackconfig.h"
9 #include "playbackengine.h"
10 #include "preferences.h"
11 #include "recordconfig.h"
12 #include "recordmonitor.h"
13 #include "vdevice1394.h"
14 #include "vdevicebuz.h"
15 #include "vdevicev4l.h"
16 #include "vdevicev4l2.h"
17 #include "vdevicev4l2jpeg.h"
18 #include "vdevicex11.h"
19 #include "videoconfig.h"
20 #include "videodevice.h"
21 #include "videowindow.h"
22 #include "videowindowgui.h"
23 #include "vframe.h"
25 #include <unistd.h>
26 #include <fcntl.h>
28 KeepaliveThread::KeepaliveThread(VideoDevice *device)
29  : Thread()
31         still_alive = 1;
32         failed = 0;
33         interrupted = 0;
34         set_synchronous(1);
35         this->device = device;
36         capturing = 0;
37         startup_lock = new Mutex("KeepaliveThread::startup_lock");
40 KeepaliveThread::~KeepaliveThread()
42         delete startup_lock;
45 int KeepaliveThread::start_keepalive()
47         startup_lock->lock("KeepaliveThread::start_keepalive 1");
48         start();
49         startup_lock->lock("KeepaliveThread::start_keepalive 2");
50         startup_lock->unlock();
53 void KeepaliveThread::run()
55         startup_lock->unlock();
56         while(!interrupted)
57         {
58                 still_alive = 0;
59 // Give the capture a moment
60 // Should fix the delay in case users want slower frame rates.
61                 timer.delay((long)(KEEPALIVE_DELAY * 1000));
63 // See if a capture happened
64                 if(still_alive == 0 && capturing)
65                 {
66 //                      printf("KeepaliveThread::run: device crashed\n");
67                         failed++;
68                 }
69                 else
70                         failed = 0;
71         }
74 int KeepaliveThread::reset_keepalive()
76         still_alive = 1;
79 int KeepaliveThread::get_failed()
81         if(failed) return 1; else return 0;
84 int KeepaliveThread::stop()
86         interrupted = 1;
88 // Force an immediate exit even if capture_frame worked.
89         Thread::end();
90         Thread::join();
99 VideoDevice::VideoDevice()
101         in_config = new VideoInConfig;
102         out_config = new VideoOutConfig;
103         channel = new Channel;
104         picture = new Picture;
105         sharing_lock = new Mutex("VideoDevice::sharing_lock");
106         channel_lock = new Mutex("VideoDevice::channel_lock");
107         picture_lock = new Mutex("VideoDevice::picture_lock");
108         initialize();
111 VideoDevice::~VideoDevice()
113         input_sources.remove_all_objects();
114         delete in_config;
115         delete out_config;
116         delete channel;
117         delete picture;
118         delete sharing_lock;
119         delete channel_lock;
120         delete picture_lock;
123 int VideoDevice::initialize()
125         sharing = 0;
126         done_sharing = 0;
127         sharing_lock->reset();
128         orate = irate = 0;
129         out_w = out_h = 0;
130         r = w = 0;
131         is_playing_back = is_recording = 0;
132         input_x = 0;
133         input_y = 0;
134         input_z = 1;
135         frame_resized = 0;
136         capturing = 0;
137         keepalive = 0;
138         swap_bytes = 0;
139         input_base = 0;
140         output_base = 0;
141         output_format = 0;
142         interrupt = 0;
143         adevice = 0;
144         quality = 80;
145         cpus = 1;
146         single_frame = 0;
147         channel_changed = 0;
148         picture_changed = 0;
151 int VideoDevice::open_input(VideoInConfig *config, 
152         int input_x, 
153         int input_y, 
154         float input_z,
155         float frame_rate)
157         int result = 0;
159         *this->in_config = *config;
161         r = 1;
162         this->input_z = -1;   // Force initialization.
163         this->frame_rate = frame_rate;
166         switch(in_config->driver)
167         {
168                 case VIDEO4LINUX:
169                         keepalive = new KeepaliveThread(this);
170                         keepalive->start_keepalive();
171                         input_base = new VDeviceV4L(this);
172                         result = input_base->open_input();
173                         break;
176 #ifdef HAVE_VIDEO4LINUX2
177                 case VIDEO4LINUX2:
178                         input_base = new VDeviceV4L2(this);
179                         result = input_base->open_input();
180                         break;
181                 case VIDEO4LINUX2JPEG:
182                         input_base = new VDeviceV4L2JPEG(this);
183                         result = input_base->open_input();
184                         break;
185 #endif
187                 case SCREENCAPTURE:
188                         this->input_x = input_x;
189                         this->input_y = input_y;
190                         input_base = new VDeviceX11(this, 0);
191                         result = input_base->open_input();
192                         break;
193                 case CAPTURE_BUZ:
194 //printf("VideoDevice 1\n");
195                         keepalive = new KeepaliveThread(this);
196                         keepalive->start_keepalive();
197                         input_base = new VDeviceBUZ(this);
198                         result = input_base->open_input();
199                         break;
200 #ifdef HAVE_FIREWIRE
201                 case CAPTURE_FIREWIRE:
202                         input_base = new VDevice1394(this);
203                         result = input_base->open_input();
204                         break;
205 #endif
206         }
207         
208         if(!result) capturing = 1;
209         return 0;
212 int VideoDevice::is_compressed(int driver, int use_file, int use_fixed)
214 // FileMOV needs to have write_frames called so the start codes get scanned.
215         return ((driver == CAPTURE_BUZ && use_fixed) ||
216                 (driver == VIDEO4LINUX2JPEG && use_fixed) || 
217                 driver == CAPTURE_LML || 
218                 driver == CAPTURE_FIREWIRE);
221 int VideoDevice::is_compressed(int use_file, int use_fixed)
223         return is_compressed(in_config->driver, use_file, use_fixed);
227 char* VideoDevice::get_vcodec(int driver)
229         switch(driver)
230         {
231                 case CAPTURE_BUZ:
232                 case CAPTURE_LML:
233                 case VIDEO4LINUX2JPEG:
234                         return QUICKTIME_MJPA;
235                         break;
236                 
237                 case CAPTURE_FIREWIRE:
238                         return QUICKTIME_DV;
239                         break;
240         }
241         return "";
245 char* VideoDevice::drivertostr(int driver)
247         switch(driver)
248         {
249                 case PLAYBACK_X11:
250                         return PLAYBACK_X11_TITLE;
251                         break;
252                 case PLAYBACK_X11_XV:
253                         return PLAYBACK_X11_XV_TITLE;
254                         break;
255                 case PLAYBACK_BUZ:
256                         return PLAYBACK_BUZ_TITLE;
257                         break;
258                 case VIDEO4LINUX:
259                         return VIDEO4LINUX_TITLE;
260                         break;
261                 case VIDEO4LINUX2:
262                         return VIDEO4LINUX2_TITLE;
263                         break;
264                 case VIDEO4LINUX2JPEG:
265                         return VIDEO4LINUX2JPEG_TITLE;
266                         break;
267                 case SCREENCAPTURE:
268                         return SCREENCAPTURE_TITLE;
269                         break;
270                 case CAPTURE_BUZ:
271                         return CAPTURE_BUZ_TITLE;
272                         break;
273                 case CAPTURE_FIREWIRE:
274                         return CAPTURE_FIREWIRE_TITLE;
275                         break;
276         }
277         return "";
280 int VideoDevice::get_best_colormodel(Asset *asset)
282         if(input_base)
283                 return input_base->get_best_colormodel(asset);
284         else
285                 return BC_RGB888;
288 int VideoDevice::close_all()
290         int i;
292 //printf("VideoDevice::close_all 1\n");
293         if(w)
294         {
295                 if(output_base)
296                 {
297                         output_base->close_all();
298                         delete output_base;
299                 }
300         }
302 //printf("VideoDevice::close_all 2\n");
303         if(r && capturing)
304         {
305                 capturing = 0;
306                 if(input_base)
307                 {
308                         input_base->close_all();
309                         delete input_base;
310                         input_base = 0;
311                 }
313                 if(keepalive)
314                 {
315                         keepalive->stop();
316                         delete keepalive;
317                 }
318         }
320 //printf("VideoDevice::close_all 3\n");
321         input_sources.remove_all_objects();
323 //printf("VideoDevice::close_all 4\n");
324         initialize();
326 //printf("VideoDevice::close_all 5\n");
327         return 0;
331 int VideoDevice::set_adevice(AudioDevice *adevice)
333         this->adevice = adevice;
334         return 0;
338 ArrayList<Channel*>* VideoDevice::get_inputs()
340         return &input_sources;
343 Channel* VideoDevice::new_input_source(char *device_name)
345         for(int i = 0; i < input_sources.total; i++)
346         {
347                 if(!strcmp(input_sources.values[i]->device_name, device_name))
348                         return input_sources.values[i];
349         }
350         Channel *item = new Channel;
351         strcpy(item->device_name, device_name);
352         input_sources.append(item);
353         return item;
356 int VideoDevice::get_failed()
358         if(keepalive)
359                 return keepalive->get_failed();
360         else
361                 return 0;
364 int VideoDevice::interrupt_crash()
366         if(input_base) return input_base->interrupt_crash();
367         return 0;
370 int VideoDevice::set_translation(int input_x, int input_y)
372         this->input_x = input_x;
373         this->input_y = input_y;
374         return 0;
377 int VideoDevice::set_field_order(int odd_field_first)
379         this->odd_field_first = odd_field_first;
380         return 0;
383 int VideoDevice::set_channel(Channel *channel)
385         if(channel)
386         {
387                 channel_lock->lock("VideoDevice::set_channel");
388                 this->channel->copy_settings(channel);
389                 channel_changed = 1;
390                 channel_lock->unlock();
392                 if(input_base) return input_base->set_channel(channel);
393                 if(output_base) return output_base->set_channel(channel);
394         }
397 void VideoDevice::set_quality(int quality)
399         this->quality = quality;
402 void VideoDevice::set_cpus(int cpus)
404         this->cpus = cpus;
407 int VideoDevice::set_picture(Picture *picture)
409         if(picture)
410         {
411                 picture_lock->lock("VideoDevice::set_picture");
412                 this->picture->copy_settings(picture);
413                 picture_changed = 1;
414                 picture_lock->unlock();
416                 if(input_base) return input_base->set_picture(picture);
417         }
420 int VideoDevice::update_translation()
422         float frame_in_capture_x1f, frame_in_capture_x2f, frame_in_capture_y1f, frame_in_capture_y2f;
423         float capture_in_frame_x1f, capture_in_frame_x2f, capture_in_frame_y1f, capture_in_frame_y2f;
424         int z_changed = 0;
426         if(frame_resized)
427         {
428                 input_x = new_input_x;
429                 input_y = new_input_y;
431                 if(in_config->driver == VIDEO4LINUX || in_config->driver == VIDEO4LINUX2)
432                 {
433                         if(input_z != new_input_z)
434                         {
435                                 input_z = new_input_z;
436                                 z_changed = 1;
438                                 capture_w = (int)((float)in_config->w * input_z + 0.5);
439                                 capture_h = (int)((float)in_config->h * input_z + 0.5);
441 // Need to align to multiple of 4
442                                 capture_w &= ~3;
443                                 capture_h &= ~3;
444                         }
446                         frame_in_capture_x1f = (float)input_x * input_z + capture_w / 2 - in_config->w / 2;
447                         frame_in_capture_x2f = (float)input_x * input_z  + capture_w / 2 + in_config->w / 2;
448                         frame_in_capture_y1f = (float)input_y * input_z  + capture_h / 2 - in_config->h / 2;
449                         frame_in_capture_y2f = (float)input_y * input_z  + capture_h / 2 + in_config->h / 2;
451                         capture_in_frame_x1f = 0;
452                         capture_in_frame_y1f = 0;
453                         capture_in_frame_x2f = in_config->w;
454                         capture_in_frame_y2f = in_config->h;
456                         if(frame_in_capture_x1f < 0) { capture_in_frame_x1f -= frame_in_capture_x1f; frame_in_capture_x1f = 0; }
457                         if(frame_in_capture_y1f < 0) { capture_in_frame_y1f -= frame_in_capture_y1f; frame_in_capture_y1f = 0; }
458                         if(frame_in_capture_x2f > capture_w) { capture_in_frame_x2f -= frame_in_capture_x2f - capture_w; frame_in_capture_x2f = capture_w; }
459                         if(frame_in_capture_y2f > capture_h) { capture_in_frame_y2f -= frame_in_capture_y2f - capture_h; frame_in_capture_y2f = capture_h; }
461                         frame_in_capture_x1 = (int)frame_in_capture_x1f;
462                         frame_in_capture_y1 = (int)frame_in_capture_y1f;
463                         frame_in_capture_x2 = (int)frame_in_capture_x2f;
464                         frame_in_capture_y2 = (int)frame_in_capture_y2f;
466                         capture_in_frame_x1 = (int)capture_in_frame_x1f;
467                         capture_in_frame_y1 = (int)capture_in_frame_y1f;
468                         capture_in_frame_x2 = (int)capture_in_frame_x2f;
469                         capture_in_frame_y2 = (int)capture_in_frame_y2f;
471                         frame_resized = 0;
472                 }
473         }
474         return 0;
477 int VideoDevice::set_latency_counter(int value)
479         latency_counter = value;
480         return 0;
483 int VideoDevice::read_buffer(VFrame *frame)
485         int result = 0;
486         if(!capturing) return 0;
488 //printf("VideoDevice::read_buffer %p %p\n", frame, input_base);
489         if(input_base)
490         {
491 // Reset the keepalive thread
492                 if(keepalive) keepalive->capturing = 1;
493                 result = input_base->read_buffer(frame);
494                 if(keepalive)
495                 {
496                         keepalive->capturing = 0;
497                         keepalive->reset_keepalive();
498                 }
499                 return result;
500         }
502         return 0;
506 // ================================= OUTPUT ==========================================
509 int VideoDevice::open_output(VideoOutConfig *config, 
510                                         float rate, 
511                                         int out_w, 
512                                         int out_h,
513                                         Canvas *output,
514                                         int single_frame)
516         w = 1;
517 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
518         *this->out_config = *config;
519 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
520         this->out_w = out_w;
521         this->out_h = out_h;
522         this->orate = rate;
523         this->single_frame = single_frame;
525 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
526         switch(out_config->driver)
527         {
528                 case PLAYBACK_BUZ:
529                         output_base = new VDeviceBUZ(this);
530                         break;
531                 case PLAYBACK_X11:
532                 case PLAYBACK_X11_XV:
533                         output_base = new VDeviceX11(this, output);
534                         break;
536                 case PLAYBACK_DV1394:
537                 case PLAYBACK_FIREWIRE:
538                         output_base = new VDevice1394(this);
539                         break;
540         }
541 //printf("VideoDevice::open_output 2 %d\n", out_config->driver);
543         if(output_base->open_output())
544         {
545                 delete output_base;
546                 output_base = 0;
547         }
548 //printf("VideoDevice::open_output 3 %d\n", out_config->driver);
550         if(output_base) 
551                 return 0;
552         else
553                 return 1;
558 int VideoDevice::start_playback()
560 // arm buffer before doing this
561         is_playing_back = 1;
562         interrupt = 0;
564         if(output_base) return output_base->start_playback();
565         return 1;
568 int VideoDevice::stop_playback()
570         if(output_base) output_base->stop_playback();
571         is_playing_back = 0;
572         interrupt = 0;
573         return 0;
576 void VideoDevice::goose_input()
578         if(input_base) input_base->goose_input();
581 void VideoDevice::new_output_buffers(VFrame **outputs, int colormodel)
583         for(int i = 0; i < MAX_CHANNELS; i++)
584                 outputs[i] = 0;
586         if(!output_base) return;
587         output_base->new_output_buffer(outputs, colormodel);
591 int VideoDevice::interrupt_playback()
593         interrupt = 1;
594         return 0;
597 int VideoDevice::write_buffer(VFrame **outputs, EDL *edl)
599 //printf("VideoDevice::write_buffer 1 %p\n", output_base);
600         if(output_base) return output_base->write_buffer(outputs, edl);
601         return 1;
604 int VideoDevice::output_visible()
606         if(output_base) return output_base->output_visible();
609 BC_Bitmap* VideoDevice::get_bitmap()
611         if(output_base) return output_base->get_bitmap();
615 int VideoDevice::set_cloexec_flag(int desc, int value)
617         int oldflags = fcntl(desc, F_GETFD, 0);
618         if(oldflags < 0) return oldflags;
619         if(value != 0) 
620                 oldflags |= FD_CLOEXEC;
621         else
622                 oldflags &= ~FD_CLOEXEC;
623         return fcntl(desc, F_SETFD, oldflags);