Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / sys / v4l2 / gstv4l2bufferpool.c
1 /* GStreamer
2  *
3  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
4  *               2006 Edgard Lima <edgard.lima@indt.org.br>
5  *               2009 Texas Instruments, Inc - http://www.ti.com/
6  *
7  * gstv4l2bufferpool.c V4L2 buffer pool class
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #include <sys/mman.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include "gst/video/video.h"
34
35 #include <gstv4l2bufferpool.h>
36 #include "gstv4l2src.h"
37 #ifdef HAVE_EXPERIMENTAL
38 #include "gstv4l2sink.h"
39 #endif
40 #include "v4l2_calls.h"
41 #include "gst/gst-i18n-plugin.h"
42 #include <gst/glib-compat-private.h>
43
44 /* videodev2.h is not versioned and we can't easily check for the presence
45  * of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define
46  * was added in the same commit as V4L2_FIELD_INTERLACED_{TB,BT} (b2787845) */
47 #ifndef V4L2_CAP_VIDEO_OUTPUT_OVERLAY
48 #define V4L2_FIELD_INTERLACED_TB 8
49 #define V4L2_FIELD_INTERLACED_BT 9
50 #endif
51
52
53 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
54 #define GST_CAT_DEFAULT v4l2_debug
55
56
57 /*
58  * GstV4l2Buffer:
59  */
60
61 static GstBufferClass *v4l2buffer_parent_class = NULL;
62
63 static void
64 gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer)
65 {
66   GstV4l2BufferPool *pool;
67   gboolean resuscitated = FALSE;
68   gint index;
69
70   pool = buffer->pool;
71
72   index = buffer->vbuffer.index;
73
74   GST_LOG_OBJECT (pool->v4l2elem, "finalizing buffer %p %d", buffer, index);
75
76   GST_V4L2_BUFFER_POOL_LOCK (pool);
77   if (pool->running) {
78     if (pool->requeuebuf) {
79       if (!gst_v4l2_buffer_pool_qbuf (pool, buffer)) {
80         GST_WARNING ("could not requeue buffer %p %d", buffer, index);
81       } else {
82         resuscitated = TRUE;
83       }
84     } else {
85       resuscitated = TRUE;
86       /* XXX double check this... I think it is ok to not synchronize this
87        * w.r.t. destruction of the pool, since the buffer is still live and
88        * the buffer holds a ref to the pool..
89        */
90       g_async_queue_push (pool->avail_buffers, buffer);
91     }
92   } else {
93     GST_LOG_OBJECT (pool->v4l2elem, "the pool is shutting down");
94   }
95
96   if (resuscitated) {
97     /* FIXME: check that the caps didn't change */
98     GST_LOG_OBJECT (pool->v4l2elem, "reviving buffer %p, %d", buffer, index);
99     gst_buffer_ref (GST_BUFFER (buffer));
100     GST_BUFFER_SIZE (buffer) = 0;
101     pool->buffers[index] = buffer;
102   }
103
104   GST_V4L2_BUFFER_POOL_UNLOCK (pool);
105
106   if (!resuscitated) {
107     GST_LOG_OBJECT (pool->v4l2elem,
108         "buffer %p (data %p, len %u) not recovered, unmapping",
109         buffer, GST_BUFFER_DATA (buffer), buffer->vbuffer.length);
110     gst_mini_object_unref (GST_MINI_OBJECT (pool));
111     v4l2_munmap ((void *) GST_BUFFER_DATA (buffer), buffer->vbuffer.length);
112
113     GST_MINI_OBJECT_CLASS (v4l2buffer_parent_class)->finalize (GST_MINI_OBJECT
114         (buffer));
115   }
116 }
117
118 static void
119 gst_v4l2_buffer_class_init (gpointer g_class, gpointer class_data)
120 {
121   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
122
123   v4l2buffer_parent_class = g_type_class_peek_parent (g_class);
124
125   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
126       gst_v4l2_buffer_finalize;
127 }
128
129 GType
130 gst_v4l2_buffer_get_type (void)
131 {
132   static GType _gst_v4l2_buffer_type;
133
134   if (G_UNLIKELY (_gst_v4l2_buffer_type == 0)) {
135     static const GTypeInfo v4l2_buffer_info = {
136       sizeof (GstBufferClass),
137       NULL,
138       NULL,
139       gst_v4l2_buffer_class_init,
140       NULL,
141       NULL,
142       sizeof (GstV4l2Buffer),
143       0,
144       NULL,
145       NULL
146     };
147     _gst_v4l2_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
148         "GstV4l2Buffer", &v4l2_buffer_info, 0);
149   }
150   return _gst_v4l2_buffer_type;
151 }
152
153 static GstV4l2Buffer *
154 gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps)
155 {
156   GstV4l2Buffer *ret;
157   guint8 *data;
158
159   ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER);
160
161   GST_LOG_OBJECT (pool->v4l2elem, "creating buffer %u, %p in pool %p", index,
162       ret, pool);
163
164   ret->pool =
165       (GstV4l2BufferPool *) gst_mini_object_ref (GST_MINI_OBJECT (pool));
166
167   ret->vbuffer.index = index;
168   ret->vbuffer.type = pool->type;
169   ret->vbuffer.memory = V4L2_MEMORY_MMAP;
170
171   if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &ret->vbuffer) < 0)
172     goto querybuf_failed;
173
174   GST_LOG_OBJECT (pool->v4l2elem, "  index:     %u", ret->vbuffer.index);
175   GST_LOG_OBJECT (pool->v4l2elem, "  type:      %d", ret->vbuffer.type);
176   GST_LOG_OBJECT (pool->v4l2elem, "  bytesused: %u", ret->vbuffer.bytesused);
177   GST_LOG_OBJECT (pool->v4l2elem, "  flags:     %08x", ret->vbuffer.flags);
178   GST_LOG_OBJECT (pool->v4l2elem, "  field:     %d", ret->vbuffer.field);
179   GST_LOG_OBJECT (pool->v4l2elem, "  memory:    %d", ret->vbuffer.memory);
180   if (ret->vbuffer.memory == V4L2_MEMORY_MMAP)
181     GST_LOG_OBJECT (pool->v4l2elem, "  MMAP offset:  %u",
182         ret->vbuffer.m.offset);
183   GST_LOG_OBJECT (pool->v4l2elem, "  length:    %u", ret->vbuffer.length);
184   GST_LOG_OBJECT (pool->v4l2elem, "  input:     %u", ret->vbuffer.input);
185
186   data = (guint8 *) v4l2_mmap (0, ret->vbuffer.length,
187       PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd,
188       ret->vbuffer.m.offset);
189
190   if (data == MAP_FAILED)
191     goto mmap_failed;
192
193   GST_BUFFER_DATA (ret) = data;
194   GST_BUFFER_SIZE (ret) = ret->vbuffer.length;
195
196   GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY);
197
198   gst_buffer_set_caps (GST_BUFFER (ret), caps);
199
200   return ret;
201
202   /* ERRORS */
203 querybuf_failed:
204   {
205     gint errnosave = errno;
206
207     GST_WARNING ("Failed QUERYBUF: %s", g_strerror (errnosave));
208     gst_buffer_unref (GST_BUFFER (ret));
209     errno = errnosave;
210     return NULL;
211   }
212 mmap_failed:
213   {
214     gint errnosave = errno;
215
216     GST_WARNING ("Failed to mmap: %s", g_strerror (errnosave));
217     gst_buffer_unref (GST_BUFFER (ret));
218     errno = errnosave;
219     return NULL;
220   }
221 }
222
223
224 /*
225  * GstV4l2BufferPool:
226  */
227
228 static GstMiniObjectClass *buffer_pool_parent_class = NULL;
229
230 static void
231 gst_v4l2_buffer_pool_finalize (GstV4l2BufferPool * pool)
232 {
233   g_mutex_free (pool->lock);
234   pool->lock = NULL;
235
236   g_async_queue_unref (pool->avail_buffers);
237   pool->avail_buffers = NULL;
238
239   if (pool->video_fd >= 0)
240     v4l2_close (pool->video_fd);
241
242   if (pool->buffers) {
243     g_free (pool->buffers);
244     pool->buffers = NULL;
245   }
246
247   GST_MINI_OBJECT_CLASS (buffer_pool_parent_class)->finalize (GST_MINI_OBJECT
248       (pool));
249 }
250
251 static void
252 gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool, gpointer g_class)
253 {
254   pool->lock = g_mutex_new ();
255   pool->running = FALSE;
256   pool->num_live_buffers = 0;
257 }
258
259 static void
260 gst_v4l2_buffer_pool_class_init (gpointer g_class, gpointer class_data)
261 {
262   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
263
264   buffer_pool_parent_class = g_type_class_peek_parent (g_class);
265
266   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
267       gst_v4l2_buffer_pool_finalize;
268 }
269
270 GType
271 gst_v4l2_buffer_pool_get_type (void)
272 {
273   static GType _gst_v4l2_buffer_pool_type;
274
275   if (G_UNLIKELY (_gst_v4l2_buffer_pool_type == 0)) {
276     static const GTypeInfo v4l2_buffer_pool_info = {
277       sizeof (GstMiniObjectClass),
278       NULL,
279       NULL,
280       gst_v4l2_buffer_pool_class_init,
281       NULL,
282       NULL,
283       sizeof (GstV4l2BufferPool),
284       0,
285       (GInstanceInitFunc) gst_v4l2_buffer_pool_init,
286       NULL
287     };
288     _gst_v4l2_buffer_pool_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
289         "GstV4l2BufferPool", &v4l2_buffer_pool_info, 0);
290   }
291   return _gst_v4l2_buffer_pool_type;
292 }
293
294
295 /* this is somewhat of a hack.. but better to keep the hack in
296  * one place than copy/pasting it around..
297  */
298 static GstV4l2Object *
299 get_v4l2_object (GstElement * v4l2elem)
300 {
301   GstV4l2Object *v4l2object = NULL;
302   if (GST_IS_V4L2SRC (v4l2elem)) {
303     v4l2object = (GST_V4L2SRC (v4l2elem))->v4l2object;
304 #ifdef HAVE_EXPERIMENTAL
305   } else if (GST_IS_V4L2SINK (v4l2elem)) {
306     v4l2object = (GST_V4L2SINK (v4l2elem))->v4l2object;
307 #endif
308   } else {
309     GST_ERROR_OBJECT (v4l2elem, "unknown v4l2 element");
310   }
311   return v4l2object;
312 }
313
314
315
316 /**
317  * gst_v4l2_buffer_pool_new:
318  * @v4l2elem:  the v4l2 element (src or sink) that owns this pool
319  * @fd:   the video device file descriptor
320  * @num_buffers:  the requested number of buffers in the pool
321  * @caps:  the caps to set on the buffer
322  * @requeuebuf: if %TRUE, and if the pool is still in the running state, a
323  *  buffer with no remaining references is immediately passed back to v4l2
324  *  (VIDIOC_QBUF), otherwise it is returned to the pool of available buffers
325  *  (which can be accessed via gst_v4l2_buffer_pool_get().
326  *
327  * Construct a new buffer pool.
328  *
329  * Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources
330  */
331 GstV4l2BufferPool *
332 gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers,
333     GstCaps * caps, gboolean requeuebuf, enum v4l2_buf_type type)
334 {
335   GstV4l2BufferPool *pool;
336   gint n;
337   struct v4l2_requestbuffers breq;
338
339   pool = (GstV4l2BufferPool *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER_POOL);
340
341   pool->video_fd = v4l2_dup (fd);
342   if (pool->video_fd < 0)
343     goto dup_failed;
344
345
346   /* first, lets request buffers, and see how many we can get: */
347   GST_DEBUG_OBJECT (v4l2elem, "STREAMING, requesting %d MMAP buffers",
348       num_buffers);
349
350   memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
351   breq.type = type;
352   breq.count = num_buffers;
353   breq.memory = V4L2_MEMORY_MMAP;
354
355   if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &breq) < 0)
356     goto reqbufs_failed;
357
358   GST_LOG_OBJECT (v4l2elem, " count:  %u", breq.count);
359   GST_LOG_OBJECT (v4l2elem, " type:   %d", breq.type);
360   GST_LOG_OBJECT (v4l2elem, " memory: %d", breq.memory);
361
362   if (breq.count < GST_V4L2_MIN_BUFFERS)
363     goto no_buffers;
364
365   if (num_buffers != breq.count) {
366     GST_WARNING_OBJECT (v4l2elem, "using %u buffers instead", breq.count);
367     num_buffers = breq.count;
368   }
369
370   pool->v4l2elem = v4l2elem;
371   pool->requeuebuf = requeuebuf;
372   pool->type = type;
373   pool->buffer_count = num_buffers;
374   pool->buffers = g_new0 (GstV4l2Buffer *, num_buffers);
375   pool->avail_buffers = g_async_queue_new ();
376
377   /* now, map the buffers: */
378   for (n = 0; n < num_buffers; n++) {
379     pool->buffers[n] = gst_v4l2_buffer_new (pool, n, caps);
380     if (!pool->buffers[n])
381       goto buffer_new_failed;
382     pool->num_live_buffers++;
383     g_async_queue_push (pool->avail_buffers, pool->buffers[n]);
384   }
385
386   return pool;
387
388   /* ERRORS */
389 dup_failed:
390   {
391     gint errnosave = errno;
392
393     gst_mini_object_unref (GST_MINI_OBJECT (pool));
394
395     errno = errnosave;
396
397     return NULL;
398   }
399 reqbufs_failed:
400   {
401     GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem);
402     GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ,
403         (_("Could not get buffers from device '%s'."),
404             v4l2object->videodev),
405         ("error requesting %d buffers: %s", num_buffers, g_strerror (errno)));
406     return NULL;
407   }
408 no_buffers:
409   {
410     GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem);
411     GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ,
412         (_("Could not get enough buffers from device '%s'."),
413             v4l2object->videodev),
414         ("we received %d from device '%s', we want at least %d",
415             breq.count, v4l2object->videodev, GST_V4L2_MIN_BUFFERS));
416     return NULL;
417   }
418 buffer_new_failed:
419   {
420     gint errnosave = errno;
421
422     gst_v4l2_buffer_pool_destroy (pool);
423
424     errno = errnosave;
425
426     return NULL;
427   }
428 }
429
430 /**
431  * gst_v4l2_buffer_pool_destroy:
432  * @pool: the pool
433  *
434  * Free all resources in the pool and the pool itself.
435  */
436 void
437 gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool)
438 {
439   gint n;
440
441   GST_V4L2_BUFFER_POOL_LOCK (pool);
442   pool->running = FALSE;
443   GST_V4L2_BUFFER_POOL_UNLOCK (pool);
444
445   GST_DEBUG_OBJECT (pool->v4l2elem, "destroy pool");
446
447   /* after this point, no more buffers will be queued or dequeued; no buffer
448    * from pool->buffers that is NULL will be set to a buffer, and no buffer that
449    * is not NULL will be pushed out. */
450
451   /* miniobjects have no dispose, so they can't break ref-cycles, as buffers ref
452    * the pool, we need to unref the buffer to properly finalize te pool */
453   for (n = 0; n < pool->buffer_count; n++) {
454     GstBuffer *buf;
455
456     GST_V4L2_BUFFER_POOL_LOCK (pool);
457     buf = GST_BUFFER (pool->buffers[n]);
458     GST_V4L2_BUFFER_POOL_UNLOCK (pool);
459
460     if (buf)
461       /* we own the ref if the buffer is in pool->buffers; drop it. */
462       gst_buffer_unref (buf);
463   }
464
465   gst_mini_object_unref (GST_MINI_OBJECT (pool));
466 }
467
468 /**
469  * gst_v4l2_buffer_pool_get:
470  * @pool:   the "this" object
471  * @blocking:  should this call suspend until there is a buffer available
472  *    in the buffer pool?
473  *
474  * Get an available buffer in the pool
475  */
476 GstV4l2Buffer *
477 gst_v4l2_buffer_pool_get (GstV4l2BufferPool * pool, gboolean blocking)
478 {
479   GstV4l2Buffer *buf;
480
481   if (blocking) {
482     buf = g_async_queue_pop (pool->avail_buffers);
483   } else {
484     buf = g_async_queue_try_pop (pool->avail_buffers);
485   }
486
487   if (buf) {
488     GST_V4L2_BUFFER_POOL_LOCK (pool);
489     GST_BUFFER_SIZE (buf) = buf->vbuffer.length;
490     GST_BUFFER_FLAG_UNSET (buf, 0xffffffff);
491     GST_V4L2_BUFFER_POOL_UNLOCK (pool);
492   }
493
494   pool->running = TRUE;
495
496   return buf;
497 }
498
499
500 /**
501  * gst_v4l2_buffer_pool_qbuf:
502  * @pool: the pool
503  * @buf: the buffer to queue
504  *
505  * Queue a buffer to the driver
506  *
507  * Returns: %TRUE for success
508  */
509 gboolean
510 gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstV4l2Buffer * buf)
511 {
512   GST_LOG_OBJECT (pool->v4l2elem, "enqueue pool buffer %d", buf->vbuffer.index);
513
514   if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &buf->vbuffer) < 0)
515     return FALSE;
516
517   pool->num_live_buffers--;
518   GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers--: %d",
519       pool->num_live_buffers);
520
521   return TRUE;
522 }
523
524 /**
525  * gst_v4l2_buffer_pool_dqbuf:
526  * @pool: the pool
527  *
528  * Dequeue a buffer from the driver.  Some generic error handling is done in
529  * this function, but any error handling specific to v4l2src (capture) or
530  * v4l2sink (output) can be done outside this function by checking 'errno'
531  *
532  * Returns: a buffer
533  */
534 GstV4l2Buffer *
535 gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool)
536 {
537   GstV4l2Object *v4l2object = get_v4l2_object (pool->v4l2elem);
538   GstV4l2Buffer *pool_buffer;
539   struct v4l2_buffer buffer;
540
541   memset (&buffer, 0x00, sizeof (buffer));
542   buffer.type = pool->type;
543   buffer.memory = V4L2_MEMORY_MMAP;
544
545
546   if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &buffer) >= 0) {
547
548     GST_V4L2_BUFFER_POOL_LOCK (pool);
549
550     /* get our GstBuffer with that index from the pool, if the buffer was
551      * outstanding we have a serious problem.
552      */
553     pool_buffer = pool->buffers[buffer.index];
554
555     if (pool_buffer == NULL) {
556       GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
557           (_("Failed trying to get video frames from device '%s'."),
558               v4l2object->videodev),
559           (_("No free buffers found in the pool at index %d."), buffer.index));
560       GST_V4L2_BUFFER_POOL_UNLOCK (pool);
561       return NULL;
562     }
563
564     GST_LOG_OBJECT (pool->v4l2elem,
565         "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p",
566         buffer.sequence, buffer.index, buffer.flags, pool->num_live_buffers,
567         pool_buffer);
568
569     pool->num_live_buffers++;
570     GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers++: %d",
571         pool->num_live_buffers);
572
573     /* set top/bottom field first if v4l2_buffer has the information */
574     if (buffer.field == V4L2_FIELD_INTERLACED_TB)
575       GST_BUFFER_FLAG_SET (pool_buffer, GST_VIDEO_BUFFER_TFF);
576     if (buffer.field == V4L2_FIELD_INTERLACED_BT)
577       GST_BUFFER_FLAG_UNSET (pool_buffer, GST_VIDEO_BUFFER_TFF);
578
579     /* this can change at every frame, esp. with jpeg */
580     GST_BUFFER_SIZE (pool_buffer) = buffer.bytesused;
581
582     GST_V4L2_BUFFER_POOL_UNLOCK (pool);
583
584     return pool_buffer;
585   }
586
587
588   GST_WARNING_OBJECT (pool->v4l2elem,
589       "problem grabbing frame %d (ix=%d), pool-ct=%d, buf.flags=%d",
590       buffer.sequence, buffer.index,
591       GST_MINI_OBJECT_REFCOUNT (pool), buffer.flags);
592
593   switch (errno) {
594     case EAGAIN:
595       GST_WARNING_OBJECT (pool->v4l2elem,
596           "Non-blocking I/O has been selected using O_NONBLOCK and"
597           " no buffer was in the outgoing queue. device %s",
598           v4l2object->videodev);
599       break;
600     case EINVAL:
601       GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
602           (_("Failed trying to get video frames from device '%s'."),
603               v4l2object->videodev),
604           (_("The buffer type is not supported, or the index is out of bounds,"
605                   " or no buffers have been allocated yet, or the userptr"
606                   " or length are invalid. device %s"), v4l2object->videodev));
607       break;
608     case ENOMEM:
609       GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
610           (_("Failed trying to get video frames from device '%s'. Not enough memory."), v4l2object->videodev), (_("insufficient memory to enqueue a user pointer buffer. device %s."), v4l2object->videodev));
611       break;
612     case EIO:
613       GST_INFO_OBJECT (pool->v4l2elem,
614           "VIDIOC_DQBUF failed due to an internal error."
615           " Can also indicate temporary problems like signal loss."
616           " Note the driver might dequeue an (empty) buffer despite"
617           " returning an error, or even stop capturing."
618           " device %s", v4l2object->videodev);
619       /* have we de-queued a buffer ? */
620       if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) {
621         GST_DEBUG_OBJECT (pool->v4l2elem, "reenqueing buffer");
622         /* FIXME ... should we do something here? */
623       }
624       break;
625     case EINTR:
626       GST_WARNING_OBJECT (pool->v4l2elem,
627           "could not sync on a buffer on device %s", v4l2object->videodev);
628       break;
629     default:
630       GST_WARNING_OBJECT (pool->v4l2elem,
631           "Grabbing frame got interrupted on %s unexpectedly. %d: %s.",
632           v4l2object->videodev, errno, g_strerror (errno));
633       break;
634   }
635
636   return NULL;
637 }
638
639 /**
640  * gst_v4l2_buffer_pool_available_buffers:
641  * @pool: the pool
642  *
643  * Check the number of buffers available to the driver, ie. buffers that
644  * have been QBUF'd but not yet DQBUF'd.
645  *
646  * Returns: the number of buffers available.
647  */
648 gint
649 gst_v4l2_buffer_pool_available_buffers (GstV4l2BufferPool * pool)
650 {
651   return pool->buffer_count - pool->num_live_buffers;
652 }