3 * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
4 * 2006 Edgard Lima <edgard.lima@indt.org.br>
6 * v4l2src.c - system calls
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
29 #include <sys/types.h>
32 #include <sys/ioctl.h>
36 #include "v4l2src_calls.h"
40 /* Needed on older Solaris Nevada builds (72 at least) */
42 #include <sys/ioccom.h>
45 #include "gstv4l2tuner.h"
46 #include "gstv4l2bufferpool.h"
48 #include "gst/gst-i18n-plugin.h"
50 #define GST_CAT_DEFAULT v4l2src_debug
51 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
54 #define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1)
55 #define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL
57 /* On some systems MAP_FAILED seems to be missing */
59 #define MAP_FAILED ((caddr_t) -1)
66 gst_v4l2src_buffer_pool_activate (GstV4l2BufferPool * pool,
71 while ((buf = gst_v4l2_buffer_pool_get (pool, FALSE)) != NULL)
72 if (!gst_v4l2_buffer_pool_qbuf (pool, buf))
80 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
81 (_("Could not enqueue buffers in device '%s'."),
82 v4l2src->v4l2object->videodev),
83 ("enqueing buffer %d/%d failed: %s",
84 buf->vbuffer.index, v4l2src->num_buffers, g_strerror (errno)));
89 /******************************************************
90 * gst_v4l2src_grab_frame ():
91 * grab a frame for capturing
92 * return value: GST_FLOW_OK, GST_FLOW_WRONG_STATE or GST_FLOW_ERROR
93 ******************************************************/
95 gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
98 GstV4l2Object *v4l2object;
99 GstV4l2BufferPool *pool;
100 gint32 trials = NUM_TRIALS;
101 GstBuffer *pool_buffer;
105 v4l2object = v4l2src->v4l2object;
106 pool = v4l2src->pool;
110 GST_DEBUG_OBJECT (v4l2src, "grab frame");
113 if (v4l2object->can_poll_device) {
114 ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
115 if (G_UNLIKELY (ret < 0)) {
118 if (errno == ENXIO) {
119 GST_DEBUG_OBJECT (v4l2src,
120 "v4l2 device doesn't support polling. Disabling");
121 v4l2object->can_poll_device = FALSE;
123 if (errno != EAGAIN && errno != EINTR)
129 pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool));
133 GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials);
135 /* if the sync() got interrupted, we can retry */
140 return GST_FLOW_ERROR;
146 /* try again, until too many trials */
150 /* check nr. of attempts to capture */
151 if (--trials == -1) {
152 goto too_many_trials;
156 /* if we are handing out the last buffer in the pool, we need to make a
157 * copy and bring the buffer back in the pool. */
158 need_copy = v4l2src->always_copy
159 || !gst_v4l2_buffer_pool_available_buffers (pool);
161 if (G_UNLIKELY (need_copy)) {
162 if (!v4l2src->always_copy) {
163 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2src,
164 "running out of buffers, making a copy to reuse current one");
166 *buf = gst_buffer_copy (pool_buffer);
167 GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
168 /* this will requeue */
169 gst_buffer_unref (pool_buffer);
173 /* we set the buffer metadata in gst_v4l2src_create() */
180 GST_DEBUG ("no buffer pool");
181 return GST_FLOW_WRONG_STATE;
185 GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, READ, (NULL),
186 ("select error %d: %s (%d)", ret, g_strerror (errno), errno));
187 return GST_FLOW_ERROR;
191 GST_DEBUG ("stop called");
192 return GST_FLOW_WRONG_STATE;
196 GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
197 (_("Failed trying to get video frames from device '%s'."),
198 v4l2object->videodev),
199 (_("Failed after %d tries. device %s. system error: %s"),
200 NUM_TRIALS, v4l2object->videodev, g_strerror (errno)));
201 return GST_FLOW_ERROR;
205 /* Note about fraction simplification
206 * n1/d1 == n2/d2 is also written as n1 == ( n2 * d1 ) / d2
208 #define fractions_are_equal(n1,d1,n2,d2) ((n1) == gst_util_uint64_scale_int((n2), (d1), (d2)))
210 /******************************************************
211 * gst_v4l2src_set_capture():
212 * set capture parameters
213 * return value: TRUE on success, FALSE on error
214 ******************************************************/
216 gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat,
217 guint32 width, guint32 height, gboolean interlaced,
218 guint fps_n, guint fps_d)
220 gint fd = v4l2src->v4l2object->video_fd;
221 struct v4l2_streamparm stream;
223 if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
226 if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width,
227 height, interlaced)) {
228 /* error already reported */
232 /* Is there a reason we require the caller to always specify a framerate? */
233 GST_DEBUG_OBJECT (v4l2src, "Desired framerate: %u/%u", fps_n, fps_d);
235 memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
236 stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
237 if (v4l2_ioctl (fd, VIDIOC_G_PARM, &stream) < 0) {
238 GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
239 (_("Could not get parameters on device '%s'"),
240 v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
244 /* Note: V4L2 provides the frame interval, we have the frame rate */
245 if (fractions_are_equal (stream.parm.capture.timeperframe.numerator,
246 stream.parm.capture.timeperframe.denominator, fps_d, fps_n)) {
247 GST_DEBUG_OBJECT (v4l2src, "Desired framerate already set");
251 /* We want to change the frame rate, so check whether we can. Some cheap USB
252 * cameras don't have the capability */
253 if ((stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
254 GST_DEBUG_OBJECT (v4l2src, "Not setting framerate (not supported)");
258 GST_LOG_OBJECT (v4l2src, "Setting framerate to %u/%u", fps_n, fps_d);
260 /* Note: V4L2 wants the frame interval, we have the frame rate */
261 stream.parm.capture.timeperframe.numerator = fps_d;
262 stream.parm.capture.timeperframe.denominator = fps_n;
264 /* some cheap USB cam's won't accept any change */
265 if (v4l2_ioctl (fd, VIDIOC_S_PARM, &stream) < 0) {
266 GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
267 (_("Video input device did not accept new frame rate setting.")),
274 v4l2src->fps_n = fps_n;
275 v4l2src->fps_d = fps_d;
277 /* if we have a framerate pre-calculate duration */
278 if (fps_n > 0 && fps_d > 0) {
279 v4l2src->duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
281 v4l2src->duration = GST_CLOCK_TIME_NONE;
284 GST_INFO_OBJECT (v4l2src,
285 "Set framerate to %u/%u and duration to %" GST_TIME_FORMAT, fps_n, fps_d,
286 GST_TIME_ARGS (v4l2src->duration));
292 /******************************************************
293 * gst_v4l2src_capture_init():
294 * initialize the capture system
295 * return value: TRUE on success, FALSE on error
296 ******************************************************/
298 gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
300 GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
302 GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
303 GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
305 if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
307 /* Map the buffers */
308 GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
310 if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2src),
311 v4l2src->v4l2object->video_fd,
312 v4l2src->num_buffers, caps, TRUE, V4L2_BUF_TYPE_VIDEO_CAPTURE)))
313 goto buffer_pool_new_failed;
315 GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
316 v4l2src->use_mmap = TRUE;
318 if (v4l2src->num_buffers != v4l2src->pool->buffer_count) {
319 v4l2src->num_buffers = v4l2src->pool->buffer_count;
320 g_object_notify (G_OBJECT (v4l2src), "queue-size");
323 } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
324 GST_INFO_OBJECT (v4l2src, "capturing buffers via read()");
325 v4l2src->use_mmap = FALSE;
326 v4l2src->pool = NULL;
328 goto no_supported_capture_method;
331 GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
336 buffer_pool_new_failed:
338 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
339 (_("Could not map buffers from device '%s'"),
340 v4l2src->v4l2object->videodev),
341 ("Failed to create buffer pool: %s", g_strerror (errno)));
344 no_supported_capture_method:
346 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
347 (_("The driver of device '%s' does not support any known capture "
348 "method."), v4l2src->v4l2object->videodev), (NULL));
354 /******************************************************
355 * gst_v4l2src_capture_start():
356 * start streaming capture
357 * return value: TRUE on success, FALSE on error
358 ******************************************************/
360 gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
362 GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
363 //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
364 GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
366 v4l2src->quit = FALSE;
368 if (v4l2src->use_mmap) {
369 if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) {
373 if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) {
378 v4l2src->is_capturing = TRUE;
383 /******************************************************
384 * gst_v4l2src_capture_stop():
385 * stop streaming capture
386 * return value: TRUE on success, FALSE on error
387 ******************************************************/
389 gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
391 GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
393 if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
396 if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
400 if (v4l2src->use_mmap) {
401 /* we actually need to sync on all queued buffers but not
402 * on the non-queued ones */
403 if (!gst_v4l2_object_stop_streaming (v4l2src->v4l2object)) {
410 /* make an optional pending wait stop */
411 v4l2src->quit = TRUE;
412 v4l2src->is_capturing = FALSE;
417 /******************************************************
418 * gst_v4l2src_capture_deinit():
419 * deinitialize the capture system
420 * return value: TRUE on success, FALSE on error
421 ******************************************************/
423 gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
425 GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
427 if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
430 if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
435 gst_v4l2_buffer_pool_destroy (v4l2src->pool);
436 v4l2src->pool = NULL;
439 GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);