upload tizen1.0 source
[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 /* Note about fraction simplification
206  * n1/d1 == n2/d2  is also written as  n1 == ( n2 * d1 ) / d2
207  */
208 #define fractions_are_equal(n1,d1,n2,d2) ((n1) == gst_util_uint64_scale_int((n2), (d1), (d2)))
209
210 /******************************************************
211  * gst_v4l2src_set_capture():
212  *   set capture parameters
213  * return value: TRUE on success, FALSE on error
214  ******************************************************/
215 gboolean
216 gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat,
217     guint32 width, guint32 height, gboolean interlaced,
218     guint fps_n, guint fps_d)
219 {
220   gint fd = v4l2src->v4l2object->video_fd;
221   struct v4l2_streamparm stream;
222
223   if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
224     return TRUE;
225
226   if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width,
227           height, interlaced)) {
228     /* error already reported */
229     return FALSE;
230   }
231
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);
234
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);
241     goto done;
242   }
243
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");
248     goto already_set;
249   }
250
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)");
255     goto done;
256   }
257
258   GST_LOG_OBJECT (v4l2src, "Setting framerate to %u/%u", fps_n, fps_d);
259
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;
263
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.")),
268         GST_ERROR_SYSTEM);
269     goto done;
270   }
271
272 already_set:
273
274   v4l2src->fps_n = fps_n;
275   v4l2src->fps_d = fps_d;
276
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);
280   } else {
281     v4l2src->duration = GST_CLOCK_TIME_NONE;
282   }
283
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));
287 done:
288
289   return TRUE;
290 }
291
292 /******************************************************
293  * gst_v4l2src_capture_init():
294  *   initialize the capture system
295  * return value: TRUE on success, FALSE on error
296  ******************************************************/
297 gboolean
298 gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
299 {
300   GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
301
302   GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
303   GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
304
305   if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
306
307     /* Map the buffers */
308     GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
309
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;
314
315     GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
316     v4l2src->use_mmap = TRUE;
317
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");
321     }
322
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;
327   } else {
328     goto no_supported_capture_method;
329   }
330
331   GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
332
333   return TRUE;
334
335   /* ERRORS */
336 buffer_pool_new_failed:
337   {
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)));
342     return FALSE;
343   }
344 no_supported_capture_method:
345   {
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));
349     return FALSE;
350   }
351 }
352
353
354 /******************************************************
355  * gst_v4l2src_capture_start():
356  *   start streaming capture
357  * return value: TRUE on success, FALSE on error
358  ******************************************************/
359 gboolean
360 gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
361 {
362   GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
363   //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
364   GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
365
366   v4l2src->quit = FALSE;
367
368   if (v4l2src->use_mmap) {
369     if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) {
370       return FALSE;
371     }
372
373     if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) {
374       return FALSE;
375     }
376   }
377
378   v4l2src->is_capturing = TRUE;
379
380   return TRUE;
381 }
382
383 /******************************************************
384  * gst_v4l2src_capture_stop():
385  *   stop streaming capture
386  * return value: TRUE on success, FALSE on error
387  ******************************************************/
388 gboolean
389 gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
390 {
391   GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
392
393   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
394     goto done;
395   }
396   if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
397     goto done;
398   }
399
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)) {
404       return FALSE;
405     }
406   }
407
408 done:
409
410   /* make an optional pending wait stop */
411   v4l2src->quit = TRUE;
412   v4l2src->is_capturing = FALSE;
413
414   return TRUE;
415 }
416
417 /******************************************************
418  * gst_v4l2src_capture_deinit():
419  *   deinitialize the capture system
420  * return value: TRUE on success, FALSE on error
421  ******************************************************/
422 gboolean
423 gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
424 {
425   GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
426
427   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
428     return TRUE;
429   }
430   if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
431     return TRUE;
432   }
433
434   if (v4l2src->pool) {
435     gst_v4l2_buffer_pool_destroy (v4l2src->pool);
436     v4l2src->pool = NULL;
437   }
438
439   GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
440
441   return TRUE;
442 }