r1006: configure: Use libx264_pic instead of libx264 if available.
[cinelerra_cv/mob.git] / cinelerra / vdevicev4l2.C
blobbdc911178b6d3ea7e9223f3d7925033dbac75f10
1 #undef _FILE_OFFSET_BITS
2 #undef _LARGEFILE_SOURCE
3 #undef _LARGEFILE64_SOURCE
5 #include "assets.h"
6 #include "channel.h"
7 #include "chantables.h"
8 #include "clip.h"
9 #include "condition.h"
10 #include "file.h"
11 #include "mutex.h"
12 #include "picture.h"
13 #include "preferences.h"
14 #include "quicktime.h"
15 #include "recordconfig.h"
16 #include "vdevicev4l2.h"
17 #include "vframe.h"
18 #include "videodevice.h"
20 #ifdef HAVE_VIDEO4LINUX2
22 #include <errno.h>
23 #include <unistd.h>
24 #include <sys/ioctl.h>
25 #include <fcntl.h>
26 #include <sys/mman.h>
27 #include <string.h>
35 VDeviceV4L2Put::VDeviceV4L2Put(VDeviceV4L2Thread *thread)
36  : Thread(1, 0, 0)
38         this->thread = thread;
39         done = 0;
40         lock = new Mutex("VDeviceV4L2Put::lock");
41         more_buffers = new Condition(0, "VDeviceV4L2Put::more_buffers");
42         putbuffers = new int[0xff];
43         total = 0;
46 VDeviceV4L2Put::~VDeviceV4L2Put()
48         if(Thread::running())
49         {
50                 done = 1;
51                 more_buffers->unlock();
52                 Thread::cancel();
53                 Thread::join();
54         }
55         delete lock;
56         delete more_buffers;
57         delete [] putbuffers;
60 void VDeviceV4L2Put::run()
62         while(!done)
63         {
64                 more_buffers->lock("VDeviceV4L2Put::run");
65                 if(done) break;
66                 lock->lock("VDeviceV4L2Put::run");
67                 int buffer = -1;
68                 if(total)
69                 {
70                         buffer = putbuffers[0];
71                         for(int i = 0; i < total - 1; i++)
72                                 putbuffers[i] = putbuffers[i + 1];
73                         total--;
74                 }
75                 lock->unlock();
77                 if(buffer >= 0)
78                 {
79                         struct v4l2_buffer arg;
80                         bzero(&arg, sizeof(arg));
81                         arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
82                         arg.index = buffer;
83                         arg.memory = V4L2_MEMORY_MMAP;
85                         Thread::enable_cancel();
86                         thread->ioctl_lock->lock("VDeviceV4L2Put::run");
87 // This locks up if there's no signal.
88                         if(ioctl(thread->input_fd, VIDIOC_QBUF, &arg) < 0)
89                                 perror("VDeviceV4L2Put::run 1 VIDIOC_QBUF");
90                         thread->ioctl_lock->unlock();
91 // Delay to keep mutexes from getting stuck
92                         usleep(1000000 * 1001 / 60000);
93                         Thread::disable_cancel();
94                 }
95         }
98 void VDeviceV4L2Put::put_buffer(int number)
100         lock->lock("VDeviceV4L2Put::put_buffer");
101         putbuffers[total++] = number;
102         lock->unlock();
103         more_buffers->unlock();
116 VDeviceV4L2Thread::VDeviceV4L2Thread(VideoDevice *device, int color_model)
117  : Thread(1, 0, 0)
119         this->device = device;
120         this->color_model = color_model;
122         video_lock = new Condition(0, "VDeviceV4L2Thread::video_lock");
123         buffer_lock = new Mutex("VDeviceV4L2Thread::buffer_lock");
124         ioctl_lock = new Mutex("VDeviceV4L2Thread::ioctl_lock");
125         device_buffers = 0;
126         buffer_valid = 0;
127         current_inbuffer = 0;
128         current_outbuffer = 0;
129         total_buffers = 0;
130         first_frame = 1;
131         done = 0;
132         input_fd = 0;
133         total_valid = 0;
134         put_thread = 0;
137 VDeviceV4L2Thread::~VDeviceV4L2Thread()
139         if(Thread::running())
140         {
141                 done = 1;
142                 Thread::cancel();
143                 Thread::join();
144         }
146         if(put_thread) delete put_thread;
148         if(buffer_valid)
149         {
150                 delete [] buffer_valid;
151         }
153 // Buffers are not unmapped by close.
154         if(device_buffers)
155         {
156                 for(int i = 0; i < total_buffers; i++)
157                 {
158                         if(color_model == BC_COMPRESSED)
159                         {
160                                 if(device_buffers[i]->get_data()) 
161                                         munmap(device_buffers[i]->get_data(),
162                                                 device_buffers[i]->get_compressed_allocated());
163                         }
164                         else
165                         {
166                                 if(device_buffers[i]->get_data()) 
167                                         munmap(device_buffers[i]->get_data(),
168                                                 device_buffers[i]->get_data_size());
169                         }
170                         delete device_buffers[i];
171                 }
172                 delete [] device_buffers;
173         }
175         if(input_fd > 0) 
176         {
177                 int streamoff_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
178                 if(ioctl(input_fd, VIDIOC_STREAMOFF, &streamoff_arg) < 0)
179                         perror("VDeviceV4L2Thread::~VDeviceV4L2Thread VIDIOC_STREAMOFF");
180                 close(input_fd);
181         }
183         delete video_lock;
184         delete buffer_lock;
185         delete ioctl_lock;
188 void VDeviceV4L2Thread::start()
190         total_buffers = device->in_config->capture_length;
191         total_buffers = MAX(total_buffers, 2);
192         total_buffers = MIN(total_buffers, 0xff);
193         put_thread = new VDeviceV4L2Put(this);
194         put_thread->start();
195         Thread::start();
198 // Allocate user space buffers
199 void VDeviceV4L2Thread::allocate_buffers(int number)
201         if(number != total_buffers)
202         {
203                 if(buffer_valid) delete [] buffer_valid;
204                 if(device_buffers)
205                 {
206                         for(int i = 0; i < total_buffers; i++)
207                         {
208                                 delete device_buffers[i];
209                         }
210                         delete [] device_buffers;
211                 }
212         }
214         total_buffers = number;
215         buffer_valid = new int[total_buffers];
216         device_buffers = new VFrame*[total_buffers];
217         for(int i = 0; i < total_buffers; i++)
218         {
219                 device_buffers[i] = new VFrame;
220         }
221         bzero(buffer_valid, sizeof(int) * total_buffers);
224 void VDeviceV4L2Thread::run()
226 // Set up the device
227         int error = 0;
228         Thread::enable_cancel();
232         if((input_fd = open(device->in_config->v4l2jpeg_in_device, 
233                 O_RDWR)) < 0)
234         {
235                 perror("VDeviceV4L2Thread::run");
236                 error = 1;
237         }
239         if(!error)
240         {
241                 device->set_cloexec_flag(input_fd, 1);
244                 struct v4l2_capability cap;
245                 if(ioctl(input_fd, VIDIOC_QUERYCAP, &cap))
246                         perror("VDeviceV4L2Thread::run VIDIOC_QUERYCAP");
248 // printf("VDeviceV4L2Thread::run input_fd=%d driver=%s card=%s bus_info=%s version=%d\n",
249 // input_fd,
250 // cap.driver,
251 // cap.card,
252 // cap.bus_info,
253 // cap.version);
254 // printf("    %s%s%s%s%s%s%s%s%s%s%s%s\n", 
255 // (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ? "V4L2_CAP_VIDEO_CAPTURE " : "",
256 // (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) ? "V4L2_CAP_VIDEO_OUTPUT " : "",
257 // (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) ? "V4L2_CAP_VIDEO_OVERLAY " : "",
258 // (cap.capabilities & V4L2_CAP_VBI_CAPTURE) ? "V4L2_CAP_VBI_CAPTURE " : "",
259 // (cap.capabilities & V4L2_CAP_VBI_OUTPUT) ? "V4L2_CAP_VBI_OUTPUT " : "",
260 // (cap.capabilities & V4L2_CAP_RDS_CAPTURE) ? "V4L2_CAP_RDS_CAPTURE " : "",
261 // (cap.capabilities & V4L2_CAP_TUNER) ? "V4L2_CAP_TUNER " : "",
262 // (cap.capabilities & V4L2_CAP_AUDIO) ? "V4L2_CAP_AUDIO " : "",
263 // (cap.capabilities & V4L2_CAP_RADIO) ? "V4L2_CAP_RADIO " : "",
264 // (cap.capabilities & V4L2_CAP_READWRITE) ? "V4L2_CAP_READWRITE " : "",
265 // (cap.capabilities & V4L2_CAP_ASYNCIO) ? "V4L2_CAP_ASYNCIO " : "",
266 // (cap.capabilities & V4L2_CAP_STREAMING) ? "V4L2_CAP_STREAMING " : "");
269 // Set up frame rate
270                 struct v4l2_streamparm v4l2_parm;
271                 v4l2_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
272                 if(ioctl(input_fd, VIDIOC_G_PARM, &v4l2_parm) < 0)
273                         perror("VDeviceV4L2Thread::run VIDIOC_G_PARM");
274                 if(v4l2_parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
275                 {
276                         v4l2_parm.parm.capture.capturemode |= V4L2_CAP_TIMEPERFRAME;
279                         v4l2_parm.parm.capture.timeperframe.numerator = 1;
280                         v4l2_parm.parm.capture.timeperframe.denominator = 
281                                 (unsigned long)((float)1 / 
282                                 device->frame_rate * 
283                                 10000000);
284                         if(ioctl(input_fd, VIDIOC_S_PARM, &v4l2_parm) < 0)
285                                 perror("VDeviceV4L2Thread::run VIDIOC_S_PARM");
287                         if(ioctl(input_fd, VIDIOC_G_PARM, &v4l2_parm) < 0)
288                                 perror("VDeviceV4L2Thread::run VIDIOC_G_PARM");
289                 }
292 // Set up data format
293                 struct v4l2_format v4l2_params;
294                 v4l2_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
295                 if(ioctl(input_fd, VIDIOC_G_FMT, &v4l2_params) < 0)
296                         perror("VDeviceV4L2Thread::run VIDIOC_G_FMT");
297                 v4l2_params.fmt.pix.width = device->in_config->w;
298                 v4l2_params.fmt.pix.height = device->in_config->h;
300                 if(color_model == BC_COMPRESSED)
301                         v4l2_params.fmt.pix.pixelformat = 
302                                 V4L2_PIX_FMT_MJPEG;
303                 else
304                         v4l2_params.fmt.pix.pixelformat = 
305                                 VDeviceV4L2::cmodel_to_device(color_model);
308                 if(ioctl(input_fd, VIDIOC_S_FMT, &v4l2_params) < 0)
309                         perror("VDeviceV4L2Thread::run VIDIOC_S_FMT");
310                 if(ioctl(input_fd, VIDIOC_G_FMT, &v4l2_params) < 0)
311                         perror("VDeviceV4L2Thread::run VIDIOC_G_FMT");
313 // Set input
314                 Channel *device_channel = 0;
315                 if(device->channel->input >= 0 &&
316                         device->channel->input < device->get_inputs()->total)
317                 {
318                         device_channel = device->get_inputs()->values[
319                                 device->channel->input];
320                 }
322 // Try first input
323                 if(!device_channel)
324                 {
325                         if(device->get_inputs()->total)
326                         {
327                                 device_channel = device->get_inputs()->values[0];
328                                 printf("VDeviceV4L2Thread::run user channel not found.  Using %s\n",
329                                         device_channel->device_name);
330                         }
331                         else
332                         {
333                                 printf("VDeviceV4L2Thread::run channel \"%s\" not found.\n",
334                                         device->channel->title);
335                         }
336                 }
341 // Set picture controls.  This driver requires the values to be set once to default
342 // values and then again to different values before it takes up the values.
343 // Unfortunately VIDIOC_S_CTRL resets the audio to mono in 2.6.7.
344                 PictureConfig *picture = device->picture;
345                 for(int i = 0; i < picture->controls.total; i++)
346                 {
347                         struct v4l2_control ctrl_arg;
348                         struct v4l2_queryctrl arg;
349                         PictureItem *item = picture->controls.values[i];
350                         arg.id = item->device_id;
351                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
352                         {
353                                 ctrl_arg.id = item->device_id;
354                                 ctrl_arg.value = 0;
355                                 if(ioctl(input_fd, VIDIOC_S_CTRL, &ctrl_arg) < 0)
356                                         perror("VDeviceV4L2Thread::run VIDIOC_S_CTRL");
357                         }
358                         else
359                         {
360                                 printf("VDeviceV4L2Thread::run VIDIOC_S_CTRL 1 id %d failed\n",
361                                         item->device_id);
362                         }
363                 }
365                 for(int i = 0; i < picture->controls.total; i++)
366                 {
367                         struct v4l2_control ctrl_arg;
368                         struct v4l2_queryctrl arg;
369                         PictureItem *item = picture->controls.values[i];
370                         arg.id = item->device_id;
371                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
372                         {
373                                 ctrl_arg.id = item->device_id;
374                                 ctrl_arg.value = item->value;
375                                 if(ioctl(input_fd, VIDIOC_S_CTRL, &ctrl_arg) < 0)
376                                         perror("VDeviceV4L2Thread::run VIDIOC_S_CTRL");
377                         }
378                         else
379                         {
380                                 printf("VDeviceV4L2Thread::run VIDIOC_S_CTRL 2 id %d failed\n",
381                                         item->device_id);
382                         }
383                 }
386 // Translate input to API structures
387                 struct v4l2_tuner tuner;
388                 int input = 0;
390                 if(ioctl(input_fd, VIDIOC_G_TUNER, &tuner) < 0)
391                         perror("VDeviceV4L2Thread::run VIDIOC_G_INPUT");
393 // printf("VDeviceV4L2Thread::run audmode=%d rxsubchans=%d\n",
394 // tuner.audmode,
395 // tuner.rxsubchans);
396                 if(device_channel)
397                 {
398                         tuner.index = device_channel->device_index;
399                         input = device_channel->device_index;
400                 }
401                 else
402                 {
403                         tuner.index = 0;
404                         input = 0;
405                 }
407                 tuner.type = V4L2_TUNER_ANALOG_TV;
408                 tuner.audmode = V4L2_TUNER_MODE_STEREO;
409                 tuner.rxsubchans = V4L2_TUNER_SUB_STEREO;
411                 if(ioctl(input_fd, VIDIOC_S_INPUT, &input) < 0)
412                         perror("VDeviceV4L2Thread::run VIDIOC_S_INPUT");
421 // Set norm
422                 v4l2_std_id std_id;
423                 switch(device->channel->norm)
424                 {
425                         case NTSC: std_id = V4L2_STD_NTSC; break;
426                         case PAL: std_id = V4L2_STD_PAL; break;
427                         case SECAM: std_id = V4L2_STD_SECAM; break;
428                         default: std_id = V4L2_STD_NTSC_M; break;
429                 }
431                 if(ioctl(input_fd, VIDIOC_S_STD, &std_id))
432                         perror("VDeviceV4L2Thread::run VIDIOC_S_STD");
435                 if(cap.capabilities & V4L2_CAP_TUNER)
436                 {
437                         if(ioctl(input_fd, VIDIOC_S_TUNER, &tuner) < 0)
438                                 perror("VDeviceV4L2Thread::run VIDIOC_S_TUNER");
439 // Set frequency
440                         struct v4l2_frequency frequency;
441                         frequency.tuner = device->channel->tuner;
442                         frequency.type = V4L2_TUNER_ANALOG_TV;
443                         frequency.frequency = (int)(chanlists[
444                                 device->channel->freqtable].list[
445                                         device->channel->entry].freq * 0.016);
446 // printf("VDeviceV4L2Thread::run tuner=%d freq=%d norm=%d\n",
447 // device->channel->tuner,
448 // frequency.frequency,
449 // device->channel->norm);
450                         if(ioctl(input_fd, VIDIOC_S_FREQUENCY, &frequency) < 0)
451                                 perror("VDeviceV4L2Thread::run VIDIOC_S_FREQUENCY");
452                 }
456 // Set compression
457                 if(color_model == BC_COMPRESSED)
458                 {
459                         struct v4l2_jpegcompression jpeg_arg;
460                         if(ioctl(input_fd, VIDIOC_G_JPEGCOMP, &jpeg_arg) < 0)
461                                 perror("VDeviceV4L2Thread::run VIDIOC_G_JPEGCOMP");
462                         jpeg_arg.quality = device->quality / 2;
463                         if(ioctl(input_fd, VIDIOC_S_JPEGCOMP, &jpeg_arg) < 0)
464                                 perror("VDeviceV4L2Thread::run VIDIOC_S_JPEGCOMP");
465                 }
467 // Allocate buffers.  Errors here are fatal.
468                 Thread::disable_cancel();
469                 struct v4l2_requestbuffers requestbuffers;
471 printf("VDeviceV4L2Thread::run requested %d buffers\n", total_buffers);
472                 requestbuffers.count = total_buffers;
473                 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
474                 requestbuffers.memory = V4L2_MEMORY_MMAP;
475                 if(ioctl(input_fd, VIDIOC_REQBUFS, &requestbuffers) < 0)
476                 {
477                         perror("VDeviceV4L2Thread::run VIDIOC_REQBUFS");
478                         error = 1;
479                 }
480                 else
481                 {
482 // The requestbuffers.count changes in the 2.6.5 version of the API
483                         allocate_buffers(requestbuffers.count);
485 printf("VDeviceV4L2Thread::run got %d buffers\n", total_buffers);
486                         for(int i = 0; i < total_buffers; i++)
487                         {
488                                 struct v4l2_buffer buffer;
489                                 buffer.type = requestbuffers.type;
490                                 buffer.index = i;
491                                 if(ioctl(input_fd, VIDIOC_QUERYBUF, &buffer) < 0)
492                                 {
493                                         perror("VDeviceV4L2Thread::run VIDIOC_QUERYBUF");
494                                         error = 1;
495                                         break;
496                                 }
498                                 unsigned char *data = (unsigned char*)mmap(NULL,
499                                         buffer.length,
500                                         PROT_READ | PROT_WRITE,
501                                         MAP_SHARED,
502                                         input_fd,
503                                         buffer.m.offset);
504                                 if(data == MAP_FAILED)
505                                 {
506                                         perror("VDeviceV4L2Thread::run mmap");
507                                         error = 1;
508                                         break;
509                                 }
511                                 VFrame *frame = device_buffers[i];
512                                 if(color_model == BC_COMPRESSED)
513                                 {
514                                         frame->set_compressed_memory(data,
515                                                 0,
516                                                 buffer.length);
517                                 }
518                                 else
519                                 {
520                                         int y_offset = 0;
521                                         int u_offset = 0;
522                                         int v_offset = 0;
524                                         switch(color_model)
525                                         {
526                                                 case BC_YUV422P:
527                                                         u_offset = device->in_config->w * device->in_config->h;
528                                                         v_offset = device->in_config->w * device->in_config->h + device->in_config->w * device->in_config->h / 2;
529                                                         break;
530                                                 case BC_YUV420P:
531                                                 case BC_YUV411P:
532 // In 2.6.7, the v and u are inverted for 420 but not 422
533                                                         v_offset = device->in_config->w * device->in_config->h;
534                                                         u_offset = device->in_config->w * device->in_config->h + device->in_config->w * device->in_config->h / 4;
535                                                         break;
536                                         }
538 //printf("VDeviceV4L2Thread::run color_model=%d\n", color_model);
539                                         frame->reallocate(data,
540                                                 y_offset,
541                                                 u_offset,
542                                                 v_offset,
543                                                 device->in_config->w,
544                                                 device->in_config->h,
545                                                 color_model,
546                                                 VFrame::calculate_bytes_per_pixel(color_model) *
547                                                         device->in_config->w);
548                                 }
549                         }
550                 }
551                 Thread::enable_cancel();
552         }
556 // Start capturing
557         if(!error)
558         {
559                 for(int i = 0; i < total_buffers; i++)
560                 {
561                         struct v4l2_buffer buffer;
562                         buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
563                         buffer.memory = V4L2_MEMORY_MMAP;
564                         buffer.index = i;
565                         if(ioctl(input_fd, VIDIOC_QBUF, &buffer) < 0)
566                         {
567                                 perror("VDeviceV4L2Thread::run VIDIOC_QBUF");
568                                 break;
569                         }
570                 }
573                 int streamon_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
574                 if(ioctl(input_fd, VIDIOC_STREAMON, &streamon_arg) < 0)
575                         perror("VDeviceV4L2Thread::run VIDIOC_STREAMON");
576         }
578         Thread::disable_cancel();
581 // Read buffers continuously
582         first_frame = 0;
583         while(!done && !error)
584         {
585                 struct v4l2_buffer buffer;
586                 bzero(&buffer, sizeof(buffer));
587                 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
588                 buffer.memory = V4L2_MEMORY_MMAP;
590 // The driver returns the first buffer not queued, so only one buffer
591 // can be unqueued at a time.
592                 Thread::enable_cancel();
593                 ioctl_lock->lock("VDeviceV4L2Thread::run");
594                 int result = ioctl(input_fd, VIDIOC_DQBUF, &buffer);
595                 ioctl_lock->unlock();
596 // Delay so the mutexes don't get stuck
597                 usleep(1000000 * 1001 / 60000);
598                 Thread::disable_cancel();
601                 if(result < 0)
602                 {
603                         perror("VDeviceV4L2Thread::run VIDIOC_DQBUF");
604                         Thread::enable_cancel();
605                         usleep(100000);
606                         Thread::disable_cancel();
607                 }
608                 else
609                 {
610                         buffer_lock->lock("VDeviceV4L2Thread::run");
612 // Set output frame as valid and set data size
613                         current_inbuffer = buffer.index;
614                         if(color_model == BC_COMPRESSED)
615                         {
616                                 device_buffers[current_inbuffer]->set_compressed_size(
617                                         buffer.bytesused);
618                         }
620                         if(!buffer_valid[current_inbuffer])
621                         {
622 // Increase valid total only if current is invalid
623                                 buffer_valid[current_inbuffer] = 1;
624                                 total_valid++;
625                                 buffer_lock->unlock();
626                                 video_lock->unlock();
627                         }
628                         else
629                         {
630 // Driver won't block on the next QBUF call because we're not requeueing the buffer.
631                                 buffer_lock->unlock();
632                                 video_lock->unlock();
633                                 usleep(33000);
634                         }
635                 }
636 //printf("VDeviceV4L2::run 100 %lld\n", timer.get_difference());
637         }
640 VFrame* VDeviceV4L2Thread::get_buffer(int *timed_out)
642         VFrame *result = 0;
643         *timed_out = 0;
645 // Acquire buffer table
646         buffer_lock->lock("VDeviceV4L2Thread::get_buffer 1");
649 // Test for buffer availability
650         while(total_valid < 2 && !*timed_out && !first_frame)
651         {
652                 buffer_lock->unlock();
653                 *timed_out = video_lock->timed_lock(BUFFER_TIMEOUT, 
654                         "VDeviceV4L2Thread::read_frame 2");
655                 buffer_lock->lock("VDeviceV4L2Thread::get_buffer 3");
656         }
658 // Copy frame
659         if(total_valid >= 2)
660         {
661                 result = device_buffers[current_outbuffer];
662         }
664         buffer_lock->unlock();
666         return result;
669 void VDeviceV4L2Thread::put_buffer()
671         buffer_lock->lock("VDeviceV4L2Thread::put_buffer");
672         buffer_valid[current_outbuffer] = 0;
674 // Release buffer for capturing.
675         put_thread->put_buffer(current_outbuffer);
677         current_outbuffer++;
678         total_valid--;
679         if(current_outbuffer >= total_buffers)
680                 current_outbuffer = 0;
681         buffer_lock->unlock();
701 VDeviceV4L2::VDeviceV4L2(VideoDevice *device)
702  : VDeviceBase(device)
704         initialize();
707 VDeviceV4L2::~VDeviceV4L2()
709         close_all();
712 int VDeviceV4L2::close_all()
714         if(thread) delete thread;
715         thread = 0;
716         return 0;
720 int VDeviceV4L2::initialize()
722         thread = 0;
723         return 0;
728 int VDeviceV4L2::open_input()
730         int result = get_sources(device,
731                 device->in_config->v4l2_in_device);
732         device->channel->use_frequency = 1;
733         device->channel->use_fine = 1;
734         return result;
737 int VDeviceV4L2::get_sources(VideoDevice *device,
738         char *path)
740         int input_fd = -1;
743         device->channel->use_norm = 1;
744         device->channel->use_input = 1;
745         if(device->in_config->driver != VIDEO4LINUX2JPEG) 
746                 device->channel->has_scanning = 1;
747         else
748                 device->channel->has_scanning = 0;
750         if((input_fd = open(path, O_RDWR)) < 0)
751         {
752                 printf("VDeviceV4L2::open_input %s: %s\n", path, strerror(errno));
753                 return 1;
754         }
755         else
756         {
757 // Get the inputs
758                 int i = 0;
759                 int done = 0;
760                 char *new_source;
762                 while(!done && i < 20)
763                 {
764                         struct v4l2_input arg;
765                         bzero(&arg, sizeof(arg));
766                         arg.index = i;
767                         
768                         if(ioctl(input_fd, VIDIOC_ENUMINPUT, &arg) < 0)
769                         {
770 // Finished
771                                 done = 1;
772                         }
773                         else
774                         {
775                                 Channel *channel = device->new_input_source((char*)arg.name);
776                                 channel->device_index = i;
777                                 channel->tuner = arg.tuner;
778                         }
779                         i++;
780                 }
782 // Get the picture controls
783                 for(i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++)
784                 {
785                         struct v4l2_queryctrl arg;
786                         bzero(&arg, sizeof(arg));
787                         arg.id = i;
788 // This returns errors for unsupported controls which is what we want.
789                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
790                         {
791 // Test if control exists already
792                                 if(!device->picture->get_item((const char*)arg.name, arg.id))
793                                 {
794 // Add control
795                                         PictureItem *item = device->picture->new_item((const char*)arg.name);
796                                         item->device_id = arg.id;
797                                         item->min = arg.minimum;
798                                         item->max = arg.maximum;
799                                         item->step = arg.step;
800                                         item->default_ = arg.default_value;
801                                         item->type = arg.type;
802                                         item->value = arg.default_value;
803                                 }
804                         }
805                 }
807 // Load defaults for picture controls
808                 device->picture->load_defaults();
810                 close(input_fd);
811         }
812         return 0;
815 int VDeviceV4L2::cmodel_to_device(int color_model)
817         switch(color_model)
818         {
819                 case BC_YUV422:
820                         return V4L2_PIX_FMT_YUYV;
821                         break;
822                 case BC_YUV411P:
823                         return V4L2_PIX_FMT_Y41P;
824                         break;
825                 case BC_YUV420P:
826                         return V4L2_PIX_FMT_YVU420;
827                         break;
828                 case BC_YUV422P:
829                         return V4L2_PIX_FMT_YUV422P;
830                         break;
831                 case BC_RGB888:
832                         return V4L2_PIX_FMT_RGB24;
833                         break;
834         }
835         return 0;
838 int VDeviceV4L2::get_best_colormodel(Asset *asset)
840         int result = BC_RGB888;
841         result = File::get_best_colormodel(asset, device->in_config->driver);
842         return result;
845 int VDeviceV4L2::has_signal()
847         if(thread)
848         {
849                 struct v4l2_tuner tuner;
850                 if(ioctl(thread->input_fd, VIDIOC_G_TUNER, &tuner) < 0)
851                         perror("VDeviceV4L2::has_signal VIDIOC_S_TUNER");
852                 return tuner.signal;
853         }
854         return 0;
857 int VDeviceV4L2::read_buffer(VFrame *frame)
859         int result = 0;
861         if((device->channel_changed || device->picture_changed) && thread)
862         {
863                 delete thread;
864                 thread = 0;
865         }
867         if(!thread)
868         {
869                 device->channel_changed = 0;
870                 device->picture_changed = 0;
871                 thread = new VDeviceV4L2Thread(device, frame->get_color_model());
872                 thread->start();
873         }
876 // Get buffer from thread
877         int timed_out;
878         VFrame *buffer = thread->get_buffer(&timed_out);
879         if(buffer)
880         {
881                 frame->copy_from(buffer);
882                 thread->put_buffer();
883         }
884         else
885         {
886 // Driver in 2.6.4 needs to be restarted when it loses sync.
887                 if(timed_out)
888                 {
889                         delete thread;
890                         thread = 0;
891                 }
892                 result = 1;
893         }
896         return result;
899 #endif