r665: Merged the official release 2.0.
[cinelerra_cv.git] / cinelerra / vdevicev4l2.C
blob1c32a30553f06c61701c47252715ae62de8e7041
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 "picture.h"
12 #include "preferences.h"
13 #include "quicktime.h"
14 #include "recordconfig.h"
15 #include "vdevicev4l2.h"
16 #include "vframe.h"
17 #include "videodevice.h"
19 #ifdef HAVE_VIDEO4LINUX2
21 #include <unistd.h>
22 #include <sys/ioctl.h>
23 #include <fcntl.h>
24 #include <sys/mman.h>
25 #include <string.h>
33 VDeviceV4L2Put::VDeviceV4L2Put(VDeviceV4L2Thread *thread)
34  : Thread(1, 0, 0)
36         this->thread = thread;
37         done = 0;
38         lock = new Mutex("VDeviceV4L2Put::lock");
39         more_buffers = new Condition(0, "VDeviceV4L2Put::more_buffers");
40         putbuffers = new int[0xff];
41         total = 0;
44 VDeviceV4L2Put::~VDeviceV4L2Put()
46         if(Thread::running())
47         {
48                 done = 1;
49                 more_buffers->unlock();
50                 Thread::cancel();
51                 Thread::join();
52         }
53         delete lock;
54         delete more_buffers;
55         delete [] putbuffers;
58 void VDeviceV4L2Put::run()
60         while(!done)
61         {
62                 more_buffers->lock("VDeviceV4L2Put::run");
63                 if(done) break;
64                 lock->lock("VDeviceV4L2Put::run");
65                 int buffer = -1;
66                 if(total)
67                 {
68                         buffer = putbuffers[0];
69                         for(int i = 0; i < total - 1; i++)
70                                 putbuffers[i] = putbuffers[i + 1];
71                         total--;
72                 }
73                 lock->unlock();
75                 if(buffer >= 0)
76                 {
77                         struct v4l2_buffer arg;
78                         bzero(&arg, sizeof(arg));
79                         arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
80                         arg.index = buffer;
81                         arg.memory = V4L2_MEMORY_MMAP;
83                         Thread::enable_cancel();
84                         thread->ioctl_lock->lock("VDeviceV4L2Put::run");
85 // This locks up if there's no signal.
86                         if(ioctl(thread->input_fd, VIDIOC_QBUF, &arg) < 0)
87                                 perror("VDeviceV4L2Put::run 1 VIDIOC_QBUF");
88                         thread->ioctl_lock->unlock();
89 // Delay to keep mutexes from getting stuck
90                         usleep(1000000 * 1001 / 60000);
91                         Thread::disable_cancel();
92                 }
93         }
96 void VDeviceV4L2Put::put_buffer(int number)
98         lock->lock("VDeviceV4L2Put::put_buffer");
99         putbuffers[total++] = number;
100         lock->unlock();
101         more_buffers->unlock();
114 VDeviceV4L2Thread::VDeviceV4L2Thread(VideoDevice *device, int color_model)
115  : Thread(1, 0, 0)
117         this->device = device;
118         this->color_model = color_model;
120         video_lock = new Condition(0, "VDeviceV4L2Thread::video_lock");
121         buffer_lock = new Mutex("VDeviceV4L2Thread::buffer_lock");
122         ioctl_lock = new Mutex("VDeviceV4L2Thread::ioctl_lock");
123         device_buffers = 0;
124         buffer_valid = 0;
125         current_inbuffer = 0;
126         current_outbuffer = 0;
127         total_buffers = 0;
128         first_frame = 1;
129         done = 0;
130         input_fd = 0;
131         total_valid = 0;
132         put_thread = 0;
135 VDeviceV4L2Thread::~VDeviceV4L2Thread()
137         if(Thread::running())
138         {
139                 done = 1;
140                 Thread::cancel();
141                 Thread::join();
142         }
144         if(put_thread) delete put_thread;
146         if(buffer_valid)
147         {
148                 delete [] buffer_valid;
149         }
151 // Buffers are not unmapped by close.
152         if(device_buffers)
153         {
154                 for(int i = 0; i < total_buffers; i++)
155                 {
156                         if(color_model == BC_COMPRESSED)
157                         {
158                                 if(device_buffers[i]->get_data()) 
159                                         munmap(device_buffers[i]->get_data(),
160                                                 device_buffers[i]->get_compressed_allocated());
161                         }
162                         else
163                         {
164                                 if(device_buffers[i]->get_data()) 
165                                         munmap(device_buffers[i]->get_data(),
166                                                 device_buffers[i]->get_data_size());
167                         }
168                         delete device_buffers[i];
169                 }
170                 delete [] device_buffers;
171         }
173         if(input_fd > 0) 
174         {
175                 int streamoff_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
176                 if(ioctl(input_fd, VIDIOC_STREAMOFF, &streamoff_arg) < 0)
177                         perror("VDeviceV4L2Thread::~VDeviceV4L2Thread VIDIOC_STREAMOFF");
178                 close(input_fd);
179         }
181         delete video_lock;
182         delete buffer_lock;
183         delete ioctl_lock;
186 void VDeviceV4L2Thread::start()
188         total_buffers = device->in_config->capture_length;
189         total_buffers = MAX(total_buffers, 2);
190         total_buffers = MIN(total_buffers, 0xff);
191         put_thread = new VDeviceV4L2Put(this);
192         put_thread->start();
193         Thread::start();
196 // Allocate user space buffers
197 void VDeviceV4L2Thread::allocate_buffers(int number)
199         if(number != total_buffers)
200         {
201                 if(buffer_valid) delete [] buffer_valid;
202                 if(device_buffers)
203                 {
204                         for(int i = 0; i < total_buffers; i++)
205                         {
206                                 delete device_buffers[i];
207                         }
208                         delete [] device_buffers;
209                 }
210         }
212         total_buffers = number;
213         buffer_valid = new int[total_buffers];
214         device_buffers = new VFrame*[total_buffers];
215         for(int i = 0; i < total_buffers; i++)
216         {
217                 device_buffers[i] = new VFrame;
218         }
219         bzero(buffer_valid, sizeof(int) * total_buffers);
222 void VDeviceV4L2Thread::run()
224 // Set up the device
225         int error = 0;
226         Thread::enable_cancel();
230         if((input_fd = open(device->in_config->v4l2jpeg_in_device, 
231                 O_RDWR)) < 0)
232         {
233                 perror("VDeviceV4L2Thread::run");
234                 error = 1;
235         }
237         if(!error)
238         {
239                 device->set_cloexec_flag(input_fd, 1);
242                 struct v4l2_capability cap;
243                 if(ioctl(input_fd, VIDIOC_QUERYCAP, &cap))
244                         perror("VDeviceV4L2Thread::run VIDIOC_QUERYCAP");
246 // printf("VDeviceV4L2Thread::run input_fd=%d driver=%s card=%s bus_info=%s version=%d\n",
247 // input_fd,
248 // cap.driver,
249 // cap.card,
250 // cap.bus_info,
251 // cap.version);
252 // printf("    %s%s%s%s%s%s%s%s%s%s%s%s\n", 
253 // (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ? "V4L2_CAP_VIDEO_CAPTURE " : "",
254 // (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) ? "V4L2_CAP_VIDEO_OUTPUT " : "",
255 // (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) ? "V4L2_CAP_VIDEO_OVERLAY " : "",
256 // (cap.capabilities & V4L2_CAP_VBI_CAPTURE) ? "V4L2_CAP_VBI_CAPTURE " : "",
257 // (cap.capabilities & V4L2_CAP_VBI_OUTPUT) ? "V4L2_CAP_VBI_OUTPUT " : "",
258 // (cap.capabilities & V4L2_CAP_RDS_CAPTURE) ? "V4L2_CAP_RDS_CAPTURE " : "",
259 // (cap.capabilities & V4L2_CAP_TUNER) ? "V4L2_CAP_TUNER " : "",
260 // (cap.capabilities & V4L2_CAP_AUDIO) ? "V4L2_CAP_AUDIO " : "",
261 // (cap.capabilities & V4L2_CAP_RADIO) ? "V4L2_CAP_RADIO " : "",
262 // (cap.capabilities & V4L2_CAP_READWRITE) ? "V4L2_CAP_READWRITE " : "",
263 // (cap.capabilities & V4L2_CAP_ASYNCIO) ? "V4L2_CAP_ASYNCIO " : "",
264 // (cap.capabilities & V4L2_CAP_STREAMING) ? "V4L2_CAP_STREAMING " : "");
267 // Set up frame rate
268                 struct v4l2_streamparm v4l2_parm;
269                 v4l2_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
270                 if(ioctl(input_fd, VIDIOC_G_PARM, &v4l2_parm) < 0)
271                         perror("VDeviceV4L2Thread::run VIDIOC_G_PARM");
272                 if(v4l2_parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
273                 {
274                         v4l2_parm.parm.capture.capturemode |= V4L2_CAP_TIMEPERFRAME;
277                         v4l2_parm.parm.capture.timeperframe.numerator = 1;
278                         v4l2_parm.parm.capture.timeperframe.denominator = 
279                                 (unsigned long)((float)1 / 
280                                 device->frame_rate * 
281                                 10000000);
282                         if(ioctl(input_fd, VIDIOC_S_PARM, &v4l2_parm) < 0)
283                                 perror("VDeviceV4L2Thread::run VIDIOC_S_PARM");
285                         if(ioctl(input_fd, VIDIOC_G_PARM, &v4l2_parm) < 0)
286                                 perror("VDeviceV4L2Thread::run VIDIOC_G_PARM");
287                 }
290 // Set up data format
291                 struct v4l2_format v4l2_params;
292                 v4l2_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
293                 if(ioctl(input_fd, VIDIOC_G_FMT, &v4l2_params) < 0)
294                         perror("VDeviceV4L2Thread::run VIDIOC_G_FMT");
295                 v4l2_params.fmt.pix.width = device->in_config->w;
296                 v4l2_params.fmt.pix.height = device->in_config->h;
298                 if(color_model == BC_COMPRESSED)
299                         v4l2_params.fmt.pix.pixelformat = 
300                                 V4L2_PIX_FMT_MJPEG;
301                 else
302                         v4l2_params.fmt.pix.pixelformat = 
303                                 VDeviceV4L2::cmodel_to_device(color_model);
306                 if(ioctl(input_fd, VIDIOC_S_FMT, &v4l2_params) < 0)
307                         perror("VDeviceV4L2Thread::run VIDIOC_S_FMT");
308                 if(ioctl(input_fd, VIDIOC_G_FMT, &v4l2_params) < 0)
309                         perror("VDeviceV4L2Thread::run VIDIOC_G_FMT");
311 // Set input
312                 Channel *device_channel = 0;
313                 if(device->channel->input >= 0 &&
314                         device->channel->input < device->get_inputs()->total)
315                 {
316                         device_channel = device->get_inputs()->values[
317                                 device->channel->input];
318                 }
320 // Try first input
321                 if(!device_channel)
322                 {
323                         if(device->get_inputs()->total)
324                         {
325                                 device_channel = device->get_inputs()->values[0];
326                                 printf("VDeviceV4L2Thread::run user channel not found.  Using %s\n",
327                                         device_channel->device_name);
328                         }
329                         else
330                         {
331                                 printf("VDeviceV4L2Thread::run channel \"%s\" not found.\n",
332                                         device->channel->title);
333                         }
334                 }
339 // Set picture controls.  This driver requires the values to be set once to default
340 // values and then again to different values before it takes up the values.
341 // Unfortunately VIDIOC_S_CTRL resets the audio to mono in 2.6.7.
342                 PictureConfig *picture = device->picture;
343                 for(int i = 0; i < picture->controls.total; i++)
344                 {
345                         struct v4l2_control ctrl_arg;
346                         struct v4l2_queryctrl arg;
347                         PictureItem *item = picture->controls.values[i];
348                         arg.id = item->device_id;
349                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
350                         {
351                                 ctrl_arg.id = item->device_id;
352                                 ctrl_arg.value = 0;
353                                 if(ioctl(input_fd, VIDIOC_S_CTRL, &ctrl_arg) < 0)
354                                         perror("VDeviceV4L2Thread::run VIDIOC_S_CTRL");
355                         }
356                         else
357                         {
358                                 printf("VDeviceV4L2Thread::run VIDIOC_S_CTRL 1 id %d failed\n",
359                                         item->device_id);
360                         }
361                 }
363                 for(int i = 0; i < picture->controls.total; i++)
364                 {
365                         struct v4l2_control ctrl_arg;
366                         struct v4l2_queryctrl arg;
367                         PictureItem *item = picture->controls.values[i];
368                         arg.id = item->device_id;
369                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
370                         {
371                                 ctrl_arg.id = item->device_id;
372                                 ctrl_arg.value = item->value;
373                                 if(ioctl(input_fd, VIDIOC_S_CTRL, &ctrl_arg) < 0)
374                                         perror("VDeviceV4L2Thread::run VIDIOC_S_CTRL");
375                         }
376                         else
377                         {
378                                 printf("VDeviceV4L2Thread::run VIDIOC_S_CTRL 2 id %d failed\n",
379                                         item->device_id);
380                         }
381                 }
384 // Translate input to API structures
385                 struct v4l2_tuner tuner;
386                 int input = 0;
388                 if(ioctl(input_fd, VIDIOC_G_TUNER, &tuner) < 0)
389                         perror("VDeviceV4L2Thread::run VIDIOC_G_INPUT");
391 // printf("VDeviceV4L2Thread::run audmode=%d rxsubchans=%d\n",
392 // tuner.audmode,
393 // tuner.rxsubchans);
394                 if(device_channel)
395                 {
396                         tuner.index = device_channel->device_index;
397                         input = device_channel->device_index;
398                 }
399                 else
400                 {
401                         tuner.index = 0;
402                         input = 0;
403                 }
405                 tuner.type = V4L2_TUNER_ANALOG_TV;
406                 tuner.audmode = V4L2_TUNER_MODE_STEREO;
407                 tuner.rxsubchans = V4L2_TUNER_SUB_STEREO;
409                 if(ioctl(input_fd, VIDIOC_S_INPUT, &input) < 0)
410                         perror("VDeviceV4L2Thread::run VIDIOC_S_INPUT");
419 // Set norm
420                 v4l2_std_id std_id;
421                 switch(device->channel->norm)
422                 {
423                         case NTSC: std_id = V4L2_STD_NTSC; break;
424                         case PAL: std_id = V4L2_STD_PAL; break;
425                         case SECAM: std_id = V4L2_STD_SECAM; break;
426                         default: std_id = V4L2_STD_NTSC_M; break;
427                 }
429                 if(ioctl(input_fd, VIDIOC_S_STD, &std_id))
430                         perror("VDeviceV4L2Thread::run VIDIOC_S_STD");
433                 if(cap.capabilities & V4L2_CAP_TUNER)
434                 {
435                         if(ioctl(input_fd, VIDIOC_S_TUNER, &tuner) < 0)
436                                 perror("VDeviceV4L2Thread::run VIDIOC_S_TUNER");
437 // Set frequency
438                         struct v4l2_frequency frequency;
439                         frequency.tuner = device->channel->tuner;
440                         frequency.type = V4L2_TUNER_ANALOG_TV;
441                         frequency.frequency = (int)(chanlists[
442                                 device->channel->freqtable].list[
443                                         device->channel->entry].freq * 0.016);
444 // printf("VDeviceV4L2Thread::run tuner=%d freq=%d norm=%d\n",
445 // device->channel->tuner,
446 // frequency.frequency,
447 // device->channel->norm);
448                         if(ioctl(input_fd, VIDIOC_S_FREQUENCY, &frequency) < 0)
449                                 perror("VDeviceV4L2Thread::run VIDIOC_S_FREQUENCY");
450                 }
454 // Set compression
455                 if(color_model == BC_COMPRESSED)
456                 {
457                         struct v4l2_jpegcompression jpeg_arg;
458                         if(ioctl(input_fd, VIDIOC_G_JPEGCOMP, &jpeg_arg) < 0)
459                                 perror("VDeviceV4L2Thread::run VIDIOC_G_JPEGCOMP");
460                         jpeg_arg.quality = device->quality / 2;
461                         if(ioctl(input_fd, VIDIOC_S_JPEGCOMP, &jpeg_arg) < 0)
462                                 perror("VDeviceV4L2Thread::run VIDIOC_S_JPEGCOMP");
463                 }
465 // Allocate buffers.  Errors here are fatal.
466                 Thread::disable_cancel();
467                 struct v4l2_requestbuffers requestbuffers;
469 printf("VDeviceV4L2Thread::run requested %d buffers\n", total_buffers);
470                 requestbuffers.count = total_buffers;
471                 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
472                 requestbuffers.memory = V4L2_MEMORY_MMAP;
473                 if(ioctl(input_fd, VIDIOC_REQBUFS, &requestbuffers) < 0)
474                 {
475                         perror("VDeviceV4L2Thread::run VIDIOC_REQBUFS");
476                         error = 1;
477                 }
478                 else
479                 {
480 // The requestbuffers.count changes in the 2.6.5 version of the API
481                         allocate_buffers(requestbuffers.count);
482 printf("VDeviceV4L2Thread::run got %d buffers\n", total_buffers);
483                         for(int i = 0; i < total_buffers; i++)
484                         {
485                                 struct v4l2_buffer buffer;
486                                 buffer.type = requestbuffers.type;
487                                 buffer.index = i;
488                                 if(ioctl(input_fd, VIDIOC_QUERYBUF, &buffer) < 0)
489                                 {
490                                         perror("VDeviceV4L2Thread::run VIDIOC_QUERYBUF");
491                                         error = 1;
492                                         break;
493                                 }
495                                 unsigned char *data = (unsigned char*)mmap(NULL,
496                                         buffer.length,
497                                         PROT_READ | PROT_WRITE,
498                                         MAP_SHARED,
499                                         input_fd,
500                                         buffer.m.offset);
501                                 if(data == MAP_FAILED)
502                                 {
503                                         perror("VDeviceV4L2Thread::run mmap");
504                                         error = 1;
505                                         break;
506                                 }
508                                 VFrame *frame = device_buffers[i];
509                                 if(color_model == BC_COMPRESSED)
510                                 {
511                                         frame->set_compressed_memory(data,
512                                                 0,
513                                                 buffer.length);
514                                 }
515                                 else
516                                 {
517                                         int y_offset = 0;
518                                         int u_offset = 0;
519                                         int v_offset = 0;
521                                         switch(color_model)
522                                         {
523                                                 case BC_YUV422P:
524                                                         u_offset = device->in_config->w * device->in_config->h;
525                                                         v_offset = device->in_config->w * device->in_config->h + device->in_config->w * device->in_config->h / 2;
526                                                         break;
527                                                 case BC_YUV420P:
528                                                 case BC_YUV411P:
529 // In 2.6.7, the v and u are inverted for 420 but not 422
530                                                         v_offset = device->in_config->w * device->in_config->h;
531                                                         u_offset = device->in_config->w * device->in_config->h + device->in_config->w * device->in_config->h / 4;
532                                                         break;
533                                         }
535                                         frame->reallocate(data,
536                                                 y_offset,
537                                                 u_offset,
538                                                 v_offset,
539                                                 device->in_config->w,
540                                                 device->in_config->h,
541                                                 color_model,
542                                                 VFrame::calculate_bytes_per_pixel(color_model) *
543                                                         device->in_config->w);
544                                 }
545                         }
546                 }
547                 Thread::enable_cancel();
548         }
552 // Start capturing
553         if(!error)
554         {
555                 for(int i = 0; i < total_buffers; i++)
556                 {
557                         struct v4l2_buffer buffer;
558                         buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
559                         buffer.index = i;
560                         if(ioctl(input_fd, VIDIOC_QBUF, &buffer) < 0)
561                         {
562                                 perror("VDeviceV4L2Thread::run VIDIOC_QBUF");
563                                 break;
564                         }
565                 }
568                 int streamon_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
569                 if(ioctl(input_fd, VIDIOC_STREAMON, &streamon_arg) < 0)
570                         perror("VDeviceV4L2Thread::run VIDIOC_STREAMON");
571         }
573         Thread::disable_cancel();
576 // Read buffers continuously
577         first_frame = 0;
578         while(!done && !error)
579         {
580                 struct v4l2_buffer buffer;
581                 bzero(&buffer, sizeof(buffer));
582                 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
583                 buffer.memory = V4L2_MEMORY_MMAP;
585 // The driver returns the first buffer not queued, so only one buffer
586 // can be unqueued at a time.
587                 Thread::enable_cancel();
588                 ioctl_lock->lock("VDeviceV4L2Thread::run");
589                 int result = ioctl(input_fd, VIDIOC_DQBUF, &buffer);
590                 ioctl_lock->unlock();
591 // Delay so the mutexes don't get stuck
592                 usleep(1000000 * 1001 / 60000);
593                 Thread::disable_cancel();
596                 if(result < 0)
597                 {
598                         perror("VDeviceV4L2Thread::run VIDIOC_DQBUF");
599                         Thread::enable_cancel();
600                         usleep(100000);
601                         Thread::disable_cancel();
602                 }
603                 else
604                 {
605                         buffer_lock->lock("VDeviceV4L2Thread::run");
607 // Set output frame as valid and set data size
608                         current_inbuffer = buffer.index;
609                         if(color_model == BC_COMPRESSED)
610                         {
611                                 device_buffers[current_inbuffer]->set_compressed_size(
612                                         buffer.bytesused);
613                         }
615                         if(!buffer_valid[current_inbuffer])
616                         {
617 // Increase valid total only if current is invalid
618                                 buffer_valid[current_inbuffer] = 1;
619                                 total_valid++;
620                                 buffer_lock->unlock();
621                                 video_lock->unlock();
622                         }
623                         else
624                         {
625 // Driver won't block on the next QBUF call because we're not requeueing the buffer.
626                                 buffer_lock->unlock();
627                                 video_lock->unlock();
628                                 usleep(33000);
629                         }
630                 }
631 //printf("VDeviceV4L2::run 100 %lld\n", timer.get_difference());
632         }
635 VFrame* VDeviceV4L2Thread::get_buffer(int *timed_out)
637         VFrame *result = 0;
638         *timed_out = 0;
640 // Acquire buffer table
641         buffer_lock->lock("VDeviceV4L2Thread::get_buffer 1");
644 // Test for buffer availability
645         while(total_valid < 2 && !*timed_out && !first_frame)
646         {
647                 buffer_lock->unlock();
648                 *timed_out = video_lock->timed_lock(BUFFER_TIMEOUT, 
649                         "VDeviceV4L2Thread::read_frame 2");
650                 buffer_lock->lock("VDeviceV4L2Thread::get_buffer 3");
651         }
653 // Copy frame
654         if(total_valid >= 2)
655         {
656                 result = device_buffers[current_outbuffer];
657         }
659         buffer_lock->unlock();
661         return result;
664 void VDeviceV4L2Thread::put_buffer()
666         buffer_lock->lock("VDeviceV4L2Thread::put_buffer");
667         buffer_valid[current_outbuffer] = 0;
669 // Release buffer for capturing.
670         put_thread->put_buffer(current_outbuffer);
672         current_outbuffer++;
673         total_valid--;
674         if(current_outbuffer >= total_buffers)
675                 current_outbuffer = 0;
676         buffer_lock->unlock();
696 VDeviceV4L2::VDeviceV4L2(VideoDevice *device)
697  : VDeviceBase(device)
699         initialize();
702 VDeviceV4L2::~VDeviceV4L2()
704         close_all();
707 int VDeviceV4L2::close_all()
709         if(thread) delete thread;
710         thread = 0;
711         return 0;
715 int VDeviceV4L2::initialize()
717         thread = 0;
718         return 0;
723 int VDeviceV4L2::open_input()
725         int result = get_sources(device,
726                 device->in_config->v4l2_in_device);
727         device->channel->use_frequency = 1;
728         device->channel->use_fine = 1;
729         return result;
732 int VDeviceV4L2::get_sources(VideoDevice *device,
733         char *path)
735         int input_fd = -1;
738         device->channel->use_norm = 1;
739         device->channel->use_input = 1;
740         if(device->in_config->driver != VIDEO4LINUX2JPEG) 
741                 device->channel->has_scanning = 1;
742         else
743                 device->channel->has_scanning = 0;
745         if((input_fd = open(path, O_RDWR)) < 0)
746         {
747                 perror("VDeviceV4L::open_input");
748                 return 1;
749         }
750         else
751         {
752 // Get the inputs
753                 int i = 0;
754                 int done = 0;
755                 char *new_source;
757                 while(!done && i < 20)
758                 {
759                         struct v4l2_input arg;
760                         bzero(&arg, sizeof(arg));
761                         arg.index = i;
762                         
763                         if(ioctl(input_fd, VIDIOC_ENUMINPUT, &arg) < 0)
764                         {
765 // Finished
766                                 done = 1;
767                         }
768                         else
769                         {
770                                 Channel *channel = device->new_input_source((char*)arg.name);
771                                 channel->device_index = i;
772                                 channel->tuner = arg.tuner;
773                         }
774                         i++;
775                 }
777 // Get the picture controls
778                 for(i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++)
779                 {
780                         struct v4l2_queryctrl arg;
781                         bzero(&arg, sizeof(arg));
782                         arg.id = i;
783 // This returns errors for unsupported controls which is what we want.
784                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
785                         {
786 // Test if control exists already
787                                 if(!device->picture->get_item((const char*)arg.name, arg.id))
788                                 {
789 // Add control
790                                         PictureItem *item = device->picture->new_item((const char*)arg.name);
791                                         item->device_id = arg.id;
792                                         item->min = arg.minimum;
793                                         item->max = arg.maximum;
794                                         item->step = arg.step;
795                                         item->default_ = arg.default_value;
796                                         item->type = arg.type;
797                                         item->value = arg.default_value;
798                                 }
799                         }
800                 }
802 // Load defaults for picture controls
803                 device->picture->load_defaults();
805                 close(input_fd);
806         }
807         return 0;
810 int VDeviceV4L2::cmodel_to_device(int color_model)
812         switch(color_model)
813         {
814                 case BC_YUV422:
815                         return V4L2_PIX_FMT_YUYV;
816                         break;
817                 case BC_YUV411P:
818                         return V4L2_PIX_FMT_Y41P;
819                         break;
820                 case BC_YUV420P:
821                         return V4L2_PIX_FMT_YVU420;
822                         break;
823                 case BC_YUV422P:
824                         return V4L2_PIX_FMT_YUV422P;
825                         break;
826                 case BC_RGB888:
827                         return V4L2_PIX_FMT_RGB24;
828                         break;
829         }
830         return 0;
833 int VDeviceV4L2::get_best_colormodel(Asset *asset)
835         int result = BC_RGB888;
836         result = File::get_best_colormodel(asset, device->in_config->driver);
837         return result;
840 int VDeviceV4L2::has_signal()
842         if(thread)
843         {
844                 struct v4l2_tuner tuner;
845                 if(ioctl(thread->input_fd, VIDIOC_G_TUNER, &tuner) < 0)
846                         perror("VDeviceV4L2::has_signal VIDIOC_S_TUNER");
847                 return tuner.signal;
848         }
849         return 0;
852 int VDeviceV4L2::read_buffer(VFrame *frame)
854         int result = 0;
856         if((device->channel_changed || device->picture_changed) && thread)
857         {
858                 delete thread;
859                 thread = 0;
860         }
862         if(!thread)
863         {
864                 device->channel_changed = 0;
865                 device->picture_changed = 0;
866                 thread = new VDeviceV4L2Thread(device, frame->get_color_model());
867                 thread->start();
868         }
871 // Get buffer from thread
872         int timed_out;
873         VFrame *buffer = thread->get_buffer(&timed_out);
874         if(buffer)
875         {
876                 frame->copy_from(buffer);
877                 thread->put_buffer();
878         }
879         else
880         {
881 // Driver in 2.6.4 needs to be restarted when it loses sync.
882                 if(timed_out)
883                 {
884                         delete thread;
885                         thread = 0;
886                 }
887                 result = 1;
888         }
891         return result;
894 #endif