gst-indent
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / v4l2src_calls.c
1 /* G-Streamer Video4linux2 video-capture plugin - system calls
2  * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <sys/mman.h>
30 #include <string.h>
31 #include <errno.h>
32 #include "v4l2src_calls.h"
33 #include <sys/time.h>
34 #include <unistd.h>
35
36 #define GST_CAT_DEFAULT v4l2src_debug
37
38 /* lalala... */
39 #define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1)
40 #define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL
41
42 #define DEBUG(format, args...) \
43         GST_CAT_DEBUG_OBJECT (\
44                 v4l2src_debug, v4l2src, \
45                 "V4L2SRC: " format, ##args)
46
47 /* On some systems MAP_FAILED seems to be missing */
48 #ifndef MAP_FAILED
49 #define MAP_FAILED ( (caddr_t) -1 )
50 #endif
51
52 /******************************************************
53  * gst_v4l2src_fill_format_list():
54  *   create list of supported capture formats
55  * return value: TRUE on success, FALSE on error
56  ******************************************************/
57
58 gboolean
59 gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
60 {
61   gint n;
62   struct v4l2_fmtdesc *format;
63
64   GST_DEBUG_OBJECT (v4l2src, "getting src format enumerations");
65
66   /* format enumeration */
67   for (n = 0;; n++) {
68     format = g_new (struct v4l2_fmtdesc, 1);
69
70     format->index = n;
71     format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
72     if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_ENUM_FMT,
73             format) < 0) {
74       if (errno == EINVAL) {
75         break;                  /* end of enumeration */
76       } else {
77         GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
78             ("failed to get number %d in pixelformat enumeration for %s: %s",
79                 n, GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
80         g_free (format);
81         return FALSE;
82       }
83     }
84     GST_LOG_OBJECT (v4l2src, "got format" GST_FOURCC_FORMAT,
85         GST_FOURCC_ARGS (format->pixelformat));
86     v4l2src->formats = g_slist_prepend (v4l2src->formats, format);
87   }
88
89   return TRUE;
90 }
91
92
93 /******************************************************
94  * gst_v4l2src_clear_format_list():
95  *   free list of supported capture formats
96  * return value: TRUE on success, FALSE on error
97  ******************************************************/
98
99 gboolean
100 gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
101 {
102   g_slist_foreach (v4l2src->formats, (GFunc) g_free, NULL);
103   g_slist_free (v4l2src->formats);
104
105   return TRUE;
106 }
107
108
109 /******************************************************
110  * gst_v4l2src_queue_frame():
111  *   queue a frame for capturing
112  * return value: TRUE on success, FALSE on error
113  ******************************************************/
114
115 gboolean
116 gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
117 {
118   GST_LOG_OBJECT (v4l2src, "queueing frame %u", i);
119
120   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QBUF,
121           &v4l2src->pool->buffers[i].buffer) < 0) {
122     GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE,
123         (_("Could not write to device \"%s\"."),
124             GST_V4L2ELEMENT (v4l2src)->device),
125         ("Error queueing buffer %u on device %s", i, g_strerror (errno)));
126     return FALSE;
127   }
128
129   return TRUE;
130 }
131
132
133 /******************************************************
134  * gst_v4l2src_grab_frame ():
135  *   grab a frame for capturing
136  * return value: TRUE on success, FALSE on error
137  ******************************************************/
138
139 gint
140 gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
141 {
142   struct v4l2_buffer buffer;
143
144   buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
145   while (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, &buffer) < 0) {
146     /* if the sync() got interrupted, we can retry */
147     if (errno != EINTR) {
148       GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
149           ("could not sync on a buffer on device %s: %s",
150               GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
151       return -1;
152     }
153     GST_DEBUG_OBJECT (v4l2src, "grab got interrupted");
154   }
155
156   GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index);
157
158   return buffer.index;
159 }
160
161
162 /******************************************************
163  * gst_v4l2src_get_capture():
164  *   get capture parameters
165  * return value: TRUE on success, FALSE on error
166  ******************************************************/
167
168 gboolean
169 gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
170 {
171   DEBUG ("Getting capture format");
172
173   GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
174
175   v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
176   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_FMT,
177           &v4l2src->format) < 0) {
178     GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
179         ("failed to get pixelformat for device %s: %s",
180             GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
181     return FALSE;
182   }
183
184   return TRUE;
185 }
186
187
188 /******************************************************
189  * gst_v4l2src_set_capture():
190  *   set capture parameters
191  * return value: TRUE on success, FALSE on error
192  ******************************************************/
193
194 gboolean
195 gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
196     struct v4l2_fmtdesc * fmt, gint width, gint height)
197 {
198   DEBUG ("Setting capture format to %dx%d, format %s",
199       width, height, fmt->description);
200
201   GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
202   GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src));
203
204   memset (&v4l2src->format, 0, sizeof (struct v4l2_format));
205   v4l2src->format.fmt.pix.width = width;
206   v4l2src->format.fmt.pix.height = height;
207   v4l2src->format.fmt.pix.pixelformat = fmt->pixelformat;
208   v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED;
209   v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
210
211   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_S_FMT,
212           &v4l2src->format) < 0) {
213     GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
214         ("failed to set pixelformat to %s @ %dx%d for device %s: %s",
215             fmt->description, width, height, GST_V4L2ELEMENT (v4l2src)->device,
216             g_strerror (errno)));
217     return FALSE;
218   }
219
220   /* update internal info */
221   return gst_v4l2src_get_capture (v4l2src);
222 }
223
224
225 /******************************************************
226  * gst_v4l2src_capture_init():
227  *   initialize the capture system
228  * return value: TRUE on success, FALSE on error
229  ******************************************************/
230
231 gboolean
232 gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
233 {
234   gint n;
235   guint buffers;
236
237   GST_DEBUG_OBJECT (v4l2src, "initting the capture system");
238
239   GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
240   GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src));
241
242   /* request buffer info */
243   buffers = v4l2src->breq.count;
244   if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS) {
245     v4l2src->breq.count = GST_V4L2_MAX_BUFFERS;
246   }
247   if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
248     v4l2src->breq.count = GST_V4L2_MIN_BUFFERS;
249   }
250   v4l2src->breq.type = v4l2src->format.type;
251   v4l2src->breq.memory = V4L2_MEMORY_MMAP;
252   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_REQBUFS,
253           &v4l2src->breq) < 0) {
254     GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
255         (_("Could not get buffers from device \"%s\"."),
256             GST_V4L2ELEMENT (v4l2src)->device),
257         ("error requesting %d buffers: %s", v4l2src->breq.count,
258             g_strerror (errno)));
259     return FALSE;
260   }
261
262   if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
263     GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
264         (_("Could not get enough buffers from device \"%s\"."),
265             GST_V4L2ELEMENT (v4l2src)->device),
266         ("we received %d, we want at least %d", v4l2src->breq.count,
267             GST_V4L2_MIN_BUFFERS));
268     v4l2src->breq.count = buffers;
269     return FALSE;
270   }
271   if (v4l2src->breq.count != buffers)
272     g_object_notify (G_OBJECT (v4l2src), "num_buffers");
273
274   GST_INFO_OBJECT (v4l2src,
275       "Got %d buffers (" GST_FOURCC_FORMAT ") of size %d KB\n",
276       v4l2src->breq.count,
277       GST_FOURCC_ARGS (v4l2src->format.fmt.pix.pixelformat),
278       v4l2src->format.fmt.pix.sizeimage / 1024);
279
280   /* Map the buffers */
281   v4l2src->pool = g_new (GstV4l2BufferPool, 1);
282   gst_atomic_int_init (&v4l2src->pool->refcount, 1);
283   v4l2src->pool->video_fd = GST_V4L2ELEMENT (v4l2src)->video_fd;
284   v4l2src->pool->buffer_count = v4l2src->breq.count;
285   v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count);
286
287   for (n = 0; n < v4l2src->breq.count; n++) {
288     GstV4l2Buffer *buffer = &v4l2src->pool->buffers[n];
289
290     gst_atomic_int_init (&buffer->refcount, 1);
291     buffer->pool = v4l2src->pool;
292     buffer->buffer.index = n;
293     buffer->buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
294     if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QUERYBUF,
295             &buffer->buffer) < 0) {
296       GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
297           ("Could not get buffer properties of buffer %d: %s", n,
298               g_strerror (errno)));
299       gst_v4l2src_capture_deinit (v4l2src);
300       return FALSE;
301     }
302     buffer->start =
303         mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
304         GST_V4L2ELEMENT (v4l2src)->video_fd, buffer->buffer.m.offset);
305     if (buffer->start == MAP_FAILED) {
306       GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
307           ("Could not mmap video buffer %d: %s", n, g_strerror (errno)));
308       buffer->start = 0;
309       gst_v4l2src_capture_deinit (v4l2src);
310       return FALSE;
311     }
312     buffer->length = buffer->buffer.length;
313     if (!gst_v4l2src_queue_frame (v4l2src, n)) {
314       gst_v4l2src_capture_deinit (v4l2src);
315       return FALSE;
316     }
317   }
318
319   GST_V4L2_SET_ACTIVE (GST_V4L2ELEMENT (v4l2src));
320   return TRUE;
321 }
322
323
324 /******************************************************
325  * gst_v4l2src_capture_start():
326  *   start streaming capture
327  * return value: TRUE on success, FALSE on error
328  ******************************************************/
329
330 gboolean
331 gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
332 {
333   gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
334
335   GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
336
337   GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
338   if (!GST_V4L2_IS_ACTIVE (GST_V4L2ELEMENT (v4l2src))) {
339     gst_pad_renegotiate (v4l2src->srcpad);
340   }
341   GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
342
343   v4l2src->quit = FALSE;
344
345   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMON, &type) < 0) {
346     GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ, (NULL),
347         ("Error starting streaming capture from device %s: %s",
348             GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
349     return FALSE;
350   }
351
352   return TRUE;
353 }
354
355
356 /******************************************************
357  * gst_v4l2src_capture_stop():
358  *   stop streaming capture
359  * return value: TRUE on success, FALSE on error
360  ******************************************************/
361
362 gboolean
363 gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
364 {
365   gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
366
367   GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
368   GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
369   GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
370
371   /* we actually need to sync on all queued buffers but not
372    * on the non-queued ones */
373   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMOFF, &type) < 0) {
374     GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE, (NULL),
375         ("Error stopping streaming capture from device %s: %s",
376             GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
377     return FALSE;
378   }
379
380   /* make an optional pending wait stop */
381   v4l2src->quit = TRUE;
382
383   return TRUE;
384 }
385
386 static void
387 gst_v4l2src_buffer_pool_free (GstV4l2BufferPool * pool, gboolean do_close)
388 {
389   guint i;
390
391   for (i = 0; i < pool->buffer_count; i++) {
392     gst_atomic_int_destroy (&pool->buffers[i].refcount);
393     munmap (pool->buffers[i].start, pool->buffers[i].length);
394   }
395   g_free (pool->buffers);
396   gst_atomic_int_destroy (&pool->refcount);
397   if (do_close)
398     close (pool->video_fd);
399   g_free (pool);
400 }
401
402 void
403 gst_v4l2src_free_buffer (GstBuffer * buffer)
404 {
405   GstV4l2Buffer *buf = (GstV4l2Buffer *) GST_BUFFER_PRIVATE (buffer);
406
407   GST_LOG ("freeing buffer %p (nr. %d)", buffer, buf->buffer.index);
408
409   if (!gst_atomic_int_dec_and_test (&buf->refcount)) {
410     /* we're still in use, add to queue again 
411        note: this might fail because the device is already stopped (race) */
412     if (ioctl (buf->pool->video_fd, VIDIOC_QBUF, &buf->buffer) < 0)
413       GST_INFO ("readding to queue failed, assuming video device is stopped");
414   }
415   if (gst_atomic_int_dec_and_test (&buf->pool->refcount)) {
416     /* we're last thing that used all this */
417     gst_v4l2src_buffer_pool_free (buf->pool, TRUE);
418   }
419 }
420
421 /******************************************************
422  * gst_v4l2src_capture_deinit():
423  *   deinitialize the capture system
424  * return value: TRUE on success, FALSE on error
425  ******************************************************/
426
427 gboolean
428 gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
429 {
430   gint i, dequeue = 0;
431
432   GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
433
434   GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
435   GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
436
437   /* free the buffers */
438   for (i = 0; i < v4l2src->breq.count; i++) {
439     if (gst_atomic_int_dec_and_test (&v4l2src->pool->buffers[i].refcount))
440       dequeue++;
441   }
442   for (i = 0; i < dequeue; i++) {
443     struct v4l2_buffer buffer;
444
445     buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
446     if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, &buffer) < 0)
447       GST_WARNING_OBJECT (v4l2src,
448           "Could not dequeue buffer on uninitialization");
449   }
450   if (gst_atomic_int_dec_and_test (&v4l2src->pool->refcount)) {
451     /* we're last thing that used all this */
452     gst_v4l2src_buffer_pool_free (v4l2src->pool, FALSE);
453   }
454   v4l2src->pool = NULL;
455
456   GST_V4L2_SET_INACTIVE (GST_V4L2ELEMENT (v4l2src));
457   return TRUE;
458 }
459
460
461 /*
462
463  */
464
465 gboolean
466 gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
467     struct v4l2_fmtdesc * format,
468     gint * min_w, gint * max_w, gint * min_h, gint * max_h)
469 {
470   struct v4l2_format fmt;
471
472   GST_LOG_OBJECT (v4l2src, "getting size limits with format " GST_FOURCC_FORMAT,
473       GST_FOURCC_ARGS (format->pixelformat));
474
475   /* get size delimiters */
476   memset (&fmt, 0, sizeof (fmt));
477   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
478   fmt.fmt.pix.width = 0;
479   fmt.fmt.pix.height = 0;
480   fmt.fmt.pix.pixelformat = format->pixelformat;
481   fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
482   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
483     return FALSE;
484   }
485
486   if (min_w)
487     *min_w = fmt.fmt.pix.width;
488   if (min_h)
489     *min_h = fmt.fmt.pix.height;
490   GST_LOG_OBJECT (v4l2src, "got min size %dx%d", fmt.fmt.pix.width,
491       fmt.fmt.pix.height);
492
493   fmt.fmt.pix.width = G_MAXINT;
494   fmt.fmt.pix.height = 576;
495   if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
496     return FALSE;
497   }
498
499   if (max_w)
500     *max_w = fmt.fmt.pix.width;
501   if (max_h)
502     *max_h = fmt.fmt.pix.height;
503   GST_LOG_OBJECT (v4l2src, "got max size %dx%d", fmt.fmt.pix.width,
504       fmt.fmt.pix.height);
505
506   return TRUE;
507 }