Statistics
| Branch: | Revision:

chunker-player / capture / video.c @ 1e69ae95

History | View | Annotate | Download (12.8 KB)

1
#include "video.h"
2
#include "capture.h"
3

    
4
void errno_exit (const char * s)
5
{
6
    fprintf (stderr, "%s error %d, %s\n", s, errno, strerror (errno));
7
    exit (EXIT_FAILURE);
8
}
9

    
10
static int xioctl (int fd, int request, void *arg)
11
{
12
    int r;
13

    
14
    do r = ioctl (fd, request, arg);
15
    while (-1 == r && EINTR == errno);
16

    
17
    return r;
18
}
19

    
20
int read_frame(void)
21
{
22
    struct v4l2_buffer buf;
23
    unsigned int i;
24

    
25
    switch (io) {
26
        case IO_METHOD_READ:
27
            if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
28
                switch (errno) {
29
                    case EAGAIN:
30
                        return 0;
31

    
32
                    case EIO:
33
                            /* Could ignore EIO, see spec. */
34

    
35
                            /* fall through */
36

    
37
                    default:
38
                        errno_exit ("read");
39
                }
40
            }
41

    
42
            process_frame (buffers[0].start, 0, &fmt);
43

    
44
            break;
45

    
46
        case IO_METHOD_MMAP:
47
            CLEAR (buf);
48

    
49
            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
50
            buf.memory = V4L2_MEMORY_MMAP;
51

    
52
            if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
53
                switch (errno) {
54
                    case EAGAIN:
55
                        return 0;
56

    
57
                    case EIO:
58
                            /* Could ignore EIO, see spec. */
59

    
60
                            /* fall through */
61

    
62
                    default:
63
                        errno_exit ("VIDIOC_DQBUF");
64
                }
65
            }
66

    
67
            assert (buf.index < n_buffers);
68

    
69
            process_frame (buffers[buf.index].start, buf.bytesused, &fmt);
70

    
71
            if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
72
                errno_exit ("VIDIOC_QBUF");
73

    
74
            break;
75

    
76
        case IO_METHOD_USERPTR:
77
            CLEAR (buf);
78

    
79
            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
80
            buf.memory = V4L2_MEMORY_USERPTR;
81

    
82
            if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
83
                switch (errno) {
84
                    case EAGAIN:
85
                        return 0;
86

    
87
                    case EIO:
88
                            /* Could ignore EIO, see spec. */
89

    
90
                            /* fall through */
91

    
92
                    default:
93
                        errno_exit ("VIDIOC_DQBUF");
94
                }
95
            }
96

    
97
            for (i = 0; i < n_buffers; ++i)
98
                if (buf.m.userptr == (unsigned long) buffers[i].start && buf.length == buffers[i].length)
99
                    break;
100

    
101
            assert (i < n_buffers);
102

    
103
            process_frame ((void *) buf.m.userptr, buf.bytesused, &fmt);
104

    
105
            if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
106
                errno_exit ("VIDIOC_QBUF");
107

    
108
            break;
109
    }
110

    
111
    return 1;
112
}
113

    
114
void mainloop (void)
115
{
116
    while(1)
117
    {
118
        int r = poll_video_device();
119

    
120
        if (-1 == r) {
121
            if (EINTR == errno)
122
                continue;
123

    
124
            errno_exit ("select");
125
        }
126

    
127
        if (0 == r) {
128
            fprintf (stderr, "select timeout\n");
129
            exit (EXIT_FAILURE);
130
        }
131

    
132
        read_frame();
133

    
134
        /* EAGAIN - continue select loop. */
135
    }
136
}
137

    
138
int poll_video_device(void)
139
{
140
    fd_set fds;
141
    struct timeval tv;
142
    int r;
143

    
144
    FD_ZERO (&fds);
145
    FD_SET (fd, &fds);
146

    
147
    /* Timeout. */
148
    tv.tv_sec = 2;
149
    tv.tv_usec = 0;
150

    
151
    return select (fd + 1, &fds, NULL, NULL, &tv);
152
}
153

    
154
void stop_video_capturing(void)
155
{
156
    enum v4l2_buf_type type;
157

    
158
    switch (io) {
159
    case IO_METHOD_READ:
160
        /* Nothing to do. */
161
        break;
162

    
163
    case IO_METHOD_MMAP:
164
    case IO_METHOD_USERPTR:
165
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
166

    
167
        if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
168
            errno_exit ("VIDIOC_STREAMOFF");
169

    
170
        break;
171
    }
172
}
173

    
174
void start_video_capturing(void)
175
{
176
    unsigned int i;
177
    enum v4l2_buf_type type;
178

    
179
    switch (io)
180
    {
181
        case IO_METHOD_READ:
182
            /* Nothing to do. */
183
            break;
184

    
185
        case IO_METHOD_MMAP:
186
            for (i = 0; i < n_buffers; ++i) {
187
                struct v4l2_buffer buf;
188

    
189
                CLEAR (buf);
190

    
191
                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
192
                buf.memory      = V4L2_MEMORY_MMAP;
193
                buf.index       = i;
194

    
195
                if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
196
                    errno_exit ("VIDIOC_QBUF");
197
            }
198

    
199
            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
200

    
201
            if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
202
                errno_exit ("VIDIOC_STREAMON");
203

    
204
            break;
205

    
206
        case IO_METHOD_USERPTR:
207
            for (i = 0; i < n_buffers; ++i) {
208
                struct v4l2_buffer buf;
209

    
210
                CLEAR (buf);
211

    
212
                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
213
                buf.memory      = V4L2_MEMORY_USERPTR;
214
                buf.index       = i;
215
                buf.m.userptr        = (unsigned long) buffers[i].start;
216
                buf.length      = buffers[i].length;
217

    
218
                if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
219
                    errno_exit ("VIDIOC_QBUF");
220
            }
221

    
222
            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
223

    
224
            if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
225
                errno_exit ("VIDIOC_STREAMON");
226

    
227
            break;
228
    }
229
}
230

    
231
void uninit_video_device (void)
232
{
233
    unsigned int i;
234

    
235
    switch (io) {
236
    case IO_METHOD_READ:
237
        free (buffers[0].start);
238
        break;
239

    
240
    case IO_METHOD_MMAP:
241
        for (i = 0; i < n_buffers; ++i)
242
            if (-1 == munmap (buffers[i].start, buffers[i].length))
243
                errno_exit ("munmap");
244
        break;
245

    
246
    case IO_METHOD_USERPTR:
247
        for (i = 0; i < n_buffers; ++i)
248
            free (buffers[i].start);
249
        break;
250
    }
251

    
252
    free (buffers);
253
}
254

    
255
static void init_read(unsigned int buffer_size)
256
{
257
    buffers = calloc (1, sizeof (*buffers));
258

    
259
    if (!buffers) {
260
        fprintf (stderr, "Out of memory\n");
261
        exit (EXIT_FAILURE);
262
    }
263

    
264
    buffers[0].length = buffer_size;
265
    buffers[0].start = malloc (buffer_size);
266

    
267
    if (!buffers[0].start) {
268
        fprintf (stderr, "Out of memory\n");
269
        exit (EXIT_FAILURE);
270
    }
271
}
272

    
273
static void init_mmap(void)
274
{
275
    struct v4l2_requestbuffers req;
276

    
277
    CLEAR (req);
278

    
279
    req.count               = 4;
280
    req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
281
    req.memory              = V4L2_MEMORY_MMAP;
282

    
283
    if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
284
        if (EINVAL == errno)
285
        {
286
            fprintf (stderr, "%s does not support memory mapping\n", video_dev_name);
287
            exit (EXIT_FAILURE);
288
        }
289
        else
290
        {
291
            errno_exit ("VIDIOC_REQBUFS");
292
        }
293
    }
294

    
295
    if (req.count < 2)
296
    {
297
        fprintf (stderr, "Insufficient buffer memory on %s\n", video_dev_name);
298
        exit (EXIT_FAILURE);
299
    }
300

    
301
    buffers = calloc (req.count, sizeof (*buffers));
302

    
303
    if (!buffers) {
304
        fprintf (stderr, "Out of memory\n");
305
        exit (EXIT_FAILURE);
306
    }
307

    
308
    for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
309
        struct v4l2_buffer buf;
310

    
311
        CLEAR (buf);
312

    
313
        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
314
        buf.memory      = V4L2_MEMORY_MMAP;
315
        buf.index       = n_buffers;
316

    
317
        if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
318
            errno_exit ("VIDIOC_QUERYBUF");
319

    
320
        buffers[n_buffers].length = buf.length;
321
        buffers[n_buffers].start = mmap (NULL /* start anywhere */,
322
            buf.length,
323
            PROT_READ | PROT_WRITE /* required */,
324
            MAP_SHARED /* recommended */,
325
            fd, buf.m.offset);
326

    
327
        if (MAP_FAILED == buffers[n_buffers].start)
328
            errno_exit ("mmap");
329
    }
330
}
331

    
332
static void init_userp (unsigned int buffer_size)
333
{
334
    struct v4l2_requestbuffers req;
335
    unsigned int page_size;
336

    
337
    page_size = getpagesize ();
338
    buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
339

    
340
    CLEAR (req);
341

    
342
    req.count               = 4;
343
    req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
344
    req.memory              = V4L2_MEMORY_USERPTR;
345

    
346
    if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req))
347
    {
348
        if (EINVAL == errno)
349
        {
350
            fprintf (stderr, "%s does not support user pointer i/o\n", video_dev_name);
351
                exit (EXIT_FAILURE);
352
        } else {
353
            errno_exit ("VIDIOC_REQBUFS");
354
        }
355
    }
356

    
357
    buffers = calloc (4, sizeof (*buffers));
358

    
359
    if (!buffers) {
360
        fprintf (stderr, "Out of memory\n");
361
        exit (EXIT_FAILURE);
362
    }
363

    
364
    for (n_buffers = 0; n_buffers < 4; ++n_buffers)
365
    {
366
        buffers[n_buffers].length = buffer_size;
367
        buffers[n_buffers].start = memalign (/* boundary */ page_size, buffer_size);
368

    
369
        if (!buffers[n_buffers].start) {
370
            fprintf (stderr, "Out of memory\n");
371
            exit (EXIT_FAILURE);
372
        }
373
    }
374
}
375

    
376
void init_video_device (void)
377
{
378
    struct v4l2_capability cap;
379
    struct v4l2_cropcap cropcap;
380
    struct v4l2_crop crop;
381
    unsigned int min;
382

    
383
    if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
384
        if (EINVAL == errno) {
385
            fprintf (stderr, "%s is no V4L2 device\n", video_dev_name);
386
            exit (EXIT_FAILURE);
387
        } else {
388
            errno_exit ("VIDIOC_QUERYCAP");
389
        }
390
    }
391

    
392
    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
393
        fprintf (stderr, "%s is no video capture device\n", video_dev_name);
394
        exit (EXIT_FAILURE);
395
    }
396

    
397
    switch (io) {
398
        case IO_METHOD_READ:
399
            if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
400
                fprintf (stderr, "%s does not support read i/o\n", video_dev_name);
401
                exit (EXIT_FAILURE);
402
            }
403

    
404
            break;
405

    
406
        case IO_METHOD_MMAP:
407
        case IO_METHOD_USERPTR:
408
            if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
409
                fprintf (stderr, "%s does not support streaming i/o\n", video_dev_name);
410
                exit (EXIT_FAILURE);
411
            }
412

    
413
            break;
414
    }
415

    
416

    
417
    /* Select video input, video standard and tune here. */
418

    
419

    
420
    CLEAR (cropcap);
421

    
422
    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
423

    
424
    if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
425
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
426
        crop.c = cropcap.defrect; /* reset to default */
427

    
428
        if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
429
            switch (errno) {
430
                case EINVAL:
431
                    /* Cropping not supported. */
432
                    break;
433
                default:
434
                    /* Errors ignored. */
435
                    break;
436
            }
437
        }
438
    } else {
439
            /* Errors ignored. */
440
    }
441

    
442

    
443
    CLEAR (fmt);
444

    
445

    
446
/*
447
    fmt.pix.bytesperline    : 1280
448
    fmt.pix.sizeimage       : 4094874830
449
    fmt.pix.colorspace      : unknown
450
    fmt.pix.priv            : 0
451
*/
452

    
453

    
454
    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
455
    fmt.fmt.pix.width       = WIDTH;
456
    fmt.fmt.pix.height      = HEIGHT;
457
    fmt.fmt.pix.pixelformat = video_format;
458
    fmt.fmt.pix.field       = V4L2_FIELD_ANY;
459

    
460
    //printf("trying %d, %d, %d, %d, %d\n", fmt.type, fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.pixelformat, fmt.fmt.pix.field);
461

    
462
    if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
463
        errno_exit ("VIDIOC_S_FMT");
464

    
465
    //printf("get %d, %d, %d, %d, %d\n", fmt.type, fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.pixelformat, fmt.fmt.pix.field);
466

    
467
    if (fmt.fmt.pix.pixelformat != video_format)
468
    {
469
        printf("Device driver didn't accept selected video format. Can't proceed.\n");
470
        exit(EXIT_FAILURE);
471
    }
472

    
473
    if ((fmt.fmt.pix.width != WIDTH) || (fmt.fmt.pix.height != HEIGHT))
474
        printf("Warning: driver is sending image at %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
475

    
476

    
477
    /* Note VIDIOC_S_FMT may change width and height. */
478

    
479
    /* Buggy driver paranoia. */
480
    min = fmt.fmt.pix.width * 2;
481
    if (fmt.fmt.pix.bytesperline < min)
482
        fmt.fmt.pix.bytesperline = min;
483
    min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
484
    if (fmt.fmt.pix.sizeimage < min)
485
        fmt.fmt.pix.sizeimage = min;
486

    
487
    switch (io)
488
    {
489
        case IO_METHOD_READ:
490
            init_read (fmt.fmt.pix.sizeimage);
491
            break;
492

    
493
        case IO_METHOD_MMAP:
494
            init_mmap ();
495
            break;
496

    
497
        case IO_METHOD_USERPTR:
498
            init_userp (fmt.fmt.pix.sizeimage);
499
            break;
500
    }
501
}
502

    
503
void close_video_device (void)
504
{
505
    if (-1 == close (fd))
506
        errno_exit ("close");
507

    
508
    fd = -1;
509
}
510

    
511
void open_video_device (void)
512
{
513
    struct stat st;
514

    
515
    if (-1 == stat (video_dev_name, &st)) {
516
        fprintf (stderr, "Cannot identify '%s': %d, %s\n",video_dev_name, errno, strerror (errno));
517
        exit (EXIT_FAILURE);
518
    }
519

    
520
    if (!S_ISCHR (st.st_mode)) {
521
        fprintf (stderr, "%s is no device\n", video_dev_name);
522
        exit (EXIT_FAILURE);
523
    }
524

    
525
    fd = open (video_dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
526

    
527
    if (-1 == fd)
528
    {
529
        fprintf (stderr, "Cannot open '%s': %d, %s\n", video_dev_name, errno, strerror (errno));
530
        exit (EXIT_FAILURE);
531
    }
532
}