3ee50755b4592cb627e4acd3957f14e7136fe1ad
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / v4l2src_calls.c
1 /* GStreamer
2  *
3  * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
4  *               2006 Edgard Lima <edgard.lima@indt.org.br>
5  *
6  * v4l2src.c - system calls
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <sys/ioctl.h>
33 #include <sys/mman.h>
34 #include <string.h>
35 #include <errno.h>
36 #include "v4l2src_calls.h"
37 #include <sys/time.h>
38 #include <unistd.h>
39 #ifdef __sun
40 /* Needed on older Solaris Nevada builds (72 at least) */
41 #include <stropts.h>
42 #include <sys/ioccom.h>
43 #endif
44
45 #include "gstv4l2tuner.h"
46 #include "gstv4l2bufferpool.h"
47
48 #include "gst/gst-i18n-plugin.h"
49
50 #define GST_CAT_DEFAULT v4l2src_debug
51 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
52
53 /* lalala... */
54 #define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1)
55 #define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL
56
57 /* On some systems MAP_FAILED seems to be missing */
58 #ifndef MAP_FAILED
59 #define MAP_FAILED ((caddr_t) -1)
60 #endif
61
62
63 /* Local functions */
64
65 static gboolean
66 gst_v4l2src_buffer_pool_activate (GstV4l2BufferPool * pool,
67     GstV4l2Src * v4l2src)
68 {
69   GstBuffer *buf;
70
71   while ((buf = gst_v4l2_buffer_pool_get (pool, FALSE)) != NULL)
72     if (!gst_v4l2_buffer_pool_qbuf (pool, buf))
73       goto queue_failed;
74
75   return TRUE;
76
77   /* ERRORS */
78 queue_failed:
79   {
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,
85             g_strerror (errno)));
86     return FALSE;
87   }
88 }
89
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  ******************************************************/
95 GstFlowReturn
96 gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
97 {
98 #define NUM_TRIALS 50
99   GstV4l2Object *v4l2object;
100   GstV4l2BufferPool *pool;
101   gint32 trials = NUM_TRIALS;
102   GstBuffer *pool_buffer;
103   gboolean need_copy;
104   gint ret;
105
106   v4l2object = v4l2src->v4l2object;
107   pool = v4l2src->pool;
108   if (!pool)
109     goto no_buffer_pool;
110
111   GST_DEBUG_OBJECT (v4l2src, "grab frame");
112
113   for (;;) {
114     if (v4l2object->can_poll_device) {
115       ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
116       if (G_UNLIKELY (ret < 0)) {
117         if (errno == EBUSY)
118           goto stopped;
119         if (errno == ENXIO) {
120           GST_DEBUG_OBJECT (v4l2src,
121               "v4l2 device doesn't support polling. Disabling");
122           v4l2object->can_poll_device = FALSE;
123         } else {
124           if (errno != EAGAIN && errno != EINTR)
125             goto select_error;
126         }
127       }
128     }
129
130     pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool));
131     if (pool_buffer)
132       break;
133
134     GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials);
135
136     /* if the sync() got interrupted, we can retry */
137     switch (errno) {
138       case EINVAL:
139       case ENOMEM:
140         /* fatal */
141         return GST_FLOW_ERROR;
142
143       case EAGAIN:
144       case EIO:
145       case EINTR:
146       default:
147         /* try again, until too many trials */
148         break;
149     }
150
151     /* check nr. of attempts to capture */
152     if (--trials == -1) {
153       goto too_many_trials;
154     }
155   }
156
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);
161
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");
166     }
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);
171   } else {
172     *buf = pool_buffer;
173   }
174   /* we set the buffer metadata in gst_v4l2src_create() */
175
176   return GST_FLOW_OK;
177
178   /* ERRORS */
179 no_buffer_pool:
180   {
181     GST_DEBUG ("no buffer pool");
182     return GST_FLOW_WRONG_STATE;
183   }
184 select_error:
185   {
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;
189   }
190 stopped:
191   {
192     GST_DEBUG ("stop called");
193     return GST_FLOW_WRONG_STATE;
194   }
195 too_many_trials:
196   {
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;
203   }
204 }
205
206 /* Note about fraction simplification
207  * n1/d1 == n2/d2  is also written as  n1 == ( n2 * d1 ) / d2
208  */
209 #define fractions_are_equal(n1,d1,n2,d2) ((n1) == gst_util_uint64_scale_int((n2), (d1), (d2)))
210
211 /******************************************************
212  * gst_v4l2src_set_capture():
213  *   set capture parameters
214  * return value: TRUE on success, FALSE on error
215  ******************************************************/
216 gboolean
217 gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat,
218     guint32 width, guint32 height, gboolean interlaced,
219     guint fps_n, guint fps_d)
220 {
221   gint fd = v4l2src->v4l2object->video_fd;
222   struct v4l2_streamparm stream;
223
224   if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
225     return TRUE;
226
227   if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width,
228           height, interlaced)) {
229     /* error already reported */
230     return FALSE;
231   }
232
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);
235
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);
242     goto done;
243   }
244
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");
249     goto already_set;
250   }
251
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)");
256     goto done;
257   }
258
259   GST_LOG_OBJECT (v4l2src, "Setting framerate to %u/%u", fps_n, fps_d);
260
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;
264
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.")),
269         GST_ERROR_SYSTEM);
270     goto done;
271   }
272
273 already_set:
274
275   v4l2src->fps_n = fps_n;
276   v4l2src->fps_d = fps_d;
277
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);
281   } else {
282     v4l2src->duration = GST_CLOCK_TIME_NONE;
283   }
284
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));
288 done:
289
290   return TRUE;
291 }
292
293 /******************************************************
294  * gst_v4l2src_capture_init():
295  *   initialize the capture system
296  * return value: TRUE on success, FALSE on error
297  ******************************************************/
298 gboolean
299 gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
300 {
301   GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
302
303   GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
304   GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
305
306   if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
307
308     /* Map the buffers */
309     GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
310
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;
315
316     GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
317     v4l2src->use_mmap = TRUE;
318
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");
322     }
323
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;
328   } else {
329     goto no_supported_capture_method;
330   }
331
332   GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
333
334   return TRUE;
335
336   /* ERRORS */
337 buffer_pool_new_failed:
338   {
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)));
343     return FALSE;
344   }
345 no_supported_capture_method:
346   {
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));
350     return FALSE;
351   }
352 }
353
354
355 /******************************************************
356  * gst_v4l2src_capture_start():
357  *   start streaming capture
358  * return value: TRUE on success, FALSE on error
359  ******************************************************/
360 gboolean
361 gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
362 {
363   GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
364   //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
365   GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
366
367   v4l2src->quit = FALSE;
368
369   if (v4l2src->use_mmap) {
370     if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) {
371       return FALSE;
372     }
373
374     if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) {
375       return FALSE;
376     }
377   }
378
379   v4l2src->is_capturing = TRUE;
380
381   return TRUE;
382 }
383
384 /******************************************************
385  * gst_v4l2src_capture_stop():
386  *   stop streaming capture
387  * return value: TRUE on success, FALSE on error
388  ******************************************************/
389 gboolean
390 gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
391 {
392   GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
393
394   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
395     goto done;
396   }
397   if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
398     goto done;
399   }
400
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)) {
405       return FALSE;
406     }
407   }
408
409 done:
410
411   /* make an optional pending wait stop */
412   v4l2src->quit = TRUE;
413   v4l2src->is_capturing = FALSE;
414
415   return TRUE;
416 }
417
418 /******************************************************
419  * gst_v4l2src_capture_deinit():
420  *   deinitialize the capture system
421  * return value: TRUE on success, FALSE on error
422  ******************************************************/
423 gboolean
424 gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
425 {
426   GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
427
428   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
429     return TRUE;
430   }
431   if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
432     return TRUE;
433   }
434
435   if (v4l2src->pool) {
436     gst_v4l2_buffer_pool_destroy (v4l2src->pool);
437     v4l2src->pool = NULL;
438   }
439
440   GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
441
442   return TRUE;
443 }