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