4
* V4L2 interface with basically JPEG decompression support and even more ...
5
* Copyright 2006 Krzysztof Blaszkowski (kb@sysmikro.com.pl)
6
* 2007 Angel Carpintero (ack@telefonica.net)
8
* Supported features and TODO
9
* - preferred palette is JPEG which seems to be very popular for many 640x480 usb cams
10
* - other supported palettes (NOT TESTED)
11
* V4L2_PIX_FMT_SBGGR8 ( sonix )
12
* V4L2_PIX_FMT_SN9C10X ( sonix )
13
* V4L2_PIX_FMT_MJPEG, ( tested )
14
* V4L2_PIX_FMT_JPEG, ( tested )
16
V4L2_PIX_FMT_UYVY, ( tested )
18
V4L2_PIX_FMT_YUV420, ( tested )
19
V4L2_PIX_FMT_YUYV ( tested )
21
* - setting tuner - NOT TESTED
22
* - access to V4L2 device controls is missing. Partially added but requires some improvements likely.
23
* - changing resolution at run-time may not work.
24
* - ucvideo svn r75 or above to work with MJPEG ( i.ex Logitech 5000 pro )
26
* This work is inspired by fswebcam and current design of motion.
27
* This interface has been tested with ZC0301 driver from kernel 2.6.17.3 and Labtec's usb camera (PAS202 sensor)
29
* I'm very pleased by achieved image quality and cpu usage comparing to junky v4l1 spca5xx driver with
30
* it nonsensical kernel messy jpeg decompressor.
31
* Default sensor settings used by ZC0301 driver are very reasonable choosen.
32
* apparently brigthness should be controlled automatically by motion still for light compensation.
33
* it can be done by adjusting ADC gain and also exposure time.
36
* This program is free software; you can redistribute it and/or modify it
37
* under the terms of the GNU General Public License as published by the
38
* Free Software Foundation; either version 2 of the License, or (at your
39
* option) any later version.
41
* This program is distributed in the hope that it will be useful, but
42
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
43
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
51
# warning **************************************************
52
# warning Using experimental V4L2 support
53
# warning **************************************************
56
#include <sys/utsname.h>
65
#include <sys/ioctl.h>
73
#ifdef MOTION_V4L2_OLD
74
// Seems that is needed for some system
75
#include <linux/time.h>
76
#include <linux/videodev2.h>
79
#define u8 unsigned char
80
#define u16 unsigned short
81
#define u32 unsigned int
83
#define MMAP_BUFFERS 4
84
#define MIN_MMAP_BUFFERS 2
86
#ifndef V4L2_PIX_FMT_SBGGR8
87
/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
88
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */
91
#ifndef V4L2_PIX_FMT_MJPEG
92
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */
95
#ifndef V4L2_PIX_FMT_SN9C10X
96
#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x compression */
99
#define ZC301_V4L2_CID_DAC_MAGN V4L2_CID_PRIVATE_BASE
100
#define ZC301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE+1)
102
static const u32 queried_ctrls[] = {
108
V4L2_CID_RED_BALANCE,
109
V4L2_CID_BLUE_BALANCE,
115
ZC301_V4L2_CID_DAC_MAGN,
116
ZC301_V4L2_CID_GREEN_BALANCE,
126
struct v4l2_capability cap;
127
struct v4l2_format fmt;
128
struct v4l2_requestbuffers req;
129
struct v4l2_buffer buf;
131
netcam_buff *buffers;
136
struct v4l2_queryctrl *controls;
140
static int xioctl(int fd, int request, void *arg)
145
r = ioctl(fd, request, arg);
146
while (-1 == r && EINTR == errno);
151
static int v4l2_get_capability(src_v4l2_t * s)
154
if (xioctl(s->fd, VIDIOC_QUERYCAP, &s->cap) < 0) {
155
motion_log(LOG_ERR, 0, "Not a V4L2 device?");
159
motion_log(LOG_INFO, 0, "cap.driver: \"%s\"", s->cap.driver);
160
motion_log(LOG_INFO, 0, "cap.card: \"%s\"", s->cap.card);
161
motion_log(LOG_INFO, 0, "cap.bus_info: \"%s\"", s->cap.bus_info);
162
motion_log(LOG_INFO, 0, "cap.capabilities=0x%08X", s->cap.capabilities);
164
if (s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
165
motion_log(LOG_INFO, 0, "- VIDEO_CAPTURE");
166
if (s->cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
167
motion_log(LOG_INFO, 0, "- VIDEO_OUTPUT");
168
if (s->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
169
motion_log(LOG_INFO, 0, "- VIDEO_OVERLAY");
170
if (s->cap.capabilities & V4L2_CAP_VBI_CAPTURE)
171
motion_log(LOG_INFO, 0, "- VBI_CAPTURE");
172
if (s->cap.capabilities & V4L2_CAP_VBI_OUTPUT)
173
motion_log(LOG_INFO, 0, "- VBI_OUTPUT");
174
if (s->cap.capabilities & V4L2_CAP_RDS_CAPTURE)
175
motion_log(LOG_INFO, 0, "- RDS_CAPTURE");
176
if (s->cap.capabilities & V4L2_CAP_TUNER)
177
motion_log(LOG_INFO, 0, "- TUNER");
178
if (s->cap.capabilities & V4L2_CAP_AUDIO)
179
motion_log(LOG_INFO, 0, "- AUDIO");
180
if (s->cap.capabilities & V4L2_CAP_READWRITE)
181
motion_log(LOG_INFO, 0, "- READWRITE");
182
if (s->cap.capabilities & V4L2_CAP_ASYNCIO)
183
motion_log(LOG_INFO, 0, "- ASYNCIO");
184
if (s->cap.capabilities & V4L2_CAP_STREAMING)
185
motion_log(LOG_INFO, 0, "- STREAMING");
186
if (s->cap.capabilities & V4L2_CAP_TIMEPERFRAME)
187
motion_log(LOG_INFO, 0, "- TIMEPERFRAME");
189
if (!s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
190
motion_log(LOG_ERR, 0, "Device does not support capturing.");
197
static int v4l2_select_input(src_v4l2_t * s, int in, int norm, unsigned long freq_, int tuner_number)
199
struct v4l2_input input;
200
struct v4l2_standard standard;
208
if (xioctl(s->fd, VIDIOC_ENUMINPUT, &input) == -1) {
209
motion_log(LOG_ERR, 0, "Unable to query input %d.", in);
210
motion_log(LOG_ERR, 0, "VIDIOC_ENUMINPUT: %s", strerror(errno));
215
motion_log(LOG_INFO, 0, "%s: name = \"%s\", type 0x%08X, status %08x", __FUNCTION__, input.name, input.type,
218
if ((input.type & V4L2_INPUT_TYPE_TUNER) && (debug_level > 5))
219
motion_log(LOG_INFO, 0, "- TUNER");
220
if ((input.type & V4L2_INPUT_TYPE_CAMERA) && (debug_level > 5))
221
motion_log(LOG_INFO, 0, "- CAMERA");
223
if (xioctl(s->fd, VIDIOC_S_INPUT, &in) == -1) {
224
motion_log(LOG_ERR, 0, "Error selecting input %d", in);
225
motion_log(LOG_ERR, 0, "VIDIOC_S_INPUT: %s", strerror(errno));
229
/* Set video standard usually webcams doesn't support the ioctl or return V4L2_STD_UNKNOWN */
230
if (xioctl(s->fd, VIDIOC_G_STD, &std_id) == -1) {
232
motion_log(LOG_INFO, 0, "Device doesn't support VIDIOC_G_STD ");
233
std_id = 0; // V4L2_STD_UNKNOWN = 0
237
memset(&standard, 0, sizeof(standard));
240
while (xioctl(s->fd, VIDIOC_ENUMSTD, &standard) == 0) {
241
if ((standard.id & std_id) && (debug_level > 5)){
242
motion_log(LOG_INFO, 0, "- video standard %s", standard.name);
249
std_id = V4L2_STD_NTSC;
252
std_id = V4L2_STD_SECAM;
255
std_id = V4L2_STD_PAL;
258
if (xioctl(s->fd, VIDIOC_S_STD, &std_id) == -1) {
259
motion_log(LOG_ERR, 0, "Error selecting standard method %d", std_id);
260
motion_log(LOG_ERR, 0, "VIDIOC_S_STD: %s", strerror(errno));
264
/* If this input is attached to a tuner, set the frequency. */
265
if (input.type & V4L2_INPUT_TYPE_TUNER) {
266
struct v4l2_tuner tuner;
267
struct v4l2_frequency freq;
269
/* Query the tuners capabilities. */
271
memset(&tuner, 0, sizeof(struct v4l2_tuner));
272
tuner.index = input.tuner;
274
if (xioctl(s->fd, VIDIOC_G_TUNER, &tuner) == -1) {
275
motion_log(LOG_ERR, 0, "VIDIOC_G_TUNER: %s", strerror(errno));
279
/* Set the frequency. */
280
memset(&freq, 0, sizeof(struct v4l2_frequency));
281
freq.tuner = input.tuner;
282
freq.type = V4L2_TUNER_ANALOG_TV;
283
freq.frequency = (freq_ / 1000) * 16;
285
if (xioctl(s->fd, VIDIOC_S_FREQUENCY, &freq) == -1) {
286
motion_log(LOG_ERR, 0, "VIDIOC_S_FREQUENCY: %s", strerror(errno));
294
static int v4l2_set_pix_format(src_v4l2_t * s, int *width, int *height)
296
struct v4l2_fmtdesc fmt;
299
static const u32 supported_formats[] = { /* higher index means better chance to be used */
300
V4L2_PIX_FMT_SN9C10X,
307
V4L2_PIX_FMT_YUV422P,
312
int index_format = -1;
314
memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
315
fmt.index = v4l2_pal = 0;
316
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
318
motion_log(LOG_INFO, 0, "Supported palettes:");
319
while (xioctl(s->fd, VIDIOC_ENUM_FMT, &fmt) != -1) {
322
motion_log(LOG_INFO, 0, "%i: %c%c%c%c (%s)", v4l2_pal,
323
fmt.pixelformat >> 0, fmt.pixelformat >> 8,
324
fmt.pixelformat >> 16, fmt.pixelformat >> 24, fmt.description);
326
for (i = 0; supported_formats[i]; i++)
327
if (supported_formats[i] == fmt.pixelformat && i > index_format) {
331
memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
332
fmt.index = ++v4l2_pal;
333
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
336
if (index_format >= 0) {
338
u32 pixformat = supported_formats[index_format];
340
memset(&s->fmt, 0, sizeof(struct v4l2_format));
341
s->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
342
s->fmt.fmt.pix.width = *width;
343
s->fmt.fmt.pix.height = *height;
344
s->fmt.fmt.pix.pixelformat = pixformat;
345
s->fmt.fmt.pix.field = V4L2_FIELD_ANY;
347
if (xioctl(s->fd, VIDIOC_TRY_FMT, &s->fmt) != -1 && s->fmt.fmt.pix.pixelformat == pixformat) {
348
motion_log(LOG_INFO, 0, "Test palette %c%c%c%c (%dx%d)", pixformat >> 0, pixformat >> 8, pixformat >> 16, pixformat >> 24, *width, *height);
350
if (s->fmt.fmt.pix.width != (unsigned int) *width
351
|| s->fmt.fmt.pix.height != (unsigned int) *height) {
352
motion_log(LOG_INFO, 0, "Adjusting resolution from %ix%i to %ix%i.", *width, *height,
353
s->fmt.fmt.pix.width, s->fmt.fmt.pix.height);
354
*width = s->fmt.fmt.pix.width;
355
*height = s->fmt.fmt.pix.height;
358
if (xioctl(s->fd, VIDIOC_S_FMT, &s->fmt) == -1) {
359
motion_log(LOG_ERR, 0, "Error setting pixel format.");
360
motion_log(LOG_ERR, 0, "VIDIOC_S_FMT: %s", strerror(errno));
364
motion_log(LOG_INFO, 0, "Using palette %c%c%c%c (%dx%d) bytesperlines %d sizeimage %d colorspace %08x", pixformat >> 0, pixformat >> 8, pixformat >> 16, pixformat >> 24, *width, *height, s->fmt.fmt.pix.bytesperline, s->fmt.fmt.pix.sizeimage, s->fmt.fmt. pix.colorspace);
366
/* TODO: Review when it has been tested */
367
if (pixformat == V4L2_PIX_FMT_MJPEG) {
368
struct v4l2_jpegcompression v4l2_jpeg;
370
if (xioctl(s->fd, VIDIOC_G_JPEGCOMP, &v4l2_jpeg) == -1) {
371
motion_log(LOG_ERR, 0, "VIDIOC_G_JPEGCOMP not supported but it should");
373
v4l2_jpeg.jpeg_markers |= V4L2_JPEG_MARKER_DHT;
374
if (xioctl(s->fd, VIDIOC_S_JPEGCOMP, &v4l2_jpeg) == -1)
375
motion_log(LOG_ERR, 0, "VIDIOC_S_JPEGCOMP %s", strerror(errno));
383
motion_log(LOG_ERR, 0, "VIDIOC_TRY_FMT failed for format %c%c%c%c (%s).", pixformat >> 0,
384
pixformat >> 8, pixformat >> 16, pixformat >> 24, strerror(errno));
389
motion_log(LOG_ERR, 0, "Unable to find a compatible palette format.");
394
static void v4l2_set_fps(src_v4l2_t * s){
395
struct v4l2_streamparm* setfps;
397
setfps=(struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm));
398
memset(setfps, 0, sizeof(struct v4l2_streamparm));
399
setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
400
setfps->parm.capture.timeperframe.numerator=1;
401
setfps->parm.capture.timeperframe.denominator=s->fps;
402
if (xioctl(s->fd, VIDIOC_S_PARM, setfps) == -1){
403
motion_log(LOG_ERR, 0, "v4l2_set_fps VIDIOC_S_PARM %s",strerror(errno));
408
static int v4l2_set_mmap(src_v4l2_t * s)
410
enum v4l2_buf_type type;
413
/* Does the device support streaming? */
414
if (!s->cap.capabilities & V4L2_CAP_STREAMING)
417
memset(&s->req, 0, sizeof(struct v4l2_requestbuffers));
419
s->req.count = MMAP_BUFFERS;
420
s->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
421
s->req.memory = V4L2_MEMORY_MMAP;
423
if (xioctl(s->fd, VIDIOC_REQBUFS, &s->req) == -1) {
424
motion_log(LOG_ERR, 1, "Error requesting buffers for memory map.");
425
motion_log(LOG_ERR, 0, "VIDIOC_REQBUFS: %s", strerror(errno));
429
motion_log(LOG_DEBUG, 0, "mmap information:");
430
motion_log(LOG_DEBUG, 0, "frames=%d", s->req.count);
432
if (s->req.count < MIN_MMAP_BUFFERS) {
433
motion_log(LOG_ERR, 0, "Insufficient buffer memory.");
437
s->buffers = calloc(s->req.count, sizeof(netcam_buff));
439
motion_log(LOG_ERR, 1, "%s: Out of memory.", __FUNCTION__);
443
for (b = 0; b < s->req.count; b++) {
444
struct v4l2_buffer buf;
446
memset(&buf, 0, sizeof(struct v4l2_buffer));
448
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
449
buf.memory = V4L2_MEMORY_MMAP;
452
if (xioctl(s->fd, VIDIOC_QUERYBUF, &buf) == -1) {
453
motion_log(LOG_ERR, 0, "Error querying buffer %i", b);
454
motion_log(LOG_ERR, 0, "VIDIOC_QUERYBUF: %s", strerror(errno));
459
s->buffers[b].size = buf.length;
460
s->buffers[b].ptr = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, buf.m.offset);
462
if (s->buffers[b].ptr == MAP_FAILED) {
463
motion_log(LOG_ERR, 0, "Error mapping buffer %i", b);
464
motion_log(LOG_ERR, 0, "mmap: %s", strerror(errno));
469
motion_log(LOG_DEBUG, 0, "%i length=%d", b, buf.length);
474
for (b = 0; b < s->req.count; b++) {
475
memset(&s->buf, 0, sizeof(struct v4l2_buffer));
477
s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
478
s->buf.memory = V4L2_MEMORY_MMAP;
481
if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) {
482
motion_log(LOG_ERR, 0, "VIDIOC_QBUF: %s", strerror(errno));
487
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
489
if (xioctl(s->fd, VIDIOC_STREAMON, &type) == -1) {
490
motion_log(LOG_ERR, 0, "Error starting stream.");
491
motion_log(LOG_ERR, 0, "VIDIOC_STREAMON: %s", strerror(errno));
498
static int v4l2_scan_controls(src_v4l2_t * s)
501
struct v4l2_queryctrl queryctrl;
503
memset(&queryctrl, 0, sizeof(struct v4l2_queryctrl));
505
for (i = 0, count = 0; queried_ctrls[i]; i++) {
506
queryctrl.id = queried_ctrls[i];
507
if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl))
511
s->ctrl_flags |= 1 << i;
515
struct v4l2_queryctrl *ctrl = s->controls = calloc(count, sizeof(struct v4l2_queryctrl));
518
motion_log(LOG_ERR, 0, "%s: Insufficient buffer memory.", __FUNCTION__);
522
for (i = 0; queried_ctrls[i]; i++) {
523
if (s->ctrl_flags & (1 << i)) {
524
struct v4l2_control control;
526
queryctrl.id = queried_ctrls[i];
527
if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl))
530
memcpy(ctrl, &queryctrl, sizeof(struct v4l2_queryctrl));
532
motion_log(LOG_INFO, 0, "found control 0x%08x, \"%s\", range %d,%d %s", ctrl->id,
533
ctrl->name, ctrl->minimum, ctrl->maximum,
534
ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "!DISABLED!" : "");
536
control.id = queried_ctrls[i];
537
xioctl(s->fd, VIDIOC_G_CTRL, &control);
538
motion_log(LOG_INFO, 0, "\t\"%s\", default %d, current %d", ctrl->name,
539
ctrl->default_value, control.value);
549
static int v4l2_set_control(src_v4l2_t * s, u32 cid, int value)
556
for (i = 0, count = 0; queried_ctrls[i]; i++) {
557
if (s->ctrl_flags & (1 << i)) {
558
if (cid == queried_ctrls[i]) {
559
struct v4l2_queryctrl *ctrl = s->controls + count;
560
struct v4l2_control control;
563
control.id = queried_ctrls[i];
565
switch (ctrl->type) {
566
case V4L2_CTRL_TYPE_INTEGER:
567
value = control.value =
568
(value * (ctrl->maximum - ctrl->minimum) / 256) + ctrl->minimum;
569
ret = xioctl(s->fd, VIDIOC_S_CTRL, &control);
572
case V4L2_CTRL_TYPE_BOOLEAN:
573
value = control.value = value ? 1 : 0;
574
ret = xioctl(s->fd, VIDIOC_S_CTRL, &control);
578
motion_log(LOG_ERR, 0, "%s: control type not supported yet");
582
motion_log(LOG_INFO, 0, "setting control \"%s\" to %d (ret %d %s) %s", ctrl->name,
583
value, ret, ret ? strerror(errno) : "",
584
ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "Control is DISABLED!" : "");
595
static void v4l2_picture_controls(struct context *cnt, struct video_dev *viddev)
597
src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
599
if (cnt->conf.contrast && cnt->conf.contrast != viddev->contrast) {
600
viddev->contrast = cnt->conf.contrast;
601
v4l2_set_control(s, V4L2_CID_CONTRAST, viddev->contrast);
604
if (cnt->conf.saturation && cnt->conf.saturation != viddev->saturation) {
605
viddev->saturation = cnt->conf.saturation;
606
v4l2_set_control(s, V4L2_CID_SATURATION, viddev->saturation);
609
if (cnt->conf.hue && cnt->conf.hue != viddev->hue) {
610
viddev->hue = cnt->conf.hue;
611
v4l2_set_control(s, V4L2_CID_HUE, viddev->hue);
614
if (cnt->conf.autobright) {
615
if (vid_do_autobright(cnt, viddev)) {
616
if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness))
617
v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness);
620
if (cnt->conf.brightness && cnt->conf.brightness != viddev->brightness) {
621
viddev->brightness = cnt->conf.brightness;
622
if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness))
623
v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness);
629
/* public functions */
631
unsigned char *v4l2_start(struct context *cnt, struct video_dev *viddev, int width, int height,
632
int input, int norm, unsigned long freq, int tuner_number)
636
/* Allocate memory for the state structure. */
637
if (!(s = calloc(sizeof(src_v4l2_t), 1))) {
638
motion_log(LOG_ERR, 0, "%s: Out of memory.", __FUNCTION__);
642
viddev->v4l2_private = s;
644
s->fps = cnt->conf.frame_limit;
647
if (v4l2_get_capability(s)) {
651
if (v4l2_select_input(s, input, norm, freq, tuner_number)) {
655
if (v4l2_set_pix_format(s, &width, &height)) {
659
if (v4l2_scan_controls(s)) {
666
if (v4l2_set_mmap(s)) {
670
viddev->size_map = 0;
671
viddev->v4l_buffers[0] = NULL;
672
viddev->v4l_maxbuffer = 1;
673
viddev->v4l_curbuffer = 0;
675
viddev->v4l_fmt = VIDEO_PALETTE_YUV420P;
676
viddev->v4l_bufsize = (width * height * 3) / 2;
679
/* Update width and height with supported values from camera driver */
680
viddev->width = width;
681
viddev->height = height;
688
viddev->v4l2_private = NULL;
693
void v4l2_set_input(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height,
697
int input = conf->input;
698
int norm = conf->norm;
699
int skip = conf->roundrobin_skip;
700
unsigned long freq = conf->frequency;
701
int tuner_number = conf->tuner_number;
703
if (input != viddev->input || width != viddev->width || height != viddev->height ||
704
freq != viddev->freq || tuner_number != viddev->tuner_number) {
706
struct timeval switchTime;
708
v4l2_select_input((src_v4l2_t *) viddev->v4l2_private, input, norm, freq, tuner_number);
710
gettimeofday(&switchTime, NULL);
712
v4l2_picture_controls(cnt, viddev);
714
viddev->input = input;
715
viddev->width = width;
716
viddev->height = height;
718
viddev->tuner_number = tuner_number;
721
/* Skip all frames captured before switchtime, capture 1 after switchtime */
723
src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
724
unsigned int counter = 0;
726
motion_log(LOG_DEBUG, 0, "set_input_skip_frame switch_time=%ld:%ld",
727
switchTime.tv_sec, switchTime.tv_usec);
729
/* Avoid hang using the number of mmap buffers */
730
while(counter < s->req.count)
733
if (v4l2_next(cnt, viddev, map, width, height))
735
if (s->buf.timestamp.tv_sec > switchTime.tv_sec ||
736
(s->buf.timestamp.tv_sec == switchTime.tv_sec && s->buf.timestamp.tv_usec > switchTime.tv_usec))
739
motion_log(LOG_DEBUG, 0, "got frame before switch timestamp=%ld:%ld",
740
s->buf.timestamp.tv_sec, s->buf.timestamp.tv_usec);
744
/* skip a few frames if needed */
745
for (i = 1; i < skip; i++)
746
v4l2_next(cnt, viddev, map, width, height);
748
/* No round robin - we only adjust picture controls */
749
v4l2_picture_controls(cnt, viddev);
753
int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height)
756
src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
758
if (viddev->v4l_fmt != VIDEO_PALETTE_YUV420P) {
759
return V4L_FATAL_ERROR;
762
/* Block signals during IOCTL */
764
sigaddset(&set, SIGCHLD);
765
sigaddset(&set, SIGALRM);
766
sigaddset(&set, SIGUSR1);
767
sigaddset(&set, SIGTERM);
768
sigaddset(&set, SIGHUP);
769
pthread_sigmask(SIG_BLOCK, &set, &old);
771
if (s->pframe >= 0) {
772
if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) {
773
motion_log(LOG_ERR, 0, "%s: VIDIOC_QBUF: %s", __FUNCTION__, strerror(errno));
778
memset(&s->buf, 0, sizeof(struct v4l2_buffer));
780
s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
781
s->buf.memory = V4L2_MEMORY_MMAP;
783
if (xioctl(s->fd, VIDIOC_DQBUF, &s->buf) == -1) {
785
/* some drivers return EIO when there is no signal,
786
driver might dequeue an (empty) buffer despite
787
returning an error, or even stop capturing.
791
if(s->pframe >= s->req.count) s->pframe=0;
792
s->buf.index = s->pframe;
794
motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: EIO (s->pframe %d)", __FUNCTION__,s->pframe);
799
motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: %s", __FUNCTION__, strerror(errno));
804
s->pframe = s->buf.index;
805
s->buffers[s->buf.index].used = s->buf.bytesused;
806
s->buffers[s->buf.index].content_length = s->buf.bytesused;
808
pthread_sigmask(SIG_UNBLOCK, &old, NULL); /*undo the signal blocking */
811
netcam_buff *the_buffer = &s->buffers[s->buf.index];
813
switch (s->fmt.fmt.pix.pixelformat) {
814
case V4L2_PIX_FMT_RGB24:
815
conv_rgb24toyuv420p(map, (unsigned char *) the_buffer->ptr, width, height);
818
case V4L2_PIX_FMT_UYVY:
819
conv_uyvyto420p(map, (unsigned char *) the_buffer->ptr, (unsigned)width, (unsigned)height);
822
case V4L2_PIX_FMT_YUYV:
823
case V4L2_PIX_FMT_YUV422P:
824
conv_yuv422to420p(map, (unsigned char *) the_buffer->ptr, width, height);
827
case V4L2_PIX_FMT_YUV420:
828
memcpy(map, the_buffer->ptr, viddev->v4l_bufsize); // ? s->buffer[s->buf.index].size;
830
case V4L2_PIX_FMT_MJPEG:
832
mjpegtoyuv420p(map, (unsigned char *) the_buffer->ptr, width, height, s->buffers[s->buf.index].content_length);
835
case V4L2_PIX_FMT_JPEG:
836
return conv_jpeg2yuv420(cnt, map, the_buffer, width, height);
838
case V4L2_PIX_FMT_SBGGR8: /* bayer */
839
bayer2rgb24(cnt->imgs.common_buffer, (unsigned char *) the_buffer->ptr, width, height);
840
conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height);
843
case V4L2_PIX_FMT_SN9C10X:
844
//sonix_decompress_init(); // now it is not necessary to call it every time
845
sonix_decompress(map, (unsigned char *) the_buffer->ptr, width, height);
846
bayer2rgb24(cnt->imgs.common_buffer, map, width, height);
847
conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height);
855
void v4l2_close(struct video_dev *viddev)
857
src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
858
enum v4l2_buf_type type;
860
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
861
xioctl(s->fd, VIDIOC_STREAMOFF, &type);
866
void v4l2_cleanup(struct video_dev *viddev)
868
src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
873
for (i = 0; i < s->req.count; i++)
874
munmap(s->buffers[i].ptr, s->buffers[i].size);
885
viddev->v4l2_private = NULL;