source: trunk/third/gst-plugins/sys/v4l2/v4l2src_calls.c @ 21443

Revision 21443, 15.6 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21442, which included commits to RCS files with non-trunk default branches.
Line 
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
58gboolean
59gst_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
99gboolean
100gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
101{
102  g_slist_foreach (v4l2src->formats, (GFunc) g_free, NULL);
103  g_slist_free (v4l2src->formats);
104  v4l2src->formats = NULL;
105
106  return TRUE;
107}
108
109
110/******************************************************
111 * gst_v4l2src_queue_frame():
112 *   queue a frame for capturing
113 * return value: TRUE on success, FALSE on error
114 ******************************************************/
115
116gboolean
117gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
118{
119  GST_LOG_OBJECT (v4l2src, "queueing frame %u", i);
120
121  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QBUF,
122          &v4l2src->pool->buffers[i].buffer) < 0) {
123    GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE,
124        (_("Could not write to device \"%s\"."),
125            GST_V4L2ELEMENT (v4l2src)->device),
126        ("Error queueing buffer %u on device %s", i, g_strerror (errno)));
127    return FALSE;
128  }
129
130  return TRUE;
131}
132
133
134/******************************************************
135 * gst_v4l2src_grab_frame ():
136 *   grab a frame for capturing
137 * return value: TRUE on success, FALSE on error
138 ******************************************************/
139
140gint
141gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
142{
143  struct v4l2_buffer buffer;
144
145  buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
146  while (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, &buffer) < 0) {
147    /* if the sync() got interrupted, we can retry */
148    if (errno != EINTR) {
149      GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
150          ("could not sync on a buffer on device %s: %s",
151              GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
152      return -1;
153    }
154    GST_DEBUG_OBJECT (v4l2src, "grab got interrupted");
155  }
156
157  GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index);
158
159  return buffer.index;
160}
161
162
163/******************************************************
164 * gst_v4l2src_get_capture():
165 *   get capture parameters
166 * return value: TRUE on success, FALSE on error
167 ******************************************************/
168
169gboolean
170gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
171{
172  DEBUG ("Getting capture format");
173
174  GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
175
176  v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
177  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_FMT,
178          &v4l2src->format) < 0) {
179    GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
180        ("failed to get pixelformat for device %s: %s",
181            GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
182    return FALSE;
183  }
184
185  return TRUE;
186}
187
188
189/******************************************************
190 * gst_v4l2src_set_capture():
191 *   set capture parameters
192 * return value: TRUE on success, FALSE on error
193 ******************************************************/
194
195gboolean
196gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
197    struct v4l2_fmtdesc * fmt, gint width, gint height)
198{
199  DEBUG ("Setting capture format to %dx%d, format %s",
200      width, height, fmt->description);
201
202  GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
203  GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src));
204
205  memset (&v4l2src->format, 0, sizeof (struct v4l2_format));
206  v4l2src->format.fmt.pix.width = width;
207  v4l2src->format.fmt.pix.height = height;
208  v4l2src->format.fmt.pix.pixelformat = fmt->pixelformat;
209  v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED;
210  v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
211
212  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_S_FMT,
213          &v4l2src->format) < 0) {
214    GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
215        ("failed to set pixelformat to %s @ %dx%d for device %s: %s",
216            fmt->description, width, height, GST_V4L2ELEMENT (v4l2src)->device,
217            g_strerror (errno)));
218    return FALSE;
219  }
220
221  /* update internal info */
222  return gst_v4l2src_get_capture (v4l2src);
223}
224
225
226/******************************************************
227 * gst_v4l2src_capture_init():
228 *   initialize the capture system
229 * return value: TRUE on success, FALSE on error
230 ******************************************************/
231
232gboolean
233gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
234{
235  gint n;
236  guint buffers;
237
238  GST_DEBUG_OBJECT (v4l2src, "initting the capture system");
239
240  GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
241  GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src));
242
243  /* request buffer info */
244  buffers = v4l2src->breq.count;
245  if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS) {
246    v4l2src->breq.count = GST_V4L2_MAX_BUFFERS;
247  }
248  if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
249    v4l2src->breq.count = GST_V4L2_MIN_BUFFERS;
250  }
251  v4l2src->breq.type = v4l2src->format.type;
252  v4l2src->breq.memory = V4L2_MEMORY_MMAP;
253  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_REQBUFS,
254          &v4l2src->breq) < 0) {
255    GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
256        (_("Could not get buffers from device \"%s\"."),
257            GST_V4L2ELEMENT (v4l2src)->device),
258        ("error requesting %d buffers: %s", v4l2src->breq.count,
259            g_strerror (errno)));
260    return FALSE;
261  }
262
263  if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
264    GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
265        (_("Could not get enough buffers from device \"%s\"."),
266            GST_V4L2ELEMENT (v4l2src)->device),
267        ("we received %d, we want at least %d", v4l2src->breq.count,
268            GST_V4L2_MIN_BUFFERS));
269    v4l2src->breq.count = buffers;
270    return FALSE;
271  }
272  if (v4l2src->breq.count != buffers)
273    g_object_notify (G_OBJECT (v4l2src), "num_buffers");
274
275  GST_INFO_OBJECT (v4l2src,
276      "Got %d buffers (" GST_FOURCC_FORMAT ") of size %d KB\n",
277      v4l2src->breq.count,
278      GST_FOURCC_ARGS (v4l2src->format.fmt.pix.pixelformat),
279      v4l2src->format.fmt.pix.sizeimage / 1024);
280
281  /* Map the buffers */
282  v4l2src->pool = g_new (GstV4l2BufferPool, 1);
283  gst_atomic_int_init (&v4l2src->pool->refcount, 1);
284  v4l2src->pool->video_fd = GST_V4L2ELEMENT (v4l2src)->video_fd;
285  v4l2src->pool->buffer_count = v4l2src->breq.count;
286  v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count);
287
288  for (n = 0; n < v4l2src->breq.count; n++) {
289    GstV4l2Buffer *buffer = &v4l2src->pool->buffers[n];
290
291    gst_atomic_int_init (&buffer->refcount, 1);
292    buffer->pool = v4l2src->pool;
293    buffer->buffer.index = n;
294    buffer->buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
295    if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QUERYBUF,
296            &buffer->buffer) < 0) {
297      GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
298          ("Could not get buffer properties of buffer %d: %s", n,
299              g_strerror (errno)));
300      gst_v4l2src_capture_deinit (v4l2src);
301      return FALSE;
302    }
303    buffer->start =
304        mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
305        GST_V4L2ELEMENT (v4l2src)->video_fd, buffer->buffer.m.offset);
306    if (buffer->start == MAP_FAILED) {
307      GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
308          ("Could not mmap video buffer %d: %s", n, g_strerror (errno)));
309      buffer->start = 0;
310      gst_v4l2src_capture_deinit (v4l2src);
311      return FALSE;
312    }
313    buffer->length = buffer->buffer.length;
314    if (!gst_v4l2src_queue_frame (v4l2src, n)) {
315      gst_v4l2src_capture_deinit (v4l2src);
316      return FALSE;
317    }
318  }
319
320  GST_V4L2_SET_ACTIVE (GST_V4L2ELEMENT (v4l2src));
321
322  return TRUE;
323}
324
325
326/******************************************************
327 * gst_v4l2src_capture_start():
328 *   start streaming capture
329 * return value: TRUE on success, FALSE on error
330 ******************************************************/
331
332gboolean
333gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
334{
335  gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
336
337  GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
338
339  GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
340  if (!GST_V4L2_IS_ACTIVE (GST_V4L2ELEMENT (v4l2src))) {
341    gst_pad_renegotiate (v4l2src->srcpad);
342  }
343  GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
344
345  v4l2src->quit = FALSE;
346
347  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMON, &type) < 0) {
348    GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ, (NULL),
349        ("Error starting streaming capture from device %s: %s",
350            GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
351    return FALSE;
352  }
353
354  v4l2src->is_capturing = TRUE;
355
356  return TRUE;
357}
358
359
360/******************************************************
361 * gst_v4l2src_capture_stop():
362 *   stop streaming capture
363 * return value: TRUE on success, FALSE on error
364 ******************************************************/
365
366gboolean
367gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
368{
369  gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
370
371  GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
372  GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
373  GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
374
375  /* we actually need to sync on all queued buffers but not
376   * on the non-queued ones */
377  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMOFF, &type) < 0) {
378    GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE, (NULL),
379        ("Error stopping streaming capture from device %s: %s",
380            GST_V4L2ELEMENT (v4l2src)->device, g_strerror (errno)));
381    return FALSE;
382  }
383
384  /* make an optional pending wait stop */
385  v4l2src->quit = TRUE;
386  v4l2src->is_capturing = FALSE;
387
388  return TRUE;
389}
390
391static void
392gst_v4l2src_buffer_pool_free (GstV4l2BufferPool * pool, gboolean do_close)
393{
394  guint i;
395
396  for (i = 0; i < pool->buffer_count; i++) {
397    gst_atomic_int_destroy (&pool->buffers[i].refcount);
398    munmap (pool->buffers[i].start, pool->buffers[i].length);
399  }
400  g_free (pool->buffers);
401  gst_atomic_int_destroy (&pool->refcount);
402  if (do_close)
403    close (pool->video_fd);
404  g_free (pool);
405}
406
407void
408gst_v4l2src_free_buffer (GstBuffer * buffer)
409{
410  GstV4l2Buffer *buf = (GstV4l2Buffer *) GST_BUFFER_PRIVATE (buffer);
411
412  GST_LOG ("freeing buffer %p (nr. %d)", buffer, buf->buffer.index);
413
414  if (!gst_atomic_int_dec_and_test (&buf->refcount)) {
415    /* we're still in use, add to queue again
416       note: this might fail because the device is already stopped (race) */
417    if (ioctl (buf->pool->video_fd, VIDIOC_QBUF, &buf->buffer) < 0)
418      GST_INFO ("readding to queue failed, assuming video device is stopped");
419  }
420  if (gst_atomic_int_dec_and_test (&buf->pool->refcount)) {
421    /* we're last thing that used all this */
422    gst_v4l2src_buffer_pool_free (buf->pool, TRUE);
423  }
424}
425
426/******************************************************
427 * gst_v4l2src_capture_deinit():
428 *   deinitialize the capture system
429 * return value: TRUE on success, FALSE on error
430 ******************************************************/
431
432gboolean
433gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
434{
435  gint i, dequeue = 0;
436
437  GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
438
439  GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src));
440  GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src));
441
442  /* free the buffers */
443  for (i = 0; i < v4l2src->breq.count; i++) {
444    if (gst_atomic_int_dec_and_test (&v4l2src->pool->buffers[i].refcount))
445      dequeue++;
446  }
447  for (i = 0; i < dequeue; i++) {
448    struct v4l2_buffer buffer;
449
450    buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
451    if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, &buffer) < 0)
452      GST_WARNING_OBJECT (v4l2src,
453          "Could not dequeue buffer on uninitialization");
454  }
455  if (gst_atomic_int_dec_and_test (&v4l2src->pool->refcount)) {
456    /* we're last thing that used all this */
457    gst_v4l2src_buffer_pool_free (v4l2src->pool, FALSE);
458  }
459  v4l2src->pool = NULL;
460
461  GST_V4L2_SET_INACTIVE (GST_V4L2ELEMENT (v4l2src));
462  return TRUE;
463}
464
465
466/*
467
468 */
469
470gboolean
471gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
472    struct v4l2_fmtdesc * format,
473    gint * min_w, gint * max_w, gint * min_h, gint * max_h)
474{
475  struct v4l2_format fmt;
476
477  GST_LOG_OBJECT (v4l2src, "getting size limits with format " GST_FOURCC_FORMAT,
478      GST_FOURCC_ARGS (format->pixelformat));
479
480  /* get size delimiters */
481  memset (&fmt, 0, sizeof (fmt));
482  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
483  fmt.fmt.pix.width = 0;
484  fmt.fmt.pix.height = 0;
485  fmt.fmt.pix.pixelformat = format->pixelformat;
486  fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
487  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
488    return FALSE;
489  }
490
491  if (min_w)
492    *min_w = fmt.fmt.pix.width;
493  if (min_h)
494    *min_h = fmt.fmt.pix.height;
495  GST_LOG_OBJECT (v4l2src, "got min size %dx%d", fmt.fmt.pix.width,
496      fmt.fmt.pix.height);
497
498  fmt.fmt.pix.width = G_MAXINT;
499  fmt.fmt.pix.height = 576;
500  if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
501    return FALSE;
502  }
503
504  if (max_w)
505    *max_w = fmt.fmt.pix.width;
506  if (max_h)
507    *max_h = fmt.fmt.pix.height;
508  GST_LOG_OBJECT (v4l2src, "got max size %dx%d", fmt.fmt.pix.width,
509      fmt.fmt.pix.height);
510
511  return TRUE;
512}
Note: See TracBrowser for help on using the repository browser.