1 /* G-Streamer Video4linux2 video-capture plugin - system calls
2 * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
25 #include <sys/types.h>
28 #include <sys/ioctl.h>
32 #include "v4l2src_calls.h"
36 #define GST_CAT_DEFAULT v4l2src_debug
39 #define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1)
40 #define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL
42 #define DEBUG(format, args...) \
43 GST_CAT_DEBUG_OBJECT (\
44 v4l2src_debug, v4l2src, \
45 "V4L2SRC: " format, ##args)
47 /* On some systems MAP_FAILED seems to be missing */
49 #define MAP_FAILED ( (caddr_t) -1 )
52 /******************************************************
53 * gst_v4l2src_fill_format_list():
54 * create list of supported capture formats
55 * return value: TRUE on success, FALSE on error
56 ******************************************************/
59 gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
62 struct v4l2_fmtdesc *format;
64 GST_DEBUG_OBJECT (v4l2src, "getting src format enumerations");
66 /* format enumeration */
68 format = g_new (struct v4l2_fmtdesc, 1);
71 format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
72 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_ENUM_FMT,
74 if (errno == EINVAL) {
75 break; /* end of enumeration */
77 GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
78 ("failed to get number %d in pixelformat enumeration for %s: %s",
79 n, GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
84 GST_LOG_OBJECT (v4l2src, "got format" GST_FOURCC_FORMAT,
85 GST_FOURCC_ARGS (format->pixelformat));
86 v4l2src->formats = g_slist_prepend (v4l2src->formats, format);
93 /******************************************************
94 * gst_v4l2src_clear_format_list():
95 * free list of supported capture formats
96 * return value: TRUE on success, FALSE on error
97 ******************************************************/
100 gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
102 g_slist_foreach (v4l2src->formats, (GFunc) g_free, NULL);
103 g_slist_free (v4l2src->formats);
109 /******************************************************
110 * gst_v4l2src_queue_frame():
111 * queue a frame for capturing
112 * return value: TRUE on success, FALSE on error
113 ******************************************************/
116 gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
118 GST_LOG_OBJECT (v4l2src, "queueing frame %u", i);
120 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QBUF,
121 &v4l2src->pool->buffers[i].buffer) < 0) {
122 GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE,
123 (_("Could not write to device \"%s\"."),
124 GST_V4L2ELEMENT (v4l2src)->device),
125 ("Error queueing buffer %u on device %s", i, g_strerror (errno)));
133 /******************************************************
134 * gst_v4l2src_grab_frame ():
135 * grab a frame for capturing
136 * return value: TRUE on success, FALSE on error
137 ******************************************************/
140 gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
142 struct v4l2_buffer buffer;
144 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
145 while (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, &buffer) < 0) {
146 /* if the sync() got interrupted, we can retry */
147 if (errno != EINTR) {
148 GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
149 ("could not sync on a buffer on device %s: %s",
150 GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
153 GST_DEBUG_OBJECT (v4l2src, "grab got interrupted");
156 GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index);
162 /******************************************************
163 * gst_v4l2src_get_capture():
164 * get capture parameters
165 * return value: TRUE on success, FALSE on error
166 ******************************************************/
169 gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
171 DEBUG ("Getting capture format");
173 GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
175 v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
176 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_FMT,
177 &v4l2src->format) < 0) {
178 GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
179 ("failed to get pixelformat for device %s: %s",
180 GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
188 /******************************************************
189 * gst_v4l2src_set_capture():
190 * set capture parameters
191 * return value: TRUE on success, FALSE on error
192 ******************************************************/
195 gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
196 struct v4l2_fmtdesc * fmt, gint width, gint height)
198 DEBUG ("Setting capture format to %dx%d, format %s",
199 width, height, fmt->description);
201 GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
202 GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src));
204 memset (&v4l2src->format, 0, sizeof (struct v4l2_format));
205 v4l2src->format.fmt.pix.width = width;
206 v4l2src->format.fmt.pix.height = height;
207 v4l2src->format.fmt.pix.pixelformat = fmt->pixelformat;
208 v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED;
209 v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
211 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_S_FMT,
212 &v4l2src->format) < 0) {
213 GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
214 ("failed to set pixelformat to %s @ %dx%d for device %s: %s",
215 fmt->description, width, height, GST_V4L2ELEMENT (v4l2src)->device,
216 g_strerror (errno)));
220 /* update internal info */
221 return gst_v4l2src_get_capture (v4l2src);
225 /******************************************************
226 * gst_v4l2src_capture_init():
227 * initialize the capture system
228 * return value: TRUE on success, FALSE on error
229 ******************************************************/
232 gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
237 GST_DEBUG_OBJECT (v4l2src, "initting the capture system");
239 GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
240 GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src));
242 /* request buffer info */
243 buffers = v4l2src->breq.count;
244 if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS) {
245 v4l2src->breq.count = GST_V4L2_MAX_BUFFERS;
247 if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
248 v4l2src->breq.count = GST_V4L2_MIN_BUFFERS;
250 v4l2src->breq.type = v4l2src->format.type;
251 v4l2src->breq.memory = V4L2_MEMORY_MMAP;
252 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_REQBUFS,
253 &v4l2src->breq) < 0) {
254 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
255 (_("Could not get buffers from device \"%s\"."),
256 GST_V4L2ELEMENT (v4l2src)->device),
257 ("error requesting %d buffers: %s", v4l2src->breq.count,
258 g_strerror (errno)));
262 if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
263 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
264 (_("Could not get enough buffers from device \"%s\"."),
265 GST_V4L2ELEMENT (v4l2src)->device),
266 ("we received %d, we want at least %d", v4l2src->breq.count,
267 GST_V4L2_MIN_BUFFERS));
268 v4l2src->breq.count = buffers;
271 if (v4l2src->breq.count != buffers)
272 g_object_notify (G_OBJECT (v4l2src), "num_buffers");
274 GST_INFO_OBJECT (v4l2src,
275 "Got %d buffers (" GST_FOURCC_FORMAT ") of size %d KB\n",
277 GST_FOURCC_ARGS (v4l2src->format.fmt.pix.pixelformat),
278 v4l2src->format.fmt.pix.sizeimage / 1024);
280 /* Map the buffers */
281 v4l2src->pool = g_new (GstV4l2BufferPool, 1);
282 gst_atomic_int_init (&v4l2src->pool->refcount, 1);
283 v4l2src->pool->video_fd = GST_V4L2ELEMENT (v4l2src)->video_fd;
284 v4l2src->pool->buffer_count = v4l2src->breq.count;
285 v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count);
287 for (n = 0; n < v4l2src->breq.count; n++) {
288 GstV4l2Buffer *buffer = &v4l2src->pool->buffers[n];
290 gst_atomic_int_init (&buffer->refcount, 1);
291 buffer->pool = v4l2src->pool;
292 buffer->buffer.index = n;
293 buffer->buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
294 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QUERYBUF,
295 &buffer->buffer) < 0) {
296 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
297 ("Could not get buffer properties of buffer %d: %s", n,
298 g_strerror (errno)));
299 gst_v4l2src_capture_deinit (v4l2src);
303 mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
304 GST_V4L2ELEMENT (v4l2src)->video_fd, buffer->buffer.m.offset);
305 if (buffer->start == MAP_FAILED) {
306 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
307 ("Could not mmap video buffer %d: %s", n, g_strerror (errno)));
309 gst_v4l2src_capture_deinit (v4l2src);
312 buffer->length = buffer->buffer.length;
313 if (!gst_v4l2src_queue_frame (v4l2src, n)) {
314 gst_v4l2src_capture_deinit (v4l2src);
319 GST_V4L2_SET_ACTIVE (GST_V4L2ELEMENT (v4l2src));
324 /******************************************************
325 * gst_v4l2src_capture_start():
326 * start streaming capture
327 * return value: TRUE on success, FALSE on error
328 ******************************************************/
331 gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
333 gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
335 GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
337 GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
338 if (!GST_V4L2_IS_ACTIVE (GST_V4L2ELEMENT (v4l2src))) {
339 gst_pad_renegotiate (v4l2src->srcpad);
341 GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
343 v4l2src->quit = FALSE;
345 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMON, &type) < 0) {
346 GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ, (NULL),
347 ("Error starting streaming capture from device %s: %s",
348 GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
356 /******************************************************
357 * gst_v4l2src_capture_stop():
358 * stop streaming capture
359 * return value: TRUE on success, FALSE on error
360 ******************************************************/
363 gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
365 gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
367 GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
368 GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
369 GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
371 /* we actually need to sync on all queued buffers but not
372 * on the non-queued ones */
373 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMOFF, &type) < 0) {
374 GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE, (NULL),
375 ("Error stopping streaming capture from device %s: %s",
376 GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
380 /* make an optional pending wait stop */
381 v4l2src->quit = TRUE;
387 gst_v4l2src_buffer_pool_free (GstV4l2BufferPool * pool, gboolean do_close)
391 for (i = 0; i < pool->buffer_count; i++) {
392 gst_atomic_int_destroy (&pool->buffers[i].refcount);
393 munmap (pool->buffers[i].start, pool->buffers[i].length);
395 g_free (pool->buffers);
396 gst_atomic_int_destroy (&pool->refcount);
398 close (pool->video_fd);
403 gst_v4l2src_free_buffer (GstBuffer * buffer)
405 GstV4l2Buffer *buf = (GstV4l2Buffer *) GST_BUFFER_PRIVATE (buffer);
407 GST_LOG ("freeing buffer %p (nr. %d)", buffer, buf->buffer.index);
409 if (!gst_atomic_int_dec_and_test (&buf->refcount)) {
410 /* we're still in use, add to queue again
411 note: this might fail because the device is already stopped (race) */
412 if (ioctl (buf->pool->video_fd, VIDIOC_QBUF, &buf->buffer) < 0)
413 GST_INFO ("readding to queue failed, assuming video device is stopped");
415 if (gst_atomic_int_dec_and_test (&buf->pool->refcount)) {
416 /* we're last thing that used all this */
417 gst_v4l2src_buffer_pool_free (buf->pool, TRUE);
421 /******************************************************
422 * gst_v4l2src_capture_deinit():
423 * deinitialize the capture system
424 * return value: TRUE on success, FALSE on error
425 ******************************************************/
428 gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
432 GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
434 GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
435 GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
437 /* free the buffers */
438 for (i = 0; i < v4l2src->breq.count; i++) {
439 if (gst_atomic_int_dec_and_test (&v4l2src->pool->buffers[i].refcount))
442 for (i = 0; i < dequeue; i++) {
443 struct v4l2_buffer buffer;
445 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
446 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, &buffer) < 0)
447 GST_WARNING_OBJECT (v4l2src,
448 "Could not dequeue buffer on uninitialization");
450 if (gst_atomic_int_dec_and_test (&v4l2src->pool->refcount)) {
451 /* we're last thing that used all this */
452 gst_v4l2src_buffer_pool_free (v4l2src->pool, FALSE);
454 v4l2src->pool = NULL;
456 GST_V4L2_SET_INACTIVE (GST_V4L2ELEMENT (v4l2src));
466 gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
467 struct v4l2_fmtdesc * format,
468 gint * min_w, gint * max_w, gint * min_h, gint * max_h)
470 struct v4l2_format fmt;
472 GST_LOG_OBJECT (v4l2src, "getting size limits with format " GST_FOURCC_FORMAT,
473 GST_FOURCC_ARGS (format->pixelformat));
475 /* get size delimiters */
476 memset (&fmt, 0, sizeof (fmt));
477 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
478 fmt.fmt.pix.width = 0;
479 fmt.fmt.pix.height = 0;
480 fmt.fmt.pix.pixelformat = format->pixelformat;
481 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
482 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
487 *min_w = fmt.fmt.pix.width;
489 *min_h = fmt.fmt.pix.height;
490 GST_LOG_OBJECT (v4l2src, "got min size %dx%d", fmt.fmt.pix.width,
493 fmt.fmt.pix.width = G_MAXINT;
494 fmt.fmt.pix.height = 576;
495 if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
500 *max_w = fmt.fmt.pix.width;
502 *max_h = fmt.fmt.pix.height;
503 GST_LOG_OBJECT (v4l2src, "got max size %dx%d", fmt.fmt.pix.width,