53c117229409abef2b7dc966aac247206fb26b0b
[goodguy/history.git] / cinelerra-5.0 / cinelerra / devicev4l2base.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22
23
24 #include "../hvirtual_config.h"
25 #include "bctimer.h"
26 #include "channel.h"
27 #include "chantables.h"
28 #include "clip.h"
29 #include "condition.h"
30 #include "devicev4l2base.h"
31 #include "mutex.h"
32 #include "picture.h"
33 #include "preferences.h"
34 #include "quicktime.h"
35 #include "recordconfig.h"
36 #include "videodevice.h"
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <stdint.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <fcntl.h>
45
46 #ifdef HAVE_VIDEO4LINUX2
47 #include <linux/videodev2.h>
48 #endif
49 #include <sys/ioctl.h>
50 #include <sys/mman.h>
51
52
53 DeviceV4L2BufferQ::
54 DeviceV4L2BufferQ(int qsize)
55 {
56         reset();
57         bfr_lock = new Mutex("DeviceV4L2BufferQ::bfr_lock");
58         buffers = new int[limit=qsize];
59 }
60
61 DeviceV4L2BufferQ::
62 ~DeviceV4L2BufferQ()
63 {
64         delete [] buffers;
65         delete bfr_lock;
66 }
67
68 int DeviceV4L2BufferQ::q(int bfr)
69 {
70         int result = 0;
71         bfr_lock->lock("DeviceV4L2Buffer::q");
72         int in1 = in+1;
73         if( in1 >= limit ) in1 = 0;
74         if( in1 != out )
75         {
76                 buffers[in] = bfr;
77                 in = in1;
78         }
79         else
80                 result = -1;
81         bfr_lock->unlock();
82         return result;
83 }
84
85 int DeviceV4L2BufferQ::dq(Condition *time_lock, int time_out)
86 {
87         int result = -1;
88         bfr_lock->lock(" DeviceV4L2Buffer::dq 0");
89         time_lock->reset();
90         if( in == out )
91         {
92                 bfr_lock->unlock();
93                 if( time_lock->timed_lock(time_out, "DeviceV4L2Buffer::dq 1") )
94                         printf("DeviceV4L2Buffer::wait time_out\n");
95                 bfr_lock->lock(" DeviceV4L2Buffer::dq 2");
96         }
97         if( in != out )
98         {
99                 result = buffers[out];
100                 int out1 = out+1;
101                 if( out1 >= limit ) out1 = 0;
102                 out = out1;
103         }
104         bfr_lock->unlock();
105         return result;
106 }
107
108 int DeviceV4L2BufferQ::dq()
109 {
110         int result = -1;
111         bfr_lock->lock(" DeviceV4L2Buffer::dq");
112         if( in != out )
113         {
114                 result = buffers[out];
115                 int out1 = out+1;
116                 if( out1 >= limit ) out1 = 0;
117                 out = out1;
118         }
119         bfr_lock->unlock();
120         return result;
121 }
122
123
124
125 DeviceV4L2Base::DeviceV4L2Base()
126  : Thread(1, 0, 0)
127 {
128         v4l2_lock = new Mutex("DeviceV4L2Input::v4l2_lock", 0);
129         qbfrs_lock = new Mutex("DeviceV4L2Base::qbfrs_lock");
130         video_lock = new Condition(0, "DeviceV4L2Base::video_lock", 1);
131         dev_fd = -1;
132         color_model = -1;
133         device_buffers = 0;
134         device_channel = 0;
135         total_buffers = 0;
136         streamon = 0;
137         dev_status = 0;
138         opened = 0;
139         q_bfrs = 0;
140         done = 0;
141         put_thread = 0;
142 }
143
144 DeviceV4L2Base::~DeviceV4L2Base()
145 {
146         close_dev();
147         delete video_lock;
148         delete qbfrs_lock;
149         delete v4l2_lock;
150 }
151
152
153
154 DeviceV4L2Put::DeviceV4L2Put(DeviceV4L2Base *v4l2)
155  : Thread(1, 0, 0)
156 {
157         this->v4l2 = v4l2;
158         done = 0;
159         putq = new DeviceV4L2BufferQ(256);
160         buffer_lock = new Condition(0, "DeviceV4L2Put::buffer_lock");
161 }
162
163 DeviceV4L2Put::~DeviceV4L2Put()
164 {
165         if(Thread::running())
166         {
167                 done = 1;
168                 buffer_lock->unlock();
169                 Thread::cancel();
170                 Thread::join();
171         }
172         delete buffer_lock;
173         delete putq;
174 }
175
176
177 void DeviceV4L2Put::run()
178 {
179         while(!done)
180         {
181                 buffer_lock->lock("DeviceV4L2Put::run");
182                 if(done) break;
183                 int bfr = putq->dq();
184                 if( bfr < 0 ) continue;
185                 struct v4l2_buffer arg;
186                 memset(&arg, 0, sizeof(arg));
187                 arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
188                 arg.index = bfr;
189                 arg.memory = V4L2_MEMORY_MMAP;
190
191                 Thread::enable_cancel();
192                 v4l2->qbfrs_lock->lock("DeviceV4L2Put::run");
193 // This locks up if there's no signal.
194                 if( v4l2->vioctl(VIDIOC_QBUF, &arg) < 0 )
195                         perror("DeviceV4L2Put::run 1 VIDIOC_QBUF");
196                 else
197                         ++v4l2->q_bfrs;
198                 v4l2->qbfrs_lock->unlock();
199                 Thread::disable_cancel();
200         }
201 }
202
203
204
205
206 int DeviceV4L2Base::get_sources()
207 {
208         v4l2_lock->lock("DeviceV4L2Base::get_sources");
209         VideoDevice *video_device = v4l2_device();
210         if( !video_device ) return 1;
211         const char *dev_path = video_device->in_config->get_path();
212         int vfd = open(dev_path, O_RDWR+O_CLOEXEC);
213         if(vfd < 0)
214         {
215                 perror("DeviceV4L2Base::get_sources open failed");
216                 printf("DeviceV4L2Base::get_sources path: %s\n", dev_path);
217                 return 1;
218         }
219
220 // Get the Inputs
221
222         for(int i = 0; i < 20; ++i)
223         {
224                 struct v4l2_input arg;
225                 memset(&arg, 0, sizeof(arg));
226                 arg.index = i;
227                         
228                 if(ioctl(vfd, VIDIOC_ENUMINPUT, &arg) < 0) break;
229                 Channel *channel = video_device->new_input_source((char*)arg.name);
230                 channel->device_index = i;
231                 channel->tuner = arg.type == V4L2_INPUT_TYPE_TUNER ? arg.tuner : -1;
232         }
233
234 // Get the picture controls
235         for(int i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++)
236         {
237                 struct v4l2_queryctrl arg;
238                 memset(&arg, 0, sizeof(arg));
239                 arg.id = i;
240 // This returns errors for unsupported controls which is what we want.
241                 if(!ioctl(vfd, VIDIOC_QUERYCTRL, &arg))
242                 {
243 // Test if control exists already
244                         if(!video_device->picture->get_item((const char*)arg.name, arg.id))
245                         {
246 // Add control
247                                 PictureItem *item = video_device->picture->new_item((const char*)arg.name);
248                                 item->device_id = arg.id;
249                                 item->min = arg.minimum;
250                                 item->max = arg.maximum;
251                                 item->step = arg.step;
252                                 item->default_ = arg.default_value;
253                                 item->type = arg.type;
254                                 item->value = arg.default_value;
255                         }
256                 }
257         }
258
259 // Load defaults for picture controls
260         video_device->picture->load_defaults();
261
262         close(vfd);
263         v4l2_lock->unlock();
264         return 0;
265 }
266
267 int DeviceV4L2Base::vioctl(unsigned long int req, void *arg)
268 {
269         int result = ioctl(dev_fd, req, arg);
270         return result;
271 }
272
273 int DeviceV4L2Base::v4l2_open(int color_model)
274 {
275         VideoDevice *video_device = v4l2_device();
276         if( !video_device ) return 1;
277
278         struct v4l2_capability cap;
279         memset(&cap, 0, sizeof(cap));
280         if(vioctl(VIDIOC_QUERYCAP, &cap))
281                 perror("DeviceV4L2Base::v4l2_open VIDIOC_QUERYCAP");
282
283 // printf("DeviceV4L2Base::v4l2_open dev_fd=%d driver=%s card=%s bus_info=%s version=%d\n",
284 // dev_fd(), cap.driver, cap.card, cap.bus_info, cap.version);
285 // printf("    ");
286 // if( (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ) printf("VIDEO_CAPTURE ");
287 // if( (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)  ) printf("VIDEO_OUTPUT ");
288 // if( (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) ) printf("VIDEO_OVERLAY ");
289 // if( (cap.capabilities & V4L2_CAP_VBI_CAPTURE)   ) printf("VBI_CAPTURE ");
290 // if( (cap.capabilities & V4L2_CAP_VBI_OUTPUT)    ) printf("VBI_OUTPUT ");
291 // if( (cap.capabilities & V4L2_CAP_RDS_CAPTURE)   ) printf("RDS_CAPTURE ");
292 // if( (cap.capabilities & V4L2_CAP_TUNER)         ) printf("TUNER ");
293 // if( (cap.capabilities & V4L2_CAP_AUDIO)         ) printf("AUDIO ");
294 // if( (cap.capabilities & V4L2_CAP_RADIO)         ) printf("RADIO ");
295 // if( (cap.capabilities & V4L2_CAP_READWRITE)     ) printf("READWRITE ");
296 // if( (cap.capabilities & V4L2_CAP_ASYNCIO)       ) printf("ASYNCIO ");
297 // if( (cap.capabilities & V4L2_CAP_STREAMING)     ) printf("STREAMING ");
298 // printf("\n"); 
299
300         int config_width = video_device->in_config->w;
301         int config_height = video_device->in_config->h;
302         int config_area = config_width * config_height;
303         int best_width = config_width;
304         int best_height = config_height;
305         unsigned int best_format = 0;
306         int best_merit = 0;
307         int best_color_model = -1;
308         int best_area = 1;
309         int driver = video_device->in_config->driver;
310
311         for( int i=0; i<20; ++i ) {
312                 struct v4l2_fmtdesc fmt;
313                 memset(&fmt,0,sizeof(fmt));
314                 fmt.index = i;
315                 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
316                 if( vioctl(VIDIOC_ENUM_FMT,&fmt) != 0 ) break;
317                 printf("DeviceV4L2Base::v4l2_open");
318                 // printf("format=\"%s\";",&fmt.description[0]);
319                 printf(" pixels=\"%4.4s\"; res=\"",(char*)&fmt.pixelformat);
320
321                 int merit = 0;
322                 int cmodel = -1;
323                 switch(fmt.pixelformat)
324                 {
325                 case V4L2_PIX_FMT_UYVY:    cmodel = BC_UVY422;  merit = 4;  break;
326                 case V4L2_PIX_FMT_YUYV:    cmodel = BC_YUV422;  merit = 4;  break;
327                 case V4L2_PIX_FMT_Y41P:    cmodel = BC_YUV411P; merit = 1;  break;
328                 case V4L2_PIX_FMT_YVU420:  cmodel = BC_YUV420P; merit = 3;  break;
329                 case V4L2_PIX_FMT_YUV422P: cmodel = BC_YUV422P; merit = 4;  break;
330                 case V4L2_PIX_FMT_RGB24:   cmodel = BC_RGB888;  merit = 6;  break;
331                 case V4L2_PIX_FMT_MJPEG:
332                         cmodel = BC_COMPRESSED;
333                         merit = driver == VIDEO4LINUX2JPEG ? 7 : 0;
334                         break;
335                 case V4L2_PIX_FMT_MPEG:
336                         cmodel = BC_YUV420P;
337                         merit = driver == VIDEO4LINUX2MPEG ? 7 : 2;
338                         break;
339                 }
340                 if( cmodel >= 0 && merit > best_merit )
341                 {
342                         best_merit = merit;
343                         best_format = fmt.pixelformat;
344                         best_color_model = cmodel;
345                 }
346
347                 for( int n=0; n<20; ++n ) {
348                         struct v4l2_frmsizeenum fsz;
349                         memset(&fsz,0,sizeof(fsz));
350                         fsz.index = n;
351                         fsz.pixel_format = fmt.pixelformat;
352                         if( vioctl(VIDIOC_ENUM_FRAMESIZES,&fsz) != 0 ) break;
353                         int w = fsz.discrete.width, h = fsz.discrete.height;
354                         if( n > 0 ) printf(" ");
355                         printf("%dx%d",w,h);
356                         int area = w * h;
357                         if( area > config_area ) continue;
358                         int diff0 = area - best_area;
359                         if( diff0 < 0 ) diff0 = -diff0;
360                         int diff1 = area - config_area;
361                         if( diff1 < 0 ) diff1 = -diff1;
362                         if( diff1 < diff0 ) {
363                                 best_area = area;
364                                 best_width = w;
365                                 best_height = h;
366                         }
367                 }
368                 printf("\"\n");
369         }
370
371         if( !best_format )
372         {
373                 printf("DeviceV4L2Base::v4l2_open cant determine best_format\n");
374                 switch(driver)
375                 {
376                 case VIDEO4LINUX2JPEG:
377                         best_format = V4L2_PIX_FMT_MJPEG;
378                         break;
379                 case VIDEO4LINUX2MPEG:
380                         best_format = V4L2_PIX_FMT_MPEG;
381                         break;
382                 default:
383                         best_color_model = color_model;
384                         best_format = cmodel_to_device(color_model);
385                         break;
386                 }
387                 printf(_("DeviceV4L2Base::v4l2_open "
388                         " attempting format %4.4s\n"), (char *)&best_format);
389         }
390         if(driver == VIDEO4LINUX2JPEG && best_format != V4L2_PIX_FMT_MJPEG)
391         {
392                 printf(_("DeviceV4L2Base::v4l2_open jpeg driver"
393                         " and best_format not mjpeg (%4.4s)\n"), (char *)&best_format);
394                 return 1;
395         }
396         if(driver == VIDEO4LINUX2MPEG && best_format != V4L2_PIX_FMT_MPEG)
397         {
398                 printf(_("DeviceV4L2Base::v4l2_open mpeg driver"
399                         " and best_format not mpeg (%4.4s)\n"),(char *)&best_format);
400                 return 1;
401         }
402         if(config_width != best_width || config_height != best_height)
403         {
404                 printf(_("DeviceV4L2Base::v4l2_open  config geom %dx%d != %dx%d best_geom\n"),
405                         config_width, config_height, best_width, best_height);
406         }
407
408 // Set up frame rate
409         struct v4l2_streamparm v4l2_parm;
410         memset(&v4l2_parm, 0, sizeof(v4l2_parm));
411         v4l2_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
412         if(vioctl(VIDIOC_G_PARM, &v4l2_parm) < 0)
413                 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_PARM");
414         if(v4l2_parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
415         {
416                 v4l2_parm.parm.capture.capturemode |= V4L2_CAP_TIMEPERFRAME;
417                 v4l2_parm.parm.capture.timeperframe.numerator = 1;
418                 v4l2_parm.parm.capture.timeperframe.denominator = 
419                         (unsigned long)((float)1 / 
420                         video_device->frame_rate * 10000000);
421                 if(vioctl(VIDIOC_S_PARM, &v4l2_parm) < 0)
422                         perror("DeviceV4L2Base::v4l2_open VIDIOC_S_PARM");
423
424                 if(vioctl(VIDIOC_G_PARM, &v4l2_parm) < 0)
425                         perror("DeviceV4L2Base::v4l2_open VIDIOC_G_PARM");
426         }
427
428 // Set up data format
429         struct v4l2_format v4l2_params;
430         memset(&v4l2_params, 0, sizeof(v4l2_params));
431         v4l2_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
432         if(vioctl(VIDIOC_G_FMT, &v4l2_params) < 0)
433                 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_FMT 1");
434         v4l2_params.fmt.pix.width = best_width;
435         v4l2_params.fmt.pix.height = best_height;
436         v4l2_params.fmt.pix.pixelformat = best_format;
437         if(vioctl(VIDIOC_S_FMT, &v4l2_params) < 0)
438                 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_FMT");
439         memset(&v4l2_params, 0, sizeof(v4l2_params));
440         v4l2_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
441         if(vioctl(VIDIOC_G_FMT, &v4l2_params) < 0)
442                 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_FMT 2");
443         if( v4l2_params.fmt.pix.pixelformat != best_format )
444         {
445                 printf("DeviceV4L2Base::v4l2_open  set format %4.4s != %4.4s best_format\n",
446                          (char*)&v4l2_params.fmt.pix.pixelformat, (char*)&best_format);
447                 return 1;
448         }
449         if( (int)v4l2_params.fmt.pix.width != best_width ||
450             (int)v4l2_params.fmt.pix.height != best_height )
451         {
452                 printf("DeviceV4L2Base::v4l2_open  set geom %dx%d != %dx%d best_geom\n",
453                         v4l2_params.fmt.pix.width, v4l2_params.fmt.pix.height,
454                         best_width, best_height);
455                 return 1;
456         }
457
458 // Set picture controls.  This driver requires the values to be set once to default
459 // values and then again to different values before it takes up the values.
460 // Unfortunately VIDIOC_S_CTRL resets the audio to mono in 2.6.7.
461         PictureConfig *picture = video_device->picture;
462         for(int i = 0; i < picture->controls.total; i++)
463         {
464                 struct v4l2_queryctrl arg;
465                 memset(&arg, 0, sizeof(arg));
466                 PictureItem *item = picture->controls.values[i];
467                 arg.id = item->device_id;
468                 if(!vioctl(VIDIOC_QUERYCTRL, &arg))
469                 {
470                         struct v4l2_control ctrl_arg;
471                         memset(&ctrl_arg, 0, sizeof(ctrl_arg));
472                         ctrl_arg.id = item->device_id;
473                         ctrl_arg.value = 0;
474                         if(vioctl(VIDIOC_S_CTRL, &ctrl_arg) < 0)
475                                 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL");
476                 }
477                 else
478                 {
479                         printf("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL 1 %s/id %08x failed\n",
480                                 item->name, item->device_id);
481                 }
482         }
483
484
485         for(int i = 0; i < picture->controls.total; i++)
486         {
487                 struct v4l2_queryctrl arg;
488                 memset(&arg, 0, sizeof(arg));
489                 PictureItem *item = picture->controls.values[i];
490                 arg.id = item->device_id;
491
492                 if(!vioctl(VIDIOC_QUERYCTRL, &arg))
493                 {
494                         struct v4l2_control ctrl_arg;
495                         memset(&ctrl_arg, 0, sizeof(ctrl_arg));
496                         ctrl_arg.id = item->device_id;
497                         ctrl_arg.value = item->value;
498                         if(vioctl(VIDIOC_S_CTRL, &ctrl_arg) < 0)
499                                 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL");
500                 }
501                 else
502                 {
503                         printf("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL 2 %s/id %08x failed\n",
504                                 item->name, item->device_id);
505                 }
506         }
507
508
509 // Set input
510         Channel *video_channel = video_device->channel;
511         ArrayList<Channel*> *inputs = video_device->get_inputs();
512         int input = video_channel->input;
513         device_channel = input >= 0 && input < inputs->total ?
514                 inputs->values[input] : 0;
515         if(!device_channel)
516         {
517 // Try first input
518                 if(inputs->total)
519                 {
520                         device_channel = inputs->values[0];
521                         printf("DeviceV4L2Base::v4l2_open user channel not found.  Using %s\n",
522                                 device_channel->device_name);
523                 }
524                 else
525                 {
526                         printf("DeviceV4L2Base::v4l2_open channel \"%s\" not found.\n",
527                                 video_channel->title);
528                 }
529         }
530
531 // Translate input to API structures
532         input = device_channel ? device_channel->device_index : 0;
533         if(vioctl(VIDIOC_S_INPUT, &input) < 0)
534                 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_INPUT");
535
536 // Set norm
537         v4l2_std_id std_id = 0;
538         switch(video_channel->norm)
539         {
540                 case NTSC: std_id = V4L2_STD_NTSC; break;
541                 case PAL: std_id = V4L2_STD_PAL; break;
542                 case SECAM: std_id = V4L2_STD_SECAM; break;
543                 default: std_id = V4L2_STD_NTSC_M; break;
544         }
545         if(vioctl(VIDIOC_S_STD, &std_id))
546                 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_STD");
547
548         int dev_tuner = device_channel ? device_channel->tuner : -1;
549         if( (cap.capabilities & V4L2_CAP_TUNER) && dev_tuner >= 0 )
550         {
551                 struct v4l2_tuner tuner;
552                 memset(&tuner, 0, sizeof(tuner));
553                 tuner.index = dev_tuner;
554                 if(!vioctl(VIDIOC_G_TUNER, &tuner) < 0)
555                 {
556 // printf("DeviceV4L2Base::v4l2_open audmode=%d rxsubchans=%d\n",
557 //   tuner.audmode, tuner.rxsubchans);
558                         tuner.index = dev_tuner;
559                         tuner.type = V4L2_TUNER_ANALOG_TV;
560                         tuner.audmode = V4L2_TUNER_MODE_STEREO;
561                         tuner.rxsubchans = V4L2_TUNER_SUB_STEREO;
562                         if(vioctl(VIDIOC_S_TUNER, &tuner) < 0)
563                                 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_TUNER");
564 // Set frequency
565                         struct v4l2_frequency frequency;
566                         memset(&frequency, 0, sizeof(frequency));
567                         frequency.tuner = video_channel->tuner;
568                         frequency.type = V4L2_TUNER_ANALOG_TV;
569                         int table = video_channel->freqtable;
570                         int entry = video_channel->entry;
571                         frequency.frequency = (int)(chanlists[table].list[entry].freq * 0.016);
572 // printf("DeviceV4L2Base::v4l2_open tuner=%d freq=%d norm=%d\n",
573 //   video_channel->tuner, frequency.frequency, video_channel->norm);
574                         if(vioctl(VIDIOC_S_FREQUENCY, &frequency) < 0)
575                                 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_FREQUENCY");
576                 }
577                 else
578                         perror("DeviceV4L2Base::v4l2_open VIDIOC_G_TUNER");
579         }
580
581 // Set compression
582         if(color_model == BC_COMPRESSED)
583         {
584                 struct v4l2_jpegcompression jpeg_arg;
585                 memset(&jpeg_arg, 0, sizeof(jpeg_arg));
586                 if(vioctl(VIDIOC_G_JPEGCOMP, &jpeg_arg) < 0)
587                         perror("DeviceV4L2Base::v4l2_open VIDIOC_G_JPEGCOMP");
588                 jpeg_arg.quality = video_device->quality / 2;
589                 if(vioctl(VIDIOC_S_JPEGCOMP, &jpeg_arg) < 0)
590                         perror("DeviceV4L2Base::v4l2_open VIDIOC_S_JPEGCOMP");
591         }
592
593         this->color_model = best_color_model;
594         return 0;
595 }
596
597 int DeviceV4L2Base::v4l2_status()
598 {
599         int result = 1;
600         Channel *channel = device_channel;
601         if( !channel )
602         {
603                 dev_status = 0;
604         }
605         else if( channel->tuner >= 0 )
606         {
607                 struct v4l2_tuner tuner;
608                 memset(&tuner,0,sizeof(tuner));
609                 tuner.index = channel->tuner;
610                 if( !vioctl(VIDIOC_G_TUNER, &tuner) )
611                 {
612                         dev_status = tuner.signal ? 1 : 0;
613                         result = 0;
614                 }
615                 else
616                         perror("DeviceV4L2Base::v4l2_status VIDIOC_S_TUNER");
617         }
618         else
619         {
620                 struct v4l2_input arg;
621                 memset(&arg, 0, sizeof(arg));
622                 arg.index = channel->device_index;
623                 if( !vioctl(VIDIOC_ENUMINPUT, &arg) )
624                 {
625                         dev_status = (arg.status &
626                         (V4L2_IN_ST_NO_POWER | V4L2_IN_ST_NO_SIGNAL)) ? 0 : 1;
627                         result = 0;
628                 }
629                 else
630                         perror("DeviceV4L2Base::v4l2_status VIDIOC_ENUMINPUT");
631         }
632         return result;
633 }
634
635 void DeviceV4L2Base::dev_close()
636 {
637         if( dev_fd >= 0 )
638         {
639                 ::close(dev_fd);
640                 dev_fd = -1;
641         }
642 }
643
644 int DeviceV4L2Base::dev_open()
645 {
646         if( dev_fd < 0 )
647         {
648                 VideoDevice *video_device = v4l2_device();
649                 if( !video_device )
650                 {
651                         printf("DeviceV4L2Base::dev_open: video_device not available\n");
652                         Timer::delay(250);
653                         return -1;
654                 }
655                 const char *dev_path = video_device->in_config->get_path();
656                 dev_fd = open(dev_path, O_RDWR);
657                 if( dev_fd < 0 )
658                 {
659                         perror("DeviceV4L2Base::dev_open: open_failed");
660                         printf("DeviceV4L2Base::dev_open: dev_path %s\n", dev_path);
661                         return 1;
662                 }
663                 video_device->set_cloexec_flag(dev_fd, 1);
664         }
665         return 0;
666 }
667
668
669 int DeviceV4L2Base::open_dev(int color_model)
670 {
671         v4l2_lock->lock("DeviceV4L2Base::open_dev");
672         int result = 0;
673         if( !opened )
674         {
675                 result = dev_open();
676                 if( !result )
677                         result = v4l2_open(color_model);
678                 if( !result )
679                         result = start_dev();
680                 if( !result )
681                 {
682                         qbfrs_lock->reset();
683                         video_lock->reset();
684                         getq = new DeviceV4L2BufferQ(total_buffers+1);
685                         put_thread = new DeviceV4L2Put(this);
686                         put_thread->start();
687                         done = 0;
688                         Thread::start();
689                 }
690                 else
691                         printf("DeviceV4L2Base::open_dev failed\n");
692         }
693         if( result )
694         {
695                 printf("DeviceV4L2Base::open_dev: adaptor open failed\n");
696                 stop_dev();
697                 dev_close();
698         }
699         else
700                 opened = 1;
701         v4l2_lock->unlock();
702         return result;
703 }
704
705 void DeviceV4L2Base::close_dev()
706 {
707         v4l2_lock->lock("DeviceV4L2Base::close_dev");
708         if( opened )
709         {
710                 if(Thread::running())
711                 {
712                         done = 1;
713                         Thread::cancel();
714                         Thread::join();
715                 }
716                 if(put_thread)
717                 {
718                         delete put_thread;
719                         put_thread = 0;
720                 }
721                 stop_dev();
722                 dev_close();
723                 delete getq;
724                 getq = 0;
725                 opened = 0;
726         }
727         v4l2_lock->unlock();
728 }
729
730 int DeviceV4L2Base::status_dev()
731 {
732         v4l2_lock->lock("DeviceV4L2Base::status_dev");
733         int result = dev_fd >= 0 ? v4l2_status() : 1;
734         v4l2_lock->unlock();
735         return result;
736 }
737
738 unsigned int DeviceV4L2Base::cmodel_to_device(int color_model)
739 {
740         switch(color_model)
741         {
742         case BC_COMPRESSED:     return V4L2_PIX_FMT_MJPEG;
743         case BC_YUV422:         return V4L2_PIX_FMT_YUYV;
744         case BC_UVY422:         return V4L2_PIX_FMT_UYVY;
745         case BC_YUV411P:        return V4L2_PIX_FMT_Y41P;
746         case BC_YUV420P:        return V4L2_PIX_FMT_YVU420;
747         case BC_YUV422P:        return V4L2_PIX_FMT_YUV422P;
748         case BC_RGB888:         return V4L2_PIX_FMT_RGB24;
749         }
750         return 0;
751 }
752
753 DeviceV4L2VFrame::DeviceV4L2VFrame(int dev_fd, unsigned long ofs, unsigned long sz)
754 {
755         dev_data = (unsigned char*)mmap(NULL, dev_size=sz,
756                 PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, ofs);
757         if(dev_data == MAP_FAILED) {
758                 perror("DeviceV4L2VFrame::DeviceV4L2VFrame: mmap");
759                 dev_data = 0;
760         }
761 }
762
763
764 DeviceV4L2VFrame::~DeviceV4L2VFrame()
765 {
766         munmap(dev_data, dev_size);
767 }
768
769 int DeviceV4L2Base::start_dev()
770 {
771         VideoDevice *video_device = v4l2_device();
772         if( !video_device ) return 1;
773
774 // Errors here are fatal.
775         int req_buffers = video_device->in_config->capture_length;
776         req_buffers = MAX(req_buffers, 2);
777         req_buffers = MIN(req_buffers, 0xff);
778
779         struct v4l2_requestbuffers requestbuffers;
780         memset(&requestbuffers, 0, sizeof(requestbuffers));
781 //printf("DeviceV4L2Base::start_dev requested %d buffers\n", req_buffers);
782         requestbuffers.count = req_buffers;
783         requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
784         requestbuffers.memory = V4L2_MEMORY_MMAP;
785         if(vioctl(VIDIOC_REQBUFS, &requestbuffers) < 0)
786         {
787                 perror("DeviceV4L2Base::start_dev VIDIOC_REQBUFS");
788                 return 1;
789         }
790         int bfr_count = requestbuffers.count;
791 //printf("DeviceV4L2Base::start_dev got %d buffers\n", bfr_count);
792         device_buffers = new DeviceV4L2VFrame *[bfr_count];
793         memset(device_buffers, 0, bfr_count*sizeof(device_buffers[0]));
794
795 //printf("DeviceV4L2Base::start_dev color_model=%d\n", color_model);
796         int iwidth = video_device->in_config->w;
797         int iheight = video_device->in_config->h;
798         int y_offset = 0, line_size = -1;
799         int u_offset = 0, v_offset = 0;
800
801         if(color_model != BC_COMPRESSED)
802         {
803                 switch(color_model)
804                 {
805                 case BC_YUV422P:
806                         u_offset = iwidth * iheight;
807                         v_offset = u_offset + u_offset / 2;
808                         break;
809                 case BC_YUV420P:
810                 case BC_YUV411P:
811 // In 2.6.7, the v and u are inverted for 420 but not 422
812                         v_offset = iwidth * iheight;
813                         u_offset = v_offset + v_offset / 4;
814                         break;
815                 }
816         }
817
818         total_buffers = 0;
819         for(int i = 0; i < bfr_count; i++)
820         {
821                 struct v4l2_buffer buffer;
822                 memset(&buffer, 0, sizeof(buffer));
823                 buffer.type = requestbuffers.type;
824                 buffer.index = i;
825                 if(vioctl(VIDIOC_QUERYBUF, &buffer) < 0)
826                 {
827                         perror("DeviceV4L2Base::start_dev VIDIOC_QUERYBUF");
828                         continue;
829                 }
830
831                 DeviceV4L2VFrame *dframe =
832                         new DeviceV4L2VFrame(dev_fd, buffer.m.offset, buffer.length);
833                 unsigned char *data = dframe->get_dev_data();
834                 if( !data ) continue;
835                 device_buffers[total_buffers++] = dframe;
836                 if(color_model != BC_COMPRESSED)
837                         dframe->reallocate(data, 0, y_offset, u_offset, v_offset,
838                                 iwidth, iheight, color_model, line_size);
839                 else
840                         dframe->set_compressed_memory(data, 0, 0, dframe->get_dev_size());
841         }
842
843         q_bfrs = 0;
844         for(int i = 0; i < total_buffers; i++)
845         {
846                 struct v4l2_buffer buffer;
847                 memset(&buffer, 0, sizeof(buffer));
848                 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
849                 buffer.memory = V4L2_MEMORY_MMAP;
850                 buffer.index = i;
851
852                 if(vioctl(VIDIOC_QBUF, &buffer) < 0)
853                 {
854                         perror("DeviceV4L2Base::start_dev VIDIOC_QBUF");
855                         continue;
856                 }
857                 ++q_bfrs;
858         }
859
860         int streamon_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
861         if(vioctl(VIDIOC_STREAMON, &streamon_arg) < 0)
862         {
863                 perror("DeviceV4L2Base::start_dev VIDIOC_STREAMON");
864                 return 1;
865         }
866
867         streamon = 1;
868         return 0;
869 }
870
871 int DeviceV4L2Base::stop_dev()
872 {
873         if( streamon )
874         {
875                 int streamoff_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
876                 if(vioctl(VIDIOC_STREAMOFF, &streamoff_arg) < 0)
877                         perror("DeviceV4L2Base::stop_stream_capture VIDIOC_STREAMOFF");
878                 streamon = 0;
879         }
880
881         for( int i = 0; i < total_buffers; i++ )
882         {
883                 delete device_buffers[i];
884         }
885
886         struct v4l2_requestbuffers requestbuffers;
887         memset(&requestbuffers, 0, sizeof(requestbuffers));
888         requestbuffers.count = 0;
889         requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
890         requestbuffers.memory = V4L2_MEMORY_MMAP;
891         vioctl(VIDIOC_REQBUFS, &requestbuffers);
892
893         delete [] device_buffers;
894         device_buffers = 0;
895         total_buffers = 0;
896         return 0;
897 }
898
899
900 void DeviceV4L2Base::run()
901 {
902         Thread::disable_cancel();
903         int min_buffers = total_buffers / 2;
904         if( min_buffers > 3 ) min_buffers = 3;
905
906 // Read buffers continuously
907         while( !done )
908         {
909                 int retry = 0;
910                 int qbfrs = q_bfrs;
911                 while( !done && (!qbfrs || (!retry && qbfrs < min_buffers)) )
912                 {
913                         Thread::enable_cancel();
914                         Timer::delay(10);
915                         Thread::disable_cancel();
916                         ++retry;  qbfrs = q_bfrs;
917                 }
918                 if( done ) break;
919                 struct v4l2_buffer buffer;
920                 memset(&buffer, 0, sizeof(buffer));
921                 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
922                 buffer.memory = V4L2_MEMORY_MMAP;
923
924 // The driver returns the first buffer not queued, so only one buffer
925 // can be unqueued at a time.
926                 Thread::enable_cancel();
927                 qbfrs_lock->lock("DeviceV4L2Base::run");
928                 int result = vioctl(VIDIOC_DQBUF, &buffer);
929                 if( !result ) --q_bfrs;
930                 qbfrs_lock->unlock();
931                 Thread::disable_cancel();
932                 if(result < 0)
933                 {
934                         perror("DeviceV4L2Base::run VIDIOC_DQBUF");
935                         Thread::enable_cancel();
936                         Timer::delay(10);
937                         Thread::disable_cancel();
938                         continue;
939                 }
940
941 // Get output frame
942                 int bfr = buffer.index;
943 // Set output frame data size/time, queue video
944                 VFrame *frame = device_buffers[bfr];
945                 if(color_model == BC_COMPRESSED)
946                         frame->set_compressed_size(buffer.bytesused);
947                 struct timeval *tv = &buffer.timestamp;
948                 double bfr_time = tv->tv_sec + tv->tv_usec / 1000000.;
949                 frame->set_timestamp(bfr_time);
950                 if( !getq->q(bfr) ) video_lock->unlock();
951         }
952 }
953