4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
24 #include "../hvirtual_config.h"
27 #include "chantables.h"
29 #include "condition.h"
30 #include "devicev4l2base.h"
33 #include "preferences.h"
34 #include "quicktime.h"
35 #include "recordconfig.h"
36 #include "videodevice.h"
46 #ifdef HAVE_VIDEO4LINUX2
47 #include <linux/videodev2.h>
49 #include <sys/ioctl.h>
54 DeviceV4L2BufferQ(int qsize)
57 bfr_lock = new Mutex("DeviceV4L2BufferQ::bfr_lock");
58 buffers = new int[limit=qsize];
68 int DeviceV4L2BufferQ::q(int bfr)
71 bfr_lock->lock("DeviceV4L2Buffer::q");
73 if( in1 >= limit ) in1 = 0;
85 int DeviceV4L2BufferQ::dq(Condition *time_lock, int time_out)
88 bfr_lock->lock(" DeviceV4L2Buffer::dq 0");
93 if( time_lock->timed_lock(time_out, "DeviceV4L2Buffer::dq 1") )
94 printf("DeviceV4L2Buffer::wait time_out\n");
95 bfr_lock->lock(" DeviceV4L2Buffer::dq 2");
99 result = buffers[out];
101 if( out1 >= limit ) out1 = 0;
108 int DeviceV4L2BufferQ::dq()
111 bfr_lock->lock(" DeviceV4L2Buffer::dq");
114 result = buffers[out];
116 if( out1 >= limit ) out1 = 0;
125 DeviceV4L2Base::DeviceV4L2Base()
128 v4l2_lock = new Mutex("DeviceV4L2Input::v4l2_lock", 0);
129 qbfrs_lock = new Mutex("DeviceV4L2Base::qbfrs_lock");
130 video_lock = new Condition(0, "DeviceV4L2Base::video_lock", 1);
144 DeviceV4L2Base::~DeviceV4L2Base()
154 DeviceV4L2Put::DeviceV4L2Put(DeviceV4L2Base *v4l2)
159 putq = new DeviceV4L2BufferQ(256);
160 buffer_lock = new Condition(0, "DeviceV4L2Put::buffer_lock");
163 DeviceV4L2Put::~DeviceV4L2Put()
165 if(Thread::running())
168 buffer_lock->unlock();
177 void DeviceV4L2Put::run()
181 buffer_lock->lock("DeviceV4L2Put::run");
183 int bfr = putq->dq();
184 if( bfr < 0 ) continue;
185 struct v4l2_buffer arg;
186 memset(&arg, 0, sizeof(arg));
187 arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
189 arg.memory = V4L2_MEMORY_MMAP;
191 Thread::enable_cancel();
192 v4l2->qbfrs_lock->lock("DeviceV4L2Put::run");
193 // This locks up if there's no signal.
194 if( v4l2->vioctl(VIDIOC_QBUF, &arg) < 0 )
195 perror("DeviceV4L2Put::run 1 VIDIOC_QBUF");
198 v4l2->qbfrs_lock->unlock();
199 Thread::disable_cancel();
206 int DeviceV4L2Base::get_sources()
208 v4l2_lock->lock("DeviceV4L2Base::get_sources");
209 VideoDevice *video_device = v4l2_device();
210 if( !video_device ) return 1;
211 const char *dev_path = video_device->in_config->get_path();
212 int vfd = open(dev_path, O_RDWR+O_CLOEXEC);
215 perror("DeviceV4L2Base::get_sources open failed");
216 printf("DeviceV4L2Base::get_sources path: %s\n", dev_path);
222 for(int i = 0; i < 20; ++i)
224 struct v4l2_input arg;
225 memset(&arg, 0, sizeof(arg));
228 if(ioctl(vfd, VIDIOC_ENUMINPUT, &arg) < 0) break;
229 Channel *channel = video_device->new_input_source((char*)arg.name);
230 channel->device_index = i;
231 channel->tuner = arg.type == V4L2_INPUT_TYPE_TUNER ? arg.tuner : -1;
234 // Get the picture controls
235 for(int i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++)
237 struct v4l2_queryctrl arg;
238 memset(&arg, 0, sizeof(arg));
240 // This returns errors for unsupported controls which is what we want.
241 if(!ioctl(vfd, VIDIOC_QUERYCTRL, &arg))
243 // Test if control exists already
244 if(!video_device->picture->get_item((const char*)arg.name, arg.id))
247 PictureItem *item = video_device->picture->new_item((const char*)arg.name);
248 item->device_id = arg.id;
249 item->min = arg.minimum;
250 item->max = arg.maximum;
251 item->step = arg.step;
252 item->default_ = arg.default_value;
253 item->type = arg.type;
254 item->value = arg.default_value;
259 // Load defaults for picture controls
260 video_device->picture->load_defaults();
267 int DeviceV4L2Base::vioctl(unsigned long int req, void *arg)
269 int result = ioctl(dev_fd, req, arg);
273 int DeviceV4L2Base::v4l2_open(int color_model)
275 VideoDevice *video_device = v4l2_device();
276 if( !video_device ) return 1;
278 struct v4l2_capability cap;
279 memset(&cap, 0, sizeof(cap));
280 if(vioctl(VIDIOC_QUERYCAP, &cap))
281 perror("DeviceV4L2Base::v4l2_open VIDIOC_QUERYCAP");
283 // printf("DeviceV4L2Base::v4l2_open dev_fd=%d driver=%s card=%s bus_info=%s version=%d\n",
284 // dev_fd(), cap.driver, cap.card, cap.bus_info, cap.version);
286 // if( (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ) printf("VIDEO_CAPTURE ");
287 // if( (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) ) printf("VIDEO_OUTPUT ");
288 // if( (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) ) printf("VIDEO_OVERLAY ");
289 // if( (cap.capabilities & V4L2_CAP_VBI_CAPTURE) ) printf("VBI_CAPTURE ");
290 // if( (cap.capabilities & V4L2_CAP_VBI_OUTPUT) ) printf("VBI_OUTPUT ");
291 // if( (cap.capabilities & V4L2_CAP_RDS_CAPTURE) ) printf("RDS_CAPTURE ");
292 // if( (cap.capabilities & V4L2_CAP_TUNER) ) printf("TUNER ");
293 // if( (cap.capabilities & V4L2_CAP_AUDIO) ) printf("AUDIO ");
294 // if( (cap.capabilities & V4L2_CAP_RADIO) ) printf("RADIO ");
295 // if( (cap.capabilities & V4L2_CAP_READWRITE) ) printf("READWRITE ");
296 // if( (cap.capabilities & V4L2_CAP_ASYNCIO) ) printf("ASYNCIO ");
297 // if( (cap.capabilities & V4L2_CAP_STREAMING) ) printf("STREAMING ");
300 int config_width = video_device->in_config->w;
301 int config_height = video_device->in_config->h;
302 int config_area = config_width * config_height;
303 int best_width = config_width;
304 int best_height = config_height;
305 unsigned int best_format = 0;
307 int best_color_model = -1;
309 int driver = video_device->in_config->driver;
311 for( int i=0; i<20; ++i ) {
312 struct v4l2_fmtdesc fmt;
313 memset(&fmt,0,sizeof(fmt));
315 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
316 if( vioctl(VIDIOC_ENUM_FMT,&fmt) != 0 ) break;
317 printf("DeviceV4L2Base::v4l2_open");
318 // printf("format=\"%s\";",&fmt.description[0]);
319 printf(" pixels=\"%4.4s\"; res=\"",(char*)&fmt.pixelformat);
323 switch(fmt.pixelformat)
325 case V4L2_PIX_FMT_UYVY: cmodel = BC_UVY422; merit = 4; break;
326 case V4L2_PIX_FMT_YUYV: cmodel = BC_YUV422; merit = 4; break;
327 case V4L2_PIX_FMT_Y41P: cmodel = BC_YUV411P; merit = 1; break;
328 case V4L2_PIX_FMT_YVU420: cmodel = BC_YUV420P; merit = 3; break;
329 case V4L2_PIX_FMT_YUV422P: cmodel = BC_YUV422P; merit = 4; break;
330 case V4L2_PIX_FMT_RGB24: cmodel = BC_RGB888; merit = 6; break;
331 case V4L2_PIX_FMT_MJPEG:
332 cmodel = BC_COMPRESSED;
333 merit = driver == VIDEO4LINUX2JPEG ? 7 : 0;
335 case V4L2_PIX_FMT_MPEG:
337 merit = driver == VIDEO4LINUX2MPEG ? 7 : 2;
340 if( cmodel >= 0 && merit > best_merit )
343 best_format = fmt.pixelformat;
344 best_color_model = cmodel;
347 for( int n=0; n<20; ++n ) {
348 struct v4l2_frmsizeenum fsz;
349 memset(&fsz,0,sizeof(fsz));
351 fsz.pixel_format = fmt.pixelformat;
352 if( vioctl(VIDIOC_ENUM_FRAMESIZES,&fsz) != 0 ) break;
353 int w = fsz.discrete.width, h = fsz.discrete.height;
354 if( n > 0 ) printf(" ");
357 if( area > config_area ) continue;
358 int diff0 = area - best_area;
359 if( diff0 < 0 ) diff0 = -diff0;
360 int diff1 = area - config_area;
361 if( diff1 < 0 ) diff1 = -diff1;
362 if( diff1 < diff0 ) {
373 printf("DeviceV4L2Base::v4l2_open cant determine best_format\n");
376 case VIDEO4LINUX2JPEG:
377 best_format = V4L2_PIX_FMT_MJPEG;
379 case VIDEO4LINUX2MPEG:
380 best_format = V4L2_PIX_FMT_MPEG;
383 best_color_model = color_model;
384 best_format = cmodel_to_device(color_model);
387 printf(_("DeviceV4L2Base::v4l2_open "
388 " attempting format %4.4s\n"), (char *)&best_format);
390 if(driver == VIDEO4LINUX2JPEG && best_format != V4L2_PIX_FMT_MJPEG)
392 printf(_("DeviceV4L2Base::v4l2_open jpeg driver"
393 " and best_format not mjpeg (%4.4s)\n"), (char *)&best_format);
396 if(driver == VIDEO4LINUX2MPEG && best_format != V4L2_PIX_FMT_MPEG)
398 printf(_("DeviceV4L2Base::v4l2_open mpeg driver"
399 " and best_format not mpeg (%4.4s)\n"),(char *)&best_format);
402 if(config_width != best_width || config_height != best_height)
404 printf(_("DeviceV4L2Base::v4l2_open config geom %dx%d != %dx%d best_geom\n"),
405 config_width, config_height, best_width, best_height);
409 struct v4l2_streamparm v4l2_parm;
410 memset(&v4l2_parm, 0, sizeof(v4l2_parm));
411 v4l2_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
412 if(vioctl(VIDIOC_G_PARM, &v4l2_parm) < 0)
413 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_PARM");
414 if(v4l2_parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
416 v4l2_parm.parm.capture.capturemode |= V4L2_CAP_TIMEPERFRAME;
417 v4l2_parm.parm.capture.timeperframe.numerator = 1;
418 v4l2_parm.parm.capture.timeperframe.denominator =
419 (unsigned long)((float)1 /
420 video_device->frame_rate * 10000000);
421 if(vioctl(VIDIOC_S_PARM, &v4l2_parm) < 0)
422 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_PARM");
424 if(vioctl(VIDIOC_G_PARM, &v4l2_parm) < 0)
425 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_PARM");
428 // Set up data format
429 struct v4l2_format v4l2_params;
430 memset(&v4l2_params, 0, sizeof(v4l2_params));
431 v4l2_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
432 if(vioctl(VIDIOC_G_FMT, &v4l2_params) < 0)
433 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_FMT 1");
434 v4l2_params.fmt.pix.width = best_width;
435 v4l2_params.fmt.pix.height = best_height;
436 v4l2_params.fmt.pix.pixelformat = best_format;
437 if(vioctl(VIDIOC_S_FMT, &v4l2_params) < 0)
438 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_FMT");
439 memset(&v4l2_params, 0, sizeof(v4l2_params));
440 v4l2_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
441 if(vioctl(VIDIOC_G_FMT, &v4l2_params) < 0)
442 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_FMT 2");
443 if( v4l2_params.fmt.pix.pixelformat != best_format )
445 printf("DeviceV4L2Base::v4l2_open set format %4.4s != %4.4s best_format\n",
446 (char*)&v4l2_params.fmt.pix.pixelformat, (char*)&best_format);
449 if( (int)v4l2_params.fmt.pix.width != best_width ||
450 (int)v4l2_params.fmt.pix.height != best_height )
452 printf("DeviceV4L2Base::v4l2_open set geom %dx%d != %dx%d best_geom\n",
453 v4l2_params.fmt.pix.width, v4l2_params.fmt.pix.height,
454 best_width, best_height);
458 // Set picture controls. This driver requires the values to be set once to default
459 // values and then again to different values before it takes up the values.
460 // Unfortunately VIDIOC_S_CTRL resets the audio to mono in 2.6.7.
461 PictureConfig *picture = video_device->picture;
462 for(int i = 0; i < picture->controls.total; i++)
464 struct v4l2_queryctrl arg;
465 memset(&arg, 0, sizeof(arg));
466 PictureItem *item = picture->controls.values[i];
467 arg.id = item->device_id;
468 if(!vioctl(VIDIOC_QUERYCTRL, &arg))
470 struct v4l2_control ctrl_arg;
471 memset(&ctrl_arg, 0, sizeof(ctrl_arg));
472 ctrl_arg.id = item->device_id;
474 if(vioctl(VIDIOC_S_CTRL, &ctrl_arg) < 0)
475 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL");
479 printf("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL 1 %s/id %08x failed\n",
480 item->name, item->device_id);
485 for(int i = 0; i < picture->controls.total; i++)
487 struct v4l2_queryctrl arg;
488 memset(&arg, 0, sizeof(arg));
489 PictureItem *item = picture->controls.values[i];
490 arg.id = item->device_id;
492 if(!vioctl(VIDIOC_QUERYCTRL, &arg))
494 struct v4l2_control ctrl_arg;
495 memset(&ctrl_arg, 0, sizeof(ctrl_arg));
496 ctrl_arg.id = item->device_id;
497 ctrl_arg.value = item->value;
498 if(vioctl(VIDIOC_S_CTRL, &ctrl_arg) < 0)
499 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL");
503 printf("DeviceV4L2Base::v4l2_open VIDIOC_S_CTRL 2 %s/id %08x failed\n",
504 item->name, item->device_id);
510 Channel *video_channel = video_device->channel;
511 ArrayList<Channel*> *inputs = video_device->get_inputs();
512 int input = video_channel->input;
513 device_channel = input >= 0 && input < inputs->total ?
514 inputs->values[input] : 0;
520 device_channel = inputs->values[0];
521 printf("DeviceV4L2Base::v4l2_open user channel not found. Using %s\n",
522 device_channel->device_name);
526 printf("DeviceV4L2Base::v4l2_open channel \"%s\" not found.\n",
527 video_channel->title);
531 // Translate input to API structures
532 input = device_channel ? device_channel->device_index : 0;
533 if(vioctl(VIDIOC_S_INPUT, &input) < 0)
534 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_INPUT");
537 v4l2_std_id std_id = 0;
538 switch(video_channel->norm)
540 case NTSC: std_id = V4L2_STD_NTSC; break;
541 case PAL: std_id = V4L2_STD_PAL; break;
542 case SECAM: std_id = V4L2_STD_SECAM; break;
543 default: std_id = V4L2_STD_NTSC_M; break;
545 if(vioctl(VIDIOC_S_STD, &std_id))
546 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_STD");
548 int dev_tuner = device_channel ? device_channel->tuner : -1;
549 if( (cap.capabilities & V4L2_CAP_TUNER) && dev_tuner >= 0 )
551 struct v4l2_tuner tuner;
552 memset(&tuner, 0, sizeof(tuner));
553 tuner.index = dev_tuner;
554 if(!vioctl(VIDIOC_G_TUNER, &tuner) < 0)
556 // printf("DeviceV4L2Base::v4l2_open audmode=%d rxsubchans=%d\n",
557 // tuner.audmode, tuner.rxsubchans);
558 tuner.index = dev_tuner;
559 tuner.type = V4L2_TUNER_ANALOG_TV;
560 tuner.audmode = V4L2_TUNER_MODE_STEREO;
561 tuner.rxsubchans = V4L2_TUNER_SUB_STEREO;
562 if(vioctl(VIDIOC_S_TUNER, &tuner) < 0)
563 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_TUNER");
565 struct v4l2_frequency frequency;
566 memset(&frequency, 0, sizeof(frequency));
567 frequency.tuner = video_channel->tuner;
568 frequency.type = V4L2_TUNER_ANALOG_TV;
569 int table = video_channel->freqtable;
570 int entry = video_channel->entry;
571 frequency.frequency = (int)(chanlists[table].list[entry].freq * 0.016);
572 // printf("DeviceV4L2Base::v4l2_open tuner=%d freq=%d norm=%d\n",
573 // video_channel->tuner, frequency.frequency, video_channel->norm);
574 if(vioctl(VIDIOC_S_FREQUENCY, &frequency) < 0)
575 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_FREQUENCY");
578 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_TUNER");
582 if(color_model == BC_COMPRESSED)
584 struct v4l2_jpegcompression jpeg_arg;
585 memset(&jpeg_arg, 0, sizeof(jpeg_arg));
586 if(vioctl(VIDIOC_G_JPEGCOMP, &jpeg_arg) < 0)
587 perror("DeviceV4L2Base::v4l2_open VIDIOC_G_JPEGCOMP");
588 jpeg_arg.quality = video_device->quality / 2;
589 if(vioctl(VIDIOC_S_JPEGCOMP, &jpeg_arg) < 0)
590 perror("DeviceV4L2Base::v4l2_open VIDIOC_S_JPEGCOMP");
593 this->color_model = best_color_model;
597 int DeviceV4L2Base::v4l2_status()
600 Channel *channel = device_channel;
605 else if( channel->tuner >= 0 )
607 struct v4l2_tuner tuner;
608 memset(&tuner,0,sizeof(tuner));
609 tuner.index = channel->tuner;
610 if( !vioctl(VIDIOC_G_TUNER, &tuner) )
612 dev_status = tuner.signal ? 1 : 0;
616 perror("DeviceV4L2Base::v4l2_status VIDIOC_S_TUNER");
620 struct v4l2_input arg;
621 memset(&arg, 0, sizeof(arg));
622 arg.index = channel->device_index;
623 if( !vioctl(VIDIOC_ENUMINPUT, &arg) )
625 dev_status = (arg.status &
626 (V4L2_IN_ST_NO_POWER | V4L2_IN_ST_NO_SIGNAL)) ? 0 : 1;
630 perror("DeviceV4L2Base::v4l2_status VIDIOC_ENUMINPUT");
635 void DeviceV4L2Base::dev_close()
644 int DeviceV4L2Base::dev_open()
648 VideoDevice *video_device = v4l2_device();
651 printf("DeviceV4L2Base::dev_open: video_device not available\n");
655 const char *dev_path = video_device->in_config->get_path();
656 dev_fd = open(dev_path, O_RDWR);
659 perror("DeviceV4L2Base::dev_open: open_failed");
660 printf("DeviceV4L2Base::dev_open: dev_path %s\n", dev_path);
663 video_device->set_cloexec_flag(dev_fd, 1);
669 int DeviceV4L2Base::open_dev(int color_model)
671 v4l2_lock->lock("DeviceV4L2Base::open_dev");
677 result = v4l2_open(color_model);
679 result = start_dev();
684 getq = new DeviceV4L2BufferQ(total_buffers+1);
685 put_thread = new DeviceV4L2Put(this);
691 printf("DeviceV4L2Base::open_dev failed\n");
695 printf("DeviceV4L2Base::open_dev: adaptor open failed\n");
705 void DeviceV4L2Base::close_dev()
707 v4l2_lock->lock("DeviceV4L2Base::close_dev");
710 if(Thread::running())
730 int DeviceV4L2Base::status_dev()
732 v4l2_lock->lock("DeviceV4L2Base::status_dev");
733 int result = dev_fd >= 0 ? v4l2_status() : 1;
738 unsigned int DeviceV4L2Base::cmodel_to_device(int color_model)
742 case BC_COMPRESSED: return V4L2_PIX_FMT_MJPEG;
743 case BC_YUV422: return V4L2_PIX_FMT_YUYV;
744 case BC_UVY422: return V4L2_PIX_FMT_UYVY;
745 case BC_YUV411P: return V4L2_PIX_FMT_Y41P;
746 case BC_YUV420P: return V4L2_PIX_FMT_YVU420;
747 case BC_YUV422P: return V4L2_PIX_FMT_YUV422P;
748 case BC_RGB888: return V4L2_PIX_FMT_RGB24;
753 DeviceV4L2VFrame::DeviceV4L2VFrame(int dev_fd, unsigned long ofs, unsigned long sz)
755 dev_data = (unsigned char*)mmap(NULL, dev_size=sz,
756 PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, ofs);
757 if(dev_data == MAP_FAILED) {
758 perror("DeviceV4L2VFrame::DeviceV4L2VFrame: mmap");
764 DeviceV4L2VFrame::~DeviceV4L2VFrame()
766 munmap(dev_data, dev_size);
769 int DeviceV4L2Base::start_dev()
771 VideoDevice *video_device = v4l2_device();
772 if( !video_device ) return 1;
774 // Errors here are fatal.
775 int req_buffers = video_device->in_config->capture_length;
776 req_buffers = MAX(req_buffers, 2);
777 req_buffers = MIN(req_buffers, 0xff);
779 struct v4l2_requestbuffers requestbuffers;
780 memset(&requestbuffers, 0, sizeof(requestbuffers));
781 //printf("DeviceV4L2Base::start_dev requested %d buffers\n", req_buffers);
782 requestbuffers.count = req_buffers;
783 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
784 requestbuffers.memory = V4L2_MEMORY_MMAP;
785 if(vioctl(VIDIOC_REQBUFS, &requestbuffers) < 0)
787 perror("DeviceV4L2Base::start_dev VIDIOC_REQBUFS");
790 int bfr_count = requestbuffers.count;
791 //printf("DeviceV4L2Base::start_dev got %d buffers\n", bfr_count);
792 device_buffers = new DeviceV4L2VFrame *[bfr_count];
793 memset(device_buffers, 0, bfr_count*sizeof(device_buffers[0]));
795 //printf("DeviceV4L2Base::start_dev color_model=%d\n", color_model);
796 int iwidth = video_device->in_config->w;
797 int iheight = video_device->in_config->h;
798 int y_offset = 0, line_size = -1;
799 int u_offset = 0, v_offset = 0;
801 if(color_model != BC_COMPRESSED)
806 u_offset = iwidth * iheight;
807 v_offset = u_offset + u_offset / 2;
811 // In 2.6.7, the v and u are inverted for 420 but not 422
812 v_offset = iwidth * iheight;
813 u_offset = v_offset + v_offset / 4;
819 for(int i = 0; i < bfr_count; i++)
821 struct v4l2_buffer buffer;
822 memset(&buffer, 0, sizeof(buffer));
823 buffer.type = requestbuffers.type;
825 if(vioctl(VIDIOC_QUERYBUF, &buffer) < 0)
827 perror("DeviceV4L2Base::start_dev VIDIOC_QUERYBUF");
831 DeviceV4L2VFrame *dframe =
832 new DeviceV4L2VFrame(dev_fd, buffer.m.offset, buffer.length);
833 unsigned char *data = dframe->get_dev_data();
834 if( !data ) continue;
835 device_buffers[total_buffers++] = dframe;
836 if(color_model != BC_COMPRESSED)
837 dframe->reallocate(data, 0, y_offset, u_offset, v_offset,
838 iwidth, iheight, color_model, line_size);
840 dframe->set_compressed_memory(data, 0, 0, dframe->get_dev_size());
844 for(int i = 0; i < total_buffers; i++)
846 struct v4l2_buffer buffer;
847 memset(&buffer, 0, sizeof(buffer));
848 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
849 buffer.memory = V4L2_MEMORY_MMAP;
852 if(vioctl(VIDIOC_QBUF, &buffer) < 0)
854 perror("DeviceV4L2Base::start_dev VIDIOC_QBUF");
860 int streamon_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
861 if(vioctl(VIDIOC_STREAMON, &streamon_arg) < 0)
863 perror("DeviceV4L2Base::start_dev VIDIOC_STREAMON");
871 int DeviceV4L2Base::stop_dev()
875 int streamoff_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
876 if(vioctl(VIDIOC_STREAMOFF, &streamoff_arg) < 0)
877 perror("DeviceV4L2Base::stop_stream_capture VIDIOC_STREAMOFF");
881 for( int i = 0; i < total_buffers; i++ )
883 delete device_buffers[i];
886 struct v4l2_requestbuffers requestbuffers;
887 memset(&requestbuffers, 0, sizeof(requestbuffers));
888 requestbuffers.count = 0;
889 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
890 requestbuffers.memory = V4L2_MEMORY_MMAP;
891 vioctl(VIDIOC_REQBUFS, &requestbuffers);
893 delete [] device_buffers;
900 void DeviceV4L2Base::run()
902 Thread::disable_cancel();
903 int min_buffers = total_buffers / 2;
904 if( min_buffers > 3 ) min_buffers = 3;
906 // Read buffers continuously
911 while( !done && (!qbfrs || (!retry && qbfrs < min_buffers)) )
913 Thread::enable_cancel();
915 Thread::disable_cancel();
916 ++retry; qbfrs = q_bfrs;
919 struct v4l2_buffer buffer;
920 memset(&buffer, 0, sizeof(buffer));
921 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
922 buffer.memory = V4L2_MEMORY_MMAP;
924 // The driver returns the first buffer not queued, so only one buffer
925 // can be unqueued at a time.
926 Thread::enable_cancel();
927 qbfrs_lock->lock("DeviceV4L2Base::run");
928 int result = vioctl(VIDIOC_DQBUF, &buffer);
929 if( !result ) --q_bfrs;
930 qbfrs_lock->unlock();
931 Thread::disable_cancel();
934 perror("DeviceV4L2Base::run VIDIOC_DQBUF");
935 Thread::enable_cancel();
937 Thread::disable_cancel();
942 int bfr = buffer.index;
943 // Set output frame data size/time, queue video
944 VFrame *frame = device_buffers[bfr];
945 if(color_model == BC_COMPRESSED)
946 frame->set_compressed_size(buffer.bytesused);
947 struct timeval *tv = &buffer.timestamp;
948 double bfr_time = tv->tv_sec + tv->tv_usec / 1000000.;
949 frame->set_timestamp(bfr_time);
950 if( !getq->q(bfr) ) video_lock->unlock();