Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.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   GstV4l2Buffer *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             buf->vbuffer.index, v4l2src->num_buffers, g_strerror (errno)));
85     return FALSE;
86   }
87 }
88
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  ******************************************************/
94 GstFlowReturn
95 gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
96 {
97 #define NUM_TRIALS 50
98   GstV4l2Object *v4l2object;
99   GstV4l2BufferPool *pool;
100   gint32 trials = NUM_TRIALS;
101   GstBuffer *pool_buffer;
102   gboolean need_copy;
103   gint ret;
104
105   v4l2object = v4l2src->v4l2object;
106   pool = v4l2src->pool;
107   if (!pool)
108     goto no_buffer_pool;
109
110   GST_DEBUG_OBJECT (v4l2src, "grab frame");
111
112   for (;;) {
113     if (v4l2object->can_poll_device) {
114       ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
115       if (G_UNLIKELY (ret < 0)) {
116         if (errno == EBUSY)
117           goto stopped;
118         if (errno == ENXIO) {
119           GST_DEBUG_OBJECT (v4l2src,
120               "v4l2 device doesn't support polling. Disabling");
121           v4l2object->can_poll_device = FALSE;
122         } else {
123           if (errno != EAGAIN && errno != EINTR)
124             goto select_error;
125         }
126       }
127     }
128
129     pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool));
130     if (pool_buffer)
131       break;
132
133     GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials);
134
135     /* if the sync() got interrupted, we can retry */
136     switch (errno) {
137       case EINVAL:
138       case ENOMEM:
139         /* fatal */
140         return GST_FLOW_ERROR;
141
142       case EAGAIN:
143       case EIO:
144       case EINTR:
145       default:
146         /* try again, until too many trials */
147         break;
148     }
149
150     /* check nr. of attempts to capture */
151     if (--trials == -1) {
152       goto too_many_trials;
153     }
154   }
155
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);
160
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");
165     }
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);
170   } else {
171     *buf = pool_buffer;
172   }
173   /* we set the buffer metadata in gst_v4l2src_create() */
174
175   return GST_FLOW_OK;
176
177   /* ERRORS */
178 no_buffer_pool:
179   {
180     GST_DEBUG ("no buffer pool");
181     return GST_FLOW_WRONG_STATE;
182   }
183 select_error:
184   {
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;
188   }
189 stopped:
190   {
191     GST_DEBUG ("stop called");
192     return GST_FLOW_WRONG_STATE;
193   }
194 too_many_trials:
195   {
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;
202   }
203 }
204
205 /******************************************************
206  * gst_v4l2src_set_capture():
207  *   set capture parameters
208  * return value: TRUE on success, FALSE on error
209  ******************************************************/
210 gboolean
211 gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat,
212     guint32 width, guint32 height, gboolean interlaced,
213     guint fps_n, guint fps_d)
214 {
215   gint fd = v4l2src->v4l2object->video_fd;
216   struct v4l2_streamparm stream;
217
218   if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
219     return TRUE;
220
221   if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width,
222           height, interlaced)) {
223     /* error already reported */
224     return FALSE;
225   }
226
227   /* Is there a reason we require the caller to always specify a framerate? */
228   GST_DEBUG_OBJECT (v4l2src, "Desired framerate: %u/%u", fps_n, fps_d);
229
230   memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
231   stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
232   if (v4l2_ioctl (fd, VIDIOC_G_PARM, &stream) < 0) {
233     GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
234         (_("Could not get parameters on device '%s'"),
235             v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
236     goto done;
237   }
238
239   /* We used to skip frame rate setup if the camera was already setup
240      with the requested frame rate. This breaks some cameras though,
241      causing them to not output data (several models of Thinkpad cameras
242      have this problem at least).
243      So, don't skip. */
244
245   /* We want to change the frame rate, so check whether we can. Some cheap USB
246    * cameras don't have the capability */
247   if ((stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
248     GST_DEBUG_OBJECT (v4l2src, "Not setting framerate (not supported)");
249     goto done;
250   }
251
252   GST_LOG_OBJECT (v4l2src, "Setting framerate to %u/%u", fps_n, fps_d);
253
254   /* Note: V4L2 wants the frame interval, we have the frame rate */
255   stream.parm.capture.timeperframe.numerator = fps_d;
256   stream.parm.capture.timeperframe.denominator = fps_n;
257
258   /* some cheap USB cam's won't accept any change */
259   if (v4l2_ioctl (fd, VIDIOC_S_PARM, &stream) < 0) {
260     GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
261         (_("Video input device did not accept new frame rate setting.")),
262         GST_ERROR_SYSTEM);
263     goto done;
264   }
265
266   v4l2src->fps_n = fps_n;
267   v4l2src->fps_d = fps_d;
268
269   /* if we have a framerate pre-calculate duration */
270   if (fps_n > 0 && fps_d > 0) {
271     v4l2src->duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
272   } else {
273     v4l2src->duration = GST_CLOCK_TIME_NONE;
274   }
275
276   GST_INFO_OBJECT (v4l2src,
277       "Set framerate to %u/%u and duration to %" GST_TIME_FORMAT, fps_n, fps_d,
278       GST_TIME_ARGS (v4l2src->duration));
279 done:
280
281   return TRUE;
282 }
283
284 /******************************************************
285  * gst_v4l2src_capture_init():
286  *   initialize the capture system
287  * return value: TRUE on success, FALSE on error
288  ******************************************************/
289 gboolean
290 gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
291 {
292   GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
293
294   GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
295   GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
296
297   if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
298
299     /* Map the buffers */
300     GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
301
302     if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2src),
303                 v4l2src->v4l2object->video_fd,
304                 v4l2src->num_buffers, caps, TRUE, V4L2_BUF_TYPE_VIDEO_CAPTURE)))
305       goto buffer_pool_new_failed;
306
307     GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
308     v4l2src->use_mmap = TRUE;
309
310     if (v4l2src->num_buffers != v4l2src->pool->buffer_count) {
311       v4l2src->num_buffers = v4l2src->pool->buffer_count;
312       g_object_notify (G_OBJECT (v4l2src), "queue-size");
313     }
314
315   } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
316     GST_INFO_OBJECT (v4l2src, "capturing buffers via read()");
317     v4l2src->use_mmap = FALSE;
318     v4l2src->pool = NULL;
319   } else {
320     goto no_supported_capture_method;
321   }
322
323   GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
324
325   return TRUE;
326
327   /* ERRORS */
328 buffer_pool_new_failed:
329   {
330     GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
331         (_("Could not map buffers from device '%s'"),
332             v4l2src->v4l2object->videodev),
333         ("Failed to create buffer pool: %s", g_strerror (errno)));
334     return FALSE;
335   }
336 no_supported_capture_method:
337   {
338     GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
339         (_("The driver of device '%s' does not support any known capture "
340                 "method."), v4l2src->v4l2object->videodev), (NULL));
341     return FALSE;
342   }
343 }
344
345
346 /******************************************************
347  * gst_v4l2src_capture_start():
348  *   start streaming capture
349  * return value: TRUE on success, FALSE on error
350  ******************************************************/
351 gboolean
352 gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
353 {
354   GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
355   //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
356   GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
357
358   v4l2src->quit = FALSE;
359
360   if (v4l2src->use_mmap) {
361     if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) {
362       return FALSE;
363     }
364
365     if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) {
366       return FALSE;
367     }
368   }
369
370   v4l2src->is_capturing = TRUE;
371
372   return TRUE;
373 }
374
375 /******************************************************
376  * gst_v4l2src_capture_stop():
377  *   stop streaming capture
378  * return value: TRUE on success, FALSE on error
379  ******************************************************/
380 gboolean
381 gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
382 {
383   GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
384
385   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
386     goto done;
387   }
388   if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
389     goto done;
390   }
391
392   if (v4l2src->use_mmap) {
393     /* we actually need to sync on all queued buffers but not
394      * on the non-queued ones */
395     if (!gst_v4l2_object_stop_streaming (v4l2src->v4l2object)) {
396       return FALSE;
397     }
398   }
399
400 done:
401
402   /* make an optional pending wait stop */
403   v4l2src->quit = TRUE;
404   v4l2src->is_capturing = FALSE;
405
406   return TRUE;
407 }
408
409 /******************************************************
410  * gst_v4l2src_capture_deinit():
411  *   deinitialize the capture system
412  * return value: TRUE on success, FALSE on error
413  ******************************************************/
414 gboolean
415 gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
416 {
417   GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
418
419   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
420     return TRUE;
421   }
422   if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
423     return TRUE;
424   }
425
426   if (v4l2src->pool) {
427     gst_v4l2_buffer_pool_destroy (v4l2src->pool);
428     v4l2src->pool = NULL;
429   }
430
431   GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
432
433   return TRUE;
434 }