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 GST_META_V4L2_GET (buf, FALSE)->vbuffer.index, v4l2src->num_buffers,
90 /******************************************************
91 * gst_v4l2src_grab_frame ():
92 * grab a frame for capturing
93 * return value: GST_FLOW_OK, GST_FLOW_WRONG_STATE or GST_FLOW_ERROR
94 ******************************************************/
96 gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
99 GstV4l2Object *v4l2object;
100 GstV4l2BufferPool *pool;
101 gint32 trials = NUM_TRIALS;
102 GstBuffer *pool_buffer;
106 v4l2object = v4l2src->v4l2object;
107 pool = v4l2src->pool;
111 GST_DEBUG_OBJECT (v4l2src, "grab frame");
114 if (v4l2object->can_poll_device) {
115 ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
116 if (G_UNLIKELY (ret < 0)) {
119 if (errno == ENXIO) {
120 GST_DEBUG_OBJECT (v4l2src,
121 "v4l2 device doesn't support polling. Disabling");
122 v4l2object->can_poll_device = FALSE;
124 if (errno != EAGAIN && errno != EINTR)
130 pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool));
134 GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials);
136 /* if the sync() got interrupted, we can retry */
141 return GST_FLOW_ERROR;
147 /* try again, until too many trials */
151 /* check nr. of attempts to capture */
152 if (--trials == -1) {
153 goto too_many_trials;
157 /* if we are handing out the last buffer in the pool, we need to make a
158 * copy and bring the buffer back in the pool. */
159 need_copy = v4l2src->always_copy
160 || !gst_v4l2_buffer_pool_available_buffers (pool);
162 if (G_UNLIKELY (need_copy)) {
163 if (!v4l2src->always_copy) {
164 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2src,
165 "running out of buffers, making a copy to reuse current one");
167 *buf = gst_buffer_copy (pool_buffer);
168 GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
169 /* this will requeue */
170 gst_buffer_unref (pool_buffer);
174 /* we set the buffer metadata in gst_v4l2src_create() */
181 GST_DEBUG ("no buffer pool");
182 return GST_FLOW_WRONG_STATE;
186 GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, READ, (NULL),
187 ("select error %d: %s (%d)", ret, g_strerror (errno), errno));
188 return GST_FLOW_ERROR;
192 GST_DEBUG ("stop called");
193 return GST_FLOW_WRONG_STATE;
197 GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
198 (_("Failed trying to get video frames from device '%s'."),
199 v4l2object->videodev),
200 (_("Failed after %d tries. device %s. system error: %s"),
201 NUM_TRIALS, v4l2object->videodev, g_strerror (errno)));
202 return GST_FLOW_ERROR;
206 /* Note about fraction simplification
207 * n1/d1 == n2/d2 is also written as n1 == ( n2 * d1 ) / d2
209 #define fractions_are_equal(n1,d1,n2,d2) ((n1) == gst_util_uint64_scale_int((n2), (d1), (d2)))
211 /******************************************************
212 * gst_v4l2src_set_capture():
213 * set capture parameters
214 * return value: TRUE on success, FALSE on error
215 ******************************************************/
217 gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat,
218 guint32 width, guint32 height, gboolean interlaced,
219 guint fps_n, guint fps_d)
221 gint fd = v4l2src->v4l2object->video_fd;
222 struct v4l2_streamparm stream;
224 if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
227 if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width,
228 height, interlaced)) {
229 /* error already reported */
233 /* Is there a reason we require the caller to always specify a framerate? */
234 GST_DEBUG_OBJECT (v4l2src, "Desired framerate: %u/%u", fps_n, fps_d);
236 memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
237 stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
238 if (v4l2_ioctl (fd, VIDIOC_G_PARM, &stream) < 0) {
239 GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
240 (_("Could not get parameters on device '%s'"),
241 v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
245 /* Note: V4L2 provides the frame interval, we have the frame rate */
246 if (fractions_are_equal (stream.parm.capture.timeperframe.numerator,
247 stream.parm.capture.timeperframe.denominator, fps_d, fps_n)) {
248 GST_DEBUG_OBJECT (v4l2src, "Desired framerate already set");
252 /* We want to change the frame rate, so check whether we can. Some cheap USB
253 * cameras don't have the capability */
254 if ((stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
255 GST_DEBUG_OBJECT (v4l2src, "Not setting framerate (not supported)");
259 GST_LOG_OBJECT (v4l2src, "Setting framerate to %u/%u", fps_n, fps_d);
261 /* Note: V4L2 wants the frame interval, we have the frame rate */
262 stream.parm.capture.timeperframe.numerator = fps_d;
263 stream.parm.capture.timeperframe.denominator = fps_n;
265 /* some cheap USB cam's won't accept any change */
266 if (v4l2_ioctl (fd, VIDIOC_S_PARM, &stream) < 0) {
267 GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
268 (_("Video input device did not accept new frame rate setting.")),
275 v4l2src->fps_n = fps_n;
276 v4l2src->fps_d = fps_d;
278 /* if we have a framerate pre-calculate duration */
279 if (fps_n > 0 && fps_d > 0) {
280 v4l2src->duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
282 v4l2src->duration = GST_CLOCK_TIME_NONE;
285 GST_INFO_OBJECT (v4l2src,
286 "Set framerate to %u/%u and duration to %" GST_TIME_FORMAT, fps_n, fps_d,
287 GST_TIME_ARGS (v4l2src->duration));
293 /******************************************************
294 * gst_v4l2src_capture_init():
295 * initialize the capture system
296 * return value: TRUE on success, FALSE on error
297 ******************************************************/
299 gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
301 GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
303 GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
304 GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
306 if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
308 /* Map the buffers */
309 GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
311 if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2src),
312 v4l2src->v4l2object->video_fd,
313 v4l2src->num_buffers, caps, TRUE, V4L2_BUF_TYPE_VIDEO_CAPTURE)))
314 goto buffer_pool_new_failed;
316 GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
317 v4l2src->use_mmap = TRUE;
319 if (v4l2src->num_buffers != v4l2src->pool->buffer_count) {
320 v4l2src->num_buffers = v4l2src->pool->buffer_count;
321 g_object_notify (G_OBJECT (v4l2src), "queue-size");
324 } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
325 GST_INFO_OBJECT (v4l2src, "capturing buffers via read()");
326 v4l2src->use_mmap = FALSE;
327 v4l2src->pool = NULL;
329 goto no_supported_capture_method;
332 GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
337 buffer_pool_new_failed:
339 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
340 (_("Could not map buffers from device '%s'"),
341 v4l2src->v4l2object->videodev),
342 ("Failed to create buffer pool: %s", g_strerror (errno)));
345 no_supported_capture_method:
347 GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
348 (_("The driver of device '%s' does not support any known capture "
349 "method."), v4l2src->v4l2object->videodev), (NULL));
355 /******************************************************
356 * gst_v4l2src_capture_start():
357 * start streaming capture
358 * return value: TRUE on success, FALSE on error
359 ******************************************************/
361 gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
363 GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
364 //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
365 GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
367 v4l2src->quit = FALSE;
369 if (v4l2src->use_mmap) {
370 if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) {
374 if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) {
379 v4l2src->is_capturing = TRUE;
384 /******************************************************
385 * gst_v4l2src_capture_stop():
386 * stop streaming capture
387 * return value: TRUE on success, FALSE on error
388 ******************************************************/
390 gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
392 GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
394 if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
397 if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
401 if (v4l2src->use_mmap) {
402 /* we actually need to sync on all queued buffers but not
403 * on the non-queued ones */
404 if (!gst_v4l2_object_stop_streaming (v4l2src->v4l2object)) {
411 /* make an optional pending wait stop */
412 v4l2src->quit = TRUE;
413 v4l2src->is_capturing = FALSE;
418 /******************************************************
419 * gst_v4l2src_capture_deinit():
420 * deinitialize the capture system
421 * return value: TRUE on success, FALSE on error
422 ******************************************************/
424 gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
426 GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
428 if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
431 if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
436 gst_v4l2_buffer_pool_destroy (v4l2src->pool);
437 v4l2src->pool = NULL;
440 GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);