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