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