~ubuntu-branches/ubuntu/karmic/motion/karmic-proposed

« back to all changes in this revision

Viewing changes to video2.c

  • Committer: Bazaar Package Importer
  • Author(s): Juan Angulo Moreno
  • Date: 2008-06-10 09:15:47 UTC
  • mfrom: (4.1.4 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080610091547-2dcuzqpznlivgvxl
Tags: 3.2.9-4
* Fixed errors in the file debian/rules that affected the non-apply of 
  two patches (01_ffmpeg_creation_update_API.dpatch and 
  02_webhttpd_security_video2_backport.dpatch) (Closes: #484566).
* Bumped Standards-Version to 3.8.0. No changes to package necessary.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      video2.c
 
3
 *
 
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)
 
7
 
 
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 )
 
15
                V4L2_PIX_FMT_RGB24,
 
16
                V4L2_PIX_FMT_UYVY,      ( tested )
 
17
                V4L2_PIX_FMT_YUV422P,
 
18
                V4L2_PIX_FMT_YUV420,    ( tested )
 
19
                V4L2_PIX_FMT_YUYV       ( tested )
 
20
 
 
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 )
 
25
 
 
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)
 
28
 
 
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.
 
34
 
 
35
 *
 
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.
 
40
 *
 
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
 
44
 * for more details.
 
45
 
 
46
 let's go :)
 
47
*/
 
48
 
 
49
#ifndef WITHOUT_V4L
 
50
#ifdef MOTION_V4L2
 
51
#               warning **************************************************
 
52
#               warning         Using experimental V4L2 support
 
53
#               warning **************************************************
 
54
 
 
55
#include <math.h>
 
56
#include <sys/utsname.h>
 
57
#include <dirent.h>
 
58
#include <stdio.h>
 
59
#include <stdlib.h>
 
60
#include <fcntl.h>
 
61
#include <unistd.h>
 
62
#include <malloc.h>
 
63
#include <string.h>
 
64
#include <errno.h>
 
65
#include <sys/ioctl.h>
 
66
#include <sys/mman.h>
 
67
 
 
68
#include "motion.h"
 
69
#include "netcam.h"
 
70
#include "video.h"
 
71
#include "rotate.h"
 
72
 
 
73
#ifdef MOTION_V4L2_OLD
 
74
// Seems that is needed for some system
 
75
#include <linux/time.h>
 
76
#include <linux/videodev2.h>
 
77
#endif
 
78
 
 
79
#define u8 unsigned char
 
80
#define u16 unsigned short
 
81
#define u32 unsigned int
 
82
 
 
83
#define MMAP_BUFFERS 4
 
84
#define MIN_MMAP_BUFFERS 2
 
85
 
 
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.. */
 
89
#endif
 
90
 
 
91
#ifndef V4L2_PIX_FMT_MJPEG
 
92
#define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M','J','P','G')      /* Motion-JPEG   */
 
93
#endif
 
94
 
 
95
#ifndef V4L2_PIX_FMT_SN9C10X
 
96
#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0')       /* SN9C10x compression */
 
97
#endif
 
98
 
 
99
#define ZC301_V4L2_CID_DAC_MAGN         V4L2_CID_PRIVATE_BASE
 
100
#define ZC301_V4L2_CID_GREEN_BALANCE    (V4L2_CID_PRIVATE_BASE+1)
 
101
 
 
102
static const u32 queried_ctrls[] = {
 
103
        V4L2_CID_BRIGHTNESS,
 
104
        V4L2_CID_CONTRAST,
 
105
        V4L2_CID_SATURATION,
 
106
        V4L2_CID_HUE,
 
107
 
 
108
        V4L2_CID_RED_BALANCE,
 
109
        V4L2_CID_BLUE_BALANCE,
 
110
        V4L2_CID_GAMMA,
 
111
        V4L2_CID_EXPOSURE,
 
112
        V4L2_CID_AUTOGAIN,
 
113
        V4L2_CID_GAIN,
 
114
 
 
115
        ZC301_V4L2_CID_DAC_MAGN,
 
116
        ZC301_V4L2_CID_GREEN_BALANCE,
 
117
        0
 
118
};
 
119
 
 
120
typedef struct {
 
121
 
 
122
        int fd;
 
123
        char map;
 
124
        int fps;
 
125
 
 
126
        struct v4l2_capability cap;
 
127
        struct v4l2_format fmt;
 
128
        struct v4l2_requestbuffers req;
 
129
        struct v4l2_buffer buf;
 
130
 
 
131
        netcam_buff *buffers;
 
132
 
 
133
        int pframe;
 
134
 
 
135
        u32 ctrl_flags;
 
136
        struct v4l2_queryctrl *controls;
 
137
 
 
138
} src_v4l2_t;
 
139
 
 
140
static int xioctl(int fd, int request, void *arg)
 
141
{
 
142
        int r;
 
143
 
 
144
        do
 
145
                r = ioctl(fd, request, arg);
 
146
        while (-1 == r && EINTR == errno);
 
147
 
 
148
        return r;
 
149
}
 
150
 
 
151
static int v4l2_get_capability(src_v4l2_t * s)
 
152
{
 
153
 
 
154
        if (xioctl(s->fd, VIDIOC_QUERYCAP, &s->cap) < 0) {
 
155
                motion_log(LOG_ERR, 0, "Not a V4L2 device?");
 
156
                return (-1);
 
157
        }
 
158
 
 
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);
 
163
 
 
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");
 
188
 
 
189
        if (!s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
 
190
                motion_log(LOG_ERR, 0, "Device does not support capturing.");
 
191
                return (-1);
 
192
        }
 
193
 
 
194
        return (0);
 
195
}
 
196
 
 
197
static int v4l2_select_input(src_v4l2_t * s, int in, int norm, unsigned long freq_, int tuner_number)
 
198
{
 
199
        struct v4l2_input input;
 
200
        struct v4l2_standard standard;
 
201
        v4l2_std_id std_id;
 
202
 
 
203
        if (in == 8)
 
204
                in = 0;
 
205
 
 
206
        /* Set the input. */
 
207
        input.index = in;
 
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));
 
211
                return (-1);
 
212
        }
 
213
 
 
214
        if (debug_level > 5)
 
215
                motion_log(LOG_INFO, 0, "%s: name = \"%s\", type 0x%08X, status %08x", __FUNCTION__, input.name, input.type,
 
216
                        input.status);
 
217
 
 
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");
 
222
 
 
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));
 
226
                return (-1);
 
227
        }
 
228
 
 
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) {
 
231
                if (debug_level > 5)
 
232
                        motion_log(LOG_INFO, 0, "Device doesn't support VIDIOC_G_STD ");
 
233
                std_id = 0;     // V4L2_STD_UNKNOWN = 0
 
234
        }
 
235
 
 
236
        if (std_id) {
 
237
                memset(&standard, 0, sizeof(standard));
 
238
                standard.index = 0;
 
239
 
 
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);
 
243
                        }
 
244
                        standard.index++;
 
245
                }
 
246
 
 
247
                switch (norm) {
 
248
                case 1:
 
249
                        std_id = V4L2_STD_NTSC;
 
250
                        break;
 
251
                case 2:
 
252
                        std_id = V4L2_STD_SECAM;
 
253
                        break;
 
254
                default:
 
255
                        std_id = V4L2_STD_PAL;
 
256
                }
 
257
 
 
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));
 
261
                }
 
262
        }
 
263
 
 
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;
 
268
 
 
269
                /* Query the tuners capabilities. */
 
270
 
 
271
                memset(&tuner, 0, sizeof(struct v4l2_tuner));
 
272
                tuner.index = input.tuner;
 
273
 
 
274
                if (xioctl(s->fd, VIDIOC_G_TUNER, &tuner) == -1) {
 
275
                        motion_log(LOG_ERR, 0, "VIDIOC_G_TUNER: %s", strerror(errno));
 
276
                        return (0);
 
277
                }
 
278
 
 
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;
 
284
 
 
285
                if (xioctl(s->fd, VIDIOC_S_FREQUENCY, &freq) == -1) {
 
286
                        motion_log(LOG_ERR, 0, "VIDIOC_S_FREQUENCY: %s", strerror(errno));
 
287
                        return (0);
 
288
                }
 
289
        }
 
290
 
 
291
        return (0);
 
292
}
 
293
 
 
294
static int v4l2_set_pix_format(src_v4l2_t * s, int *width, int *height)
 
295
{
 
296
        struct v4l2_fmtdesc fmt;
 
297
        int v4l2_pal;
 
298
 
 
299
        static const u32 supported_formats[] = {        /* higher index means better chance to be used */
 
300
                V4L2_PIX_FMT_SN9C10X,
 
301
                V4L2_PIX_FMT_SBGGR8,
 
302
                V4L2_PIX_FMT_MJPEG,
 
303
                V4L2_PIX_FMT_JPEG,
 
304
                V4L2_PIX_FMT_RGB24,
 
305
                V4L2_PIX_FMT_UYVY,
 
306
                V4L2_PIX_FMT_YUYV,
 
307
                V4L2_PIX_FMT_YUV422P,
 
308
                V4L2_PIX_FMT_YUV420,
 
309
                0
 
310
        };
 
311
 
 
312
        int index_format = -1;
 
313
 
 
314
        memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
 
315
        fmt.index = v4l2_pal = 0;
 
316
        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
317
 
 
318
        motion_log(LOG_INFO, 0, "Supported palettes:");
 
319
        while (xioctl(s->fd, VIDIOC_ENUM_FMT, &fmt) != -1) {
 
320
                int i;
 
321
 
 
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);
 
325
 
 
326
                for (i = 0; supported_formats[i]; i++)
 
327
                        if (supported_formats[i] == fmt.pixelformat && i > index_format) {
 
328
                                index_format = i;
 
329
                        }
 
330
 
 
331
                memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
 
332
                fmt.index = ++v4l2_pal;
 
333
                fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
334
        }
 
335
 
 
336
        if (index_format >= 0) {
 
337
                
 
338
                u32 pixformat = supported_formats[index_format];
 
339
 
 
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;
 
346
 
 
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);
 
349
 
 
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;
 
356
                        }
 
357
 
 
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));
 
361
                                return (-1);
 
362
                        }
 
363
 
 
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);
 
365
 
 
366
                        /* TODO: Review when it has been tested */
 
367
                        if (pixformat == V4L2_PIX_FMT_MJPEG) {
 
368
                                struct v4l2_jpegcompression v4l2_jpeg;
 
369
 
 
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");
 
372
                                } else {
 
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));
 
376
 
 
377
                                }
 
378
 
 
379
                        }
 
380
                        return 0;
 
381
                }
 
382
 
 
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));
 
385
 
 
386
                return -1;
 
387
        }
 
388
 
 
389
        motion_log(LOG_ERR, 0, "Unable to find a compatible palette format.");
 
390
        return (-1);
 
391
}
 
392
 
 
393
 
 
394
static void v4l2_set_fps(src_v4l2_t * s){
 
395
        struct v4l2_streamparm* setfps;
 
396
 
 
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));
 
404
        }
 
405
 
 
406
}
 
407
 
 
408
static int v4l2_set_mmap(src_v4l2_t * s)
 
409
{
 
410
        enum v4l2_buf_type type;
 
411
        u32 b;
 
412
 
 
413
        /* Does the device support streaming? */
 
414
        if (!s->cap.capabilities & V4L2_CAP_STREAMING)
 
415
                return (-1);
 
416
 
 
417
        memset(&s->req, 0, sizeof(struct v4l2_requestbuffers));
 
418
 
 
419
        s->req.count = MMAP_BUFFERS;
 
420
        s->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
421
        s->req.memory = V4L2_MEMORY_MMAP;
 
422
 
 
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));
 
426
                return (-1);
 
427
        }
 
428
 
 
429
        motion_log(LOG_DEBUG, 0, "mmap information:");
 
430
        motion_log(LOG_DEBUG, 0, "frames=%d", s->req.count);
 
431
 
 
432
        if (s->req.count < MIN_MMAP_BUFFERS) {
 
433
                motion_log(LOG_ERR, 0, "Insufficient buffer memory.");
 
434
                return (-1);
 
435
        }
 
436
 
 
437
        s->buffers = calloc(s->req.count, sizeof(netcam_buff));
 
438
        if (!s->buffers) {
 
439
                motion_log(LOG_ERR, 1, "%s: Out of memory.", __FUNCTION__);
 
440
                return (-1);
 
441
        }
 
442
 
 
443
        for (b = 0; b < s->req.count; b++) {
 
444
                struct v4l2_buffer buf;
 
445
 
 
446
                memset(&buf, 0, sizeof(struct v4l2_buffer));
 
447
 
 
448
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
449
                buf.memory = V4L2_MEMORY_MMAP;
 
450
                buf.index = b;
 
451
 
 
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));
 
455
                        free(s->buffers);
 
456
                        return (-1);
 
457
                }
 
458
 
 
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);
 
461
 
 
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));
 
465
                        free(s->buffers);
 
466
                        return (-1);
 
467
                }
 
468
 
 
469
                motion_log(LOG_DEBUG, 0, "%i length=%d", b, buf.length);
 
470
        }
 
471
 
 
472
        s->map = -1;
 
473
 
 
474
        for (b = 0; b < s->req.count; b++) {
 
475
                memset(&s->buf, 0, sizeof(struct v4l2_buffer));
 
476
 
 
477
                s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
478
                s->buf.memory = V4L2_MEMORY_MMAP;
 
479
                s->buf.index = b;
 
480
 
 
481
                if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) {
 
482
                        motion_log(LOG_ERR, 0, "VIDIOC_QBUF: %s", strerror(errno));
 
483
                        return (-1);
 
484
                }
 
485
        }
 
486
 
 
487
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
488
 
 
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));
 
492
                return (-1);
 
493
        }
 
494
 
 
495
        return (0);
 
496
}
 
497
 
 
498
static int v4l2_scan_controls(src_v4l2_t * s)
 
499
{
 
500
        int count, i;
 
501
        struct v4l2_queryctrl queryctrl;
 
502
 
 
503
        memset(&queryctrl, 0, sizeof(struct v4l2_queryctrl));
 
504
 
 
505
        for (i = 0, count = 0; queried_ctrls[i]; i++) {
 
506
                queryctrl.id = queried_ctrls[i];
 
507
                if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl))
 
508
                        continue;
 
509
 
 
510
                count++;
 
511
                s->ctrl_flags |= 1 << i;
 
512
        }
 
513
 
 
514
        if (count) {
 
515
                struct v4l2_queryctrl *ctrl = s->controls = calloc(count, sizeof(struct v4l2_queryctrl));
 
516
 
 
517
                if (!ctrl) {
 
518
                        motion_log(LOG_ERR, 0, "%s: Insufficient buffer memory.", __FUNCTION__);
 
519
                        return (-1);
 
520
                }
 
521
 
 
522
                for (i = 0; queried_ctrls[i]; i++) {
 
523
                        if (s->ctrl_flags & (1 << i)) {
 
524
                                struct v4l2_control control;
 
525
 
 
526
                                queryctrl.id = queried_ctrls[i];
 
527
                                if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl))
 
528
                                        continue;
 
529
 
 
530
                                memcpy(ctrl, &queryctrl, sizeof(struct v4l2_queryctrl));
 
531
 
 
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!" : "");
 
535
 
 
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);
 
540
 
 
541
                                ctrl++;
 
542
                        }
 
543
                }
 
544
        }
 
545
 
 
546
        return 0;
 
547
}
 
548
 
 
549
static int v4l2_set_control(src_v4l2_t * s, u32 cid, int value)
 
550
{
 
551
        int i, count;
 
552
 
 
553
        if (!s->controls)
 
554
                return -1;
 
555
 
 
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;
 
561
                                int ret;
 
562
 
 
563
                                control.id = queried_ctrls[i];
 
564
 
 
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);
 
570
                                        break;
 
571
 
 
572
                                case V4L2_CTRL_TYPE_BOOLEAN:
 
573
                                        value = control.value = value ? 1 : 0;
 
574
                                        ret = xioctl(s->fd, VIDIOC_S_CTRL, &control);
 
575
                                        break;
 
576
 
 
577
                                default:
 
578
                                        motion_log(LOG_ERR, 0, "%s: control type not supported yet");
 
579
                                        return -1;
 
580
                                }
 
581
 
 
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!" : "");
 
585
 
 
586
                                return 0;
 
587
                        }
 
588
                        count++;
 
589
                }
 
590
        }
 
591
 
 
592
        return -1;
 
593
}
 
594
 
 
595
static void v4l2_picture_controls(struct context *cnt, struct video_dev *viddev)
 
596
{
 
597
        src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
 
598
 
 
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);
 
602
        }
 
603
 
 
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);
 
607
        }
 
608
 
 
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);
 
612
        }
 
613
 
 
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);
 
618
                }
 
619
        } else {
 
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);
 
624
                }
 
625
        }
 
626
 
 
627
}
 
628
 
 
629
/* public functions */
 
630
 
 
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)
 
633
{
 
634
        src_v4l2_t *s;
 
635
 
 
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__);
 
639
                goto err;
 
640
        }
 
641
 
 
642
        viddev->v4l2_private = s;
 
643
        s->fd = viddev->fd;
 
644
        s->fps = cnt->conf.frame_limit;
 
645
        s->pframe = -1;
 
646
 
 
647
        if (v4l2_get_capability(s)) {
 
648
                goto err;
 
649
        }
 
650
 
 
651
        if (v4l2_select_input(s, input, norm, freq, tuner_number)) {
 
652
                goto err;
 
653
        }
 
654
 
 
655
        if (v4l2_set_pix_format(s, &width, &height)) {
 
656
                goto err;
 
657
        }
 
658
 
 
659
        if (v4l2_scan_controls(s)) {
 
660
                goto err;
 
661
        }
 
662
 
 
663
#if 0
 
664
        v4l2_set_fps(s);
 
665
#endif
 
666
        if (v4l2_set_mmap(s)) {
 
667
                goto err;
 
668
        }
 
669
 
 
670
        viddev->size_map = 0;
 
671
        viddev->v4l_buffers[0] = NULL;
 
672
        viddev->v4l_maxbuffer = 1;
 
673
        viddev->v4l_curbuffer = 0;
 
674
 
 
675
        viddev->v4l_fmt = VIDEO_PALETTE_YUV420P;
 
676
        viddev->v4l_bufsize = (width * height * 3) / 2;
 
677
 
 
678
 
 
679
        /* Update width and height with supported values from camera driver */
 
680
        viddev->width = width;
 
681
        viddev->height = height;
 
682
 
 
683
        return (void *) 1;
 
684
 
 
685
      err:
 
686
        if (s)
 
687
                free(s);
 
688
        viddev->v4l2_private = NULL;
 
689
        viddev->v4l2 = 0;
 
690
        return NULL;
 
691
}
 
692
 
 
693
void v4l2_set_input(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height,
 
694
                    struct config *conf)
 
695
{
 
696
        int i;
 
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;
 
702
 
 
703
        if (input != viddev->input || width != viddev->width || height != viddev->height ||
 
704
            freq != viddev->freq || tuner_number != viddev->tuner_number) {
 
705
 
 
706
                struct timeval switchTime;
 
707
 
 
708
                v4l2_select_input((src_v4l2_t *) viddev->v4l2_private, input, norm, freq, tuner_number);
 
709
 
 
710
                gettimeofday(&switchTime, NULL);
 
711
 
 
712
                v4l2_picture_controls(cnt, viddev);
 
713
 
 
714
                viddev->input = input;
 
715
                viddev->width = width;
 
716
                viddev->height = height;
 
717
                viddev->freq = freq;
 
718
                viddev->tuner_number = tuner_number;
 
719
 
 
720
 
 
721
                /* Skip all frames captured before switchtime, capture 1 after switchtime */
 
722
                {
 
723
                        src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
 
724
                        unsigned int counter = 0;
 
725
                        if (debug_level > 5)
 
726
                                motion_log(LOG_DEBUG, 0, "set_input_skip_frame switch_time=%ld:%ld", 
 
727
                                                switchTime.tv_sec, switchTime.tv_usec);
 
728
 
 
729
                        /* Avoid hang using the number of mmap buffers */
 
730
                        while(counter < s->req.count)
 
731
                        {
 
732
                                counter++;
 
733
                                if (v4l2_next(cnt, viddev, map, width, height))
 
734
                                        break;
 
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))
 
737
                                        break;
 
738
                                if (debug_level > 5)
 
739
                                        motion_log(LOG_DEBUG, 0, "got frame before switch timestamp=%ld:%ld", 
 
740
                                                        s->buf.timestamp.tv_sec, s->buf.timestamp.tv_usec);
 
741
                        }
 
742
                }
 
743
 
 
744
                /* skip a few frames if needed */
 
745
                for (i = 1; i < skip; i++)
 
746
                        v4l2_next(cnt, viddev, map, width, height);
 
747
        } else {
 
748
                /* No round robin - we only adjust picture controls */
 
749
                v4l2_picture_controls(cnt, viddev);
 
750
        }
 
751
}
 
752
 
 
753
int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height)
 
754
{
 
755
        sigset_t set, old;
 
756
        src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
 
757
 
 
758
        if (viddev->v4l_fmt != VIDEO_PALETTE_YUV420P) {
 
759
                return V4L_FATAL_ERROR;
 
760
        }
 
761
 
 
762
        /* Block signals during IOCTL */
 
763
        sigemptyset(&set);
 
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);
 
770
 
 
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));
 
774
                        return (-1);
 
775
                }
 
776
        }
 
777
 
 
778
        memset(&s->buf, 0, sizeof(struct v4l2_buffer));
 
779
 
 
780
        s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
781
        s->buf.memory = V4L2_MEMORY_MMAP;
 
782
 
 
783
        if (xioctl(s->fd, VIDIOC_DQBUF, &s->buf) == -1) {
 
784
 
 
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.
 
788
                */
 
789
                if ( errno == EIO ){
 
790
                        s->pframe++; 
 
791
                        if(s->pframe >= s->req.count) s->pframe=0;
 
792
                        s->buf.index = s->pframe;
 
793
                
 
794
                        motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: EIO (s->pframe %d)", __FUNCTION__,s->pframe);
 
795
        
 
796
                        return (1);
 
797
                }
 
798
 
 
799
                motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: %s", __FUNCTION__, strerror(errno));
 
800
 
 
801
                return (-1);
 
802
        }
 
803
 
 
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;
 
807
 
 
808
        pthread_sigmask(SIG_UNBLOCK, &old, NULL);       /*undo the signal blocking */
 
809
 
 
810
        {
 
811
                netcam_buff *the_buffer = &s->buffers[s->buf.index];
 
812
 
 
813
                switch (s->fmt.fmt.pix.pixelformat) {
 
814
                case V4L2_PIX_FMT_RGB24:
 
815
                        conv_rgb24toyuv420p(map, (unsigned char *) the_buffer->ptr, width, height);
 
816
                        return 0;
 
817
 
 
818
                case V4L2_PIX_FMT_UYVY:
 
819
                        conv_uyvyto420p(map, (unsigned char *) the_buffer->ptr, (unsigned)width, (unsigned)height);
 
820
                        return 0;
 
821
 
 
822
                case V4L2_PIX_FMT_YUYV:
 
823
                case V4L2_PIX_FMT_YUV422P:
 
824
                        conv_yuv422to420p(map, (unsigned char *) the_buffer->ptr, width, height);
 
825
                        return 0;
 
826
 
 
827
                case V4L2_PIX_FMT_YUV420:
 
828
                        memcpy(map, the_buffer->ptr, viddev->v4l_bufsize);      // ? s->buffer[s->buf.index].size;
 
829
                        return 0;
 
830
                case V4L2_PIX_FMT_MJPEG:
 
831
#ifdef MJPEGT
 
832
                        mjpegtoyuv420p(map, (unsigned char *) the_buffer->ptr, width, height, s->buffers[s->buf.index].content_length);
 
833
                        return 0;
 
834
#endif
 
835
                case V4L2_PIX_FMT_JPEG:
 
836
                        return conv_jpeg2yuv420(cnt, map, the_buffer, width, height);
 
837
 
 
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);
 
841
                        return 0;
 
842
 
 
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);
 
848
                        return 0;
 
849
                }
 
850
        }
 
851
 
 
852
        return 1;
 
853
}
 
854
 
 
855
void v4l2_close(struct video_dev *viddev)
 
856
{
 
857
        src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
 
858
        enum v4l2_buf_type type;
 
859
 
 
860
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
861
        xioctl(s->fd, VIDIOC_STREAMOFF, &type);
 
862
        close(s->fd);
 
863
        s->fd = -1;
 
864
}
 
865
 
 
866
void v4l2_cleanup(struct video_dev *viddev)
 
867
{
 
868
        src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private;
 
869
 
 
870
        if (s->buffers) {
 
871
                unsigned int i;
 
872
 
 
873
                for (i = 0; i < s->req.count; i++)
 
874
                        munmap(s->buffers[i].ptr, s->buffers[i].size);
 
875
                free(s->buffers);
 
876
                s->buffers = NULL;
 
877
        }
 
878
 
 
879
        if (s->controls) {
 
880
                free(s->controls);
 
881
                s->controls = NULL;
 
882
        }
 
883
 
 
884
        free(s);
 
885
        viddev->v4l2_private = NULL;
 
886
}
 
887
 
 
888
#endif
 
889
#endif