2009-08-04 07:14:20 +00:00
/* GStreamer
*
* Copyright ( C ) 2001 - 2002 Ronald Bultje < rbultje @ ronald . bitfreak . net >
* 2006 Edgard Lima < edgard . lima @ indt . org . br >
* 2009 Texas Instruments , Inc - http : //www.ti.com/
*
2010-01-18 12:55:38 +00:00
* gstv4l2bufferpool . c V4L2 buffer pool class
2009-08-04 07:14:20 +00:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the
* Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*/
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include <sys/mman.h>
# include <string.h>
# include <unistd.h>
2010-11-04 18:31:45 +00:00
# include "gst/video/video.h"
2009-08-04 07:14:20 +00:00
# include <gstv4l2bufferpool.h>
# include "gstv4l2src.h"
# include "gstv4l2sink.h"
# include "v4l2_calls.h"
# include "gst/gst-i18n-plugin.h"
2011-01-12 20:38:59 +00:00
/* videodev2.h is not versioned and we can't easily check for the presence
* of enum values at compile time , but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define
* was added in the same commit as V4L2_FIELD_INTERLACED_ { TB , BT } ( b2787845 ) */
# ifndef V4L2_CAP_VIDEO_OUTPUT_OVERLAY
# define V4L2_FIELD_INTERLACED_TB 8
# define V4L2_FIELD_INTERLACED_BT 9
# endif
2009-08-04 07:14:20 +00:00
GST_DEBUG_CATEGORY_EXTERN ( v4l2_debug ) ;
# define GST_CAT_DEFAULT v4l2_debug
/*
* GstV4l2Buffer :
*/
2011-02-28 09:16:52 +00:00
const GstMetaInfo *
gst_meta_v4l2_get_info ( void )
{
static const GstMetaInfo * meta_info = NULL ;
if ( meta_info = = NULL ) {
meta_info =
gst_meta_register ( " GstMetaV4l2 " , " GstMetaV4l2 " ,
sizeof ( GstMetaV4l2 ) , ( GstMetaInitFunction ) NULL ,
2011-07-08 10:49:12 +00:00
( GstMetaFreeFunction ) NULL , ( GstMetaCopyFunction ) NULL ,
( GstMetaTransformFunction ) NULL ) ;
2011-02-28 09:16:52 +00:00
}
return meta_info ;
}
2009-08-04 07:14:20 +00:00
static void
2011-02-24 12:51:32 +00:00
gst_v4l2_buffer_dispose ( GstBuffer * buffer )
2009-08-04 07:14:20 +00:00
{
GstV4l2BufferPool * pool ;
gboolean resuscitated = FALSE ;
gint index ;
2011-02-25 15:29:38 +00:00
GstMetaV4l2 * meta ;
2011-07-12 16:13:42 +00:00
GstV4l2Object * obj ;
2009-08-04 07:14:20 +00:00
2011-02-27 18:43:13 +00:00
meta = GST_META_V4L2_GET ( buffer ) ;
2011-02-25 15:29:38 +00:00
g_assert ( meta ! = NULL ) ;
2009-08-04 07:14:20 +00:00
2011-02-25 15:29:38 +00:00
pool = meta - > pool ;
index = meta - > vbuffer . index ;
2011-07-12 16:13:42 +00:00
obj = pool - > obj ;
2009-08-04 07:14:20 +00:00
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " finalizing buffer %p %d " , buffer , index ) ;
2009-08-04 07:14:20 +00:00
GST_V4L2_BUFFER_POOL_LOCK ( pool ) ;
if ( pool - > running ) {
if ( pool - > requeuebuf ) {
if ( ! gst_v4l2_buffer_pool_qbuf ( pool , buffer ) ) {
2011-07-12 16:13:42 +00:00
GST_WARNING_OBJECT ( obj - > element , " could not requeue buffer %p %d " ,
buffer , index ) ;
2009-08-04 07:14:20 +00:00
} else {
resuscitated = TRUE ;
}
} else {
resuscitated = TRUE ;
/* XXX double check this... I think it is ok to not synchronize this
* w . r . t . destruction of the pool , since the buffer is still live and
* the buffer holds a ref to the pool . .
*/
g_async_queue_push ( pool - > avail_buffers , buffer ) ;
}
} else {
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " the pool is shutting down " ) ;
2009-08-04 07:14:20 +00:00
}
if ( resuscitated ) {
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " reviving buffer %p, %d " , buffer , index ) ;
2011-02-24 12:51:32 +00:00
gst_buffer_ref ( buffer ) ;
2009-08-04 07:14:20 +00:00
pool - > buffers [ index ] = buffer ;
}
GST_V4L2_BUFFER_POOL_UNLOCK ( pool ) ;
if ( ! resuscitated ) {
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element ,
2010-02-16 08:13:17 +00:00
" buffer %p (data %p, len %u) not recovered, unmapping " ,
2011-07-08 10:49:12 +00:00
buffer , meta - > mem , meta - > vbuffer . length ) ;
v4l2_munmap ( meta - > mem , meta - > vbuffer . length ) ;
2009-08-04 07:14:20 +00:00
2011-02-24 12:51:32 +00:00
g_object_unref ( pool ) ;
2009-08-04 07:14:20 +00:00
}
}
2011-02-24 12:51:32 +00:00
static GstBuffer *
2011-07-12 15:06:41 +00:00
gst_v4l2_buffer_new ( GstV4l2BufferPool * pool , guint index )
2009-08-04 07:14:20 +00:00
{
2011-02-24 12:51:32 +00:00
GstBuffer * ret ;
2011-02-25 15:29:38 +00:00
GstMetaV4l2 * meta ;
2011-07-12 16:13:42 +00:00
GstV4l2Object * obj ;
obj = pool - > obj ;
2009-08-04 07:14:20 +00:00
2011-02-24 12:51:32 +00:00
ret = gst_buffer_new ( ) ;
GST_MINI_OBJECT_CAST ( ret ) - > dispose =
( GstMiniObjectDisposeFunction ) gst_v4l2_buffer_dispose ;
2009-08-04 07:14:20 +00:00
2011-02-27 18:43:13 +00:00
meta = GST_META_V4L2_ADD ( ret ) ;
2011-02-25 15:29:38 +00:00
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " creating buffer %u, %p in pool %p " , index ,
2009-08-04 07:14:20 +00:00
ret , pool ) ;
2011-02-25 15:29:38 +00:00
meta - > pool = ( GstV4l2BufferPool * ) g_object_ref ( pool ) ;
2009-08-04 07:14:20 +00:00
2011-02-25 15:29:38 +00:00
meta - > vbuffer . index = index ;
meta - > vbuffer . type = pool - > type ;
meta - > vbuffer . memory = V4L2_MEMORY_MMAP ;
2009-08-04 07:14:20 +00:00
2011-02-25 15:29:38 +00:00
if ( v4l2_ioctl ( pool - > video_fd , VIDIOC_QUERYBUF , & meta - > vbuffer ) < 0 )
2009-08-04 07:14:20 +00:00
goto querybuf_failed ;
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " index: %u " , meta - > vbuffer . index ) ;
GST_LOG_OBJECT ( obj - > element , " type: %d " , meta - > vbuffer . type ) ;
GST_LOG_OBJECT ( obj - > element , " bytesused: %u " , meta - > vbuffer . bytesused ) ;
GST_LOG_OBJECT ( obj - > element , " flags: %08x " , meta - > vbuffer . flags ) ;
GST_LOG_OBJECT ( obj - > element , " field: %d " , meta - > vbuffer . field ) ;
GST_LOG_OBJECT ( obj - > element , " memory: %d " , meta - > vbuffer . memory ) ;
2011-02-25 15:29:38 +00:00
if ( meta - > vbuffer . memory = = V4L2_MEMORY_MMAP )
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " MMAP offset: %u " , meta - > vbuffer . m . offset ) ;
GST_LOG_OBJECT ( obj - > element , " length: %u " , meta - > vbuffer . length ) ;
GST_LOG_OBJECT ( obj - > element , " input: %u " , meta - > vbuffer . input ) ;
2009-08-04 07:14:20 +00:00
2011-07-08 10:49:12 +00:00
meta - > mem = v4l2_mmap ( 0 , meta - > vbuffer . length ,
2009-08-04 07:14:20 +00:00
PROT_READ | PROT_WRITE , MAP_SHARED , pool - > video_fd ,
2011-02-25 15:29:38 +00:00
meta - > vbuffer . m . offset ) ;
2011-07-08 10:49:12 +00:00
if ( meta - > mem = = MAP_FAILED )
2009-08-04 07:14:20 +00:00
goto mmap_failed ;
2011-07-08 10:49:12 +00:00
gst_buffer_take_memory ( ret , - 1 ,
2011-07-12 15:43:04 +00:00
gst_memory_new_wrapped ( 0 ,
2011-07-08 10:49:12 +00:00
meta - > mem , NULL , meta - > vbuffer . length , 0 , meta - > vbuffer . length ) ) ;
2009-08-04 07:14:20 +00:00
2011-07-12 16:13:42 +00:00
/* add metadata to buffers */
2009-08-04 07:14:20 +00:00
return ret ;
/* ERRORS */
querybuf_failed :
{
gint errnosave = errno ;
GST_WARNING ( " Failed QUERYBUF: %s " , g_strerror ( errnosave ) ) ;
2011-02-24 12:51:32 +00:00
gst_buffer_unref ( ret ) ;
2009-08-04 07:14:20 +00:00
errno = errnosave ;
return NULL ;
}
mmap_failed :
{
gint errnosave = errno ;
GST_WARNING ( " Failed to mmap: %s " , g_strerror ( errnosave ) ) ;
2011-02-24 12:51:32 +00:00
gst_buffer_unref ( ret ) ;
2009-08-04 07:14:20 +00:00
errno = errnosave ;
return NULL ;
}
}
/*
* GstV4l2BufferPool :
*/
2011-07-11 10:04:57 +00:00
# define gst_v4l2_buffer_pool_parent_class parent_class
G_DEFINE_TYPE ( GstV4l2BufferPool , gst_v4l2_buffer_pool , G_TYPE_OBJECT ) ;
2009-08-04 07:14:20 +00:00
static void
2011-02-24 12:51:32 +00:00
gst_v4l2_buffer_pool_finalize ( GObject * object )
2009-08-04 07:14:20 +00:00
{
2011-02-24 12:51:32 +00:00
GstV4l2BufferPool * pool = GST_V4L2_BUFFER_POOL ( object ) ;
2009-08-04 07:14:20 +00:00
g_mutex_free ( pool - > lock ) ;
pool - > lock = NULL ;
g_async_queue_unref ( pool - > avail_buffers ) ;
pool - > avail_buffers = NULL ;
if ( pool - > video_fd > = 0 )
v4l2_close ( pool - > video_fd ) ;
if ( pool - > buffers ) {
g_free ( pool - > buffers ) ;
pool - > buffers = NULL ;
}
2011-07-11 10:04:57 +00:00
G_OBJECT_CLASS ( parent_class ) - > finalize ( object ) ;
2009-08-04 07:14:20 +00:00
}
static void
2011-07-11 10:04:57 +00:00
gst_v4l2_buffer_pool_init ( GstV4l2BufferPool * pool )
2009-08-04 07:14:20 +00:00
{
pool - > lock = g_mutex_new ( ) ;
pool - > running = FALSE ;
pool - > num_live_buffers = 0 ;
}
static void
2011-07-11 10:04:57 +00:00
gst_v4l2_buffer_pool_class_init ( GstV4l2BufferPoolClass * klass )
2009-08-04 07:14:20 +00:00
{
2011-07-11 10:04:57 +00:00
GObjectClass * object_class = G_OBJECT_CLASS ( klass ) ;
2009-08-04 07:14:20 +00:00
2011-02-24 12:51:32 +00:00
object_class - > finalize = gst_v4l2_buffer_pool_finalize ;
2009-08-04 07:14:20 +00:00
}
/**
2009-09-10 07:26:23 +00:00
* gst_v4l2_buffer_pool_new :
2011-07-12 16:13:42 +00:00
* @ obj : the v4l2 object owning the pool
2009-09-10 07:26:23 +00:00
* @ num_buffers : the requested number of buffers in the pool
* @ requeuebuf : if % TRUE , and if the pool is still in the running state , a
* buffer with no remaining references is immediately passed back to v4l2
* ( VIDIOC_QBUF ) , otherwise it is returned to the pool of available buffers
* ( which can be accessed via gst_v4l2_buffer_pool_get ( ) .
2009-08-04 07:14:20 +00:00
*
2009-09-10 07:26:23 +00:00
* Construct a new buffer pool .
*
* Returns : the new pool , use gst_v4l2_buffer_pool_destroy ( ) to free resources
2009-08-04 07:14:20 +00:00
*/
GstV4l2BufferPool *
2011-07-12 16:13:42 +00:00
gst_v4l2_buffer_pool_new ( GstV4l2Object * obj , gint num_buffers ,
gboolean requeuebuf )
2009-08-04 07:14:20 +00:00
{
GstV4l2BufferPool * pool ;
gint n ;
struct v4l2_requestbuffers breq ;
2011-02-24 12:51:32 +00:00
pool = ( GstV4l2BufferPool * ) g_object_new ( GST_TYPE_V4L2_BUFFER_POOL , NULL ) ;
2009-08-04 07:14:20 +00:00
2011-07-12 16:13:42 +00:00
pool - > video_fd = v4l2_dup ( obj - > video_fd ) ;
2009-08-04 07:14:20 +00:00
if ( pool - > video_fd < 0 )
goto dup_failed ;
/* first, lets request buffers, and see how many we can get: */
2011-07-12 16:13:42 +00:00
GST_DEBUG_OBJECT ( obj - > element , " STREAMING, requesting %d MMAP buffers " ,
2009-08-04 07:14:20 +00:00
num_buffers ) ;
memset ( & breq , 0 , sizeof ( struct v4l2_requestbuffers ) ) ;
2011-07-12 16:13:42 +00:00
breq . type = obj - > type ;
2009-08-04 07:14:20 +00:00
breq . count = num_buffers ;
breq . memory = V4L2_MEMORY_MMAP ;
2011-07-12 16:13:42 +00:00
if ( v4l2_ioctl ( pool - > video_fd , VIDIOC_REQBUFS , & breq ) < 0 )
2009-08-04 07:14:20 +00:00
goto reqbufs_failed ;
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " count: %u " , breq . count ) ;
GST_LOG_OBJECT ( obj - > element , " type: %d " , breq . type ) ;
GST_LOG_OBJECT ( obj - > element , " memory: %d " , breq . memory ) ;
2009-08-04 07:14:20 +00:00
if ( breq . count < GST_V4L2_MIN_BUFFERS )
goto no_buffers ;
if ( num_buffers ! = breq . count ) {
2011-07-12 16:13:42 +00:00
GST_WARNING_OBJECT ( obj - > element , " using %u buffers instead " , breq . count ) ;
2009-08-04 07:14:20 +00:00
num_buffers = breq . count ;
}
2011-07-12 16:13:42 +00:00
pool - > obj = obj ;
2009-08-04 07:14:20 +00:00
pool - > requeuebuf = requeuebuf ;
2011-07-12 16:13:42 +00:00
pool - > type = obj - > type ;
2009-08-04 07:14:20 +00:00
pool - > buffer_count = num_buffers ;
2011-02-24 12:51:32 +00:00
pool - > buffers = g_new0 ( GstBuffer * , num_buffers ) ;
2009-08-04 07:14:20 +00:00
pool - > avail_buffers = g_async_queue_new ( ) ;
/* now, map the buffers: */
for ( n = 0 ; n < num_buffers ; n + + ) {
2011-07-12 15:06:41 +00:00
pool - > buffers [ n ] = gst_v4l2_buffer_new ( pool , n ) ;
2009-08-04 07:14:20 +00:00
if ( ! pool - > buffers [ n ] )
goto buffer_new_failed ;
2009-08-04 07:22:29 +00:00
pool - > num_live_buffers + + ;
2009-08-04 07:14:20 +00:00
g_async_queue_push ( pool - > avail_buffers , pool - > buffers [ n ] ) ;
}
return pool ;
/* ERRORS */
dup_failed :
{
gint errnosave = errno ;
2011-02-24 12:51:32 +00:00
g_object_unref ( pool ) ;
2009-08-04 07:14:20 +00:00
errno = errnosave ;
return NULL ;
}
reqbufs_failed :
{
2011-07-12 16:13:42 +00:00
GST_ELEMENT_ERROR ( obj - > element , RESOURCE , READ ,
2009-08-04 07:14:20 +00:00
( _ ( " Could not get buffers from device '%s'. " ) ,
2011-07-12 16:13:42 +00:00
obj - > videodev ) ,
2009-08-04 07:14:20 +00:00
( " error requesting %d buffers: %s " , num_buffers , g_strerror ( errno ) ) ) ;
return NULL ;
}
no_buffers :
{
2011-07-12 16:13:42 +00:00
GST_ELEMENT_ERROR ( obj - > element , RESOURCE , READ ,
2009-08-04 07:14:20 +00:00
( _ ( " Could not get enough buffers from device '%s'. " ) ,
2011-07-12 16:13:42 +00:00
obj - > videodev ) ,
2009-08-04 07:14:20 +00:00
( " we received %d from device '%s', we want at least %d " ,
2011-07-12 16:13:42 +00:00
breq . count , obj - > videodev , GST_V4L2_MIN_BUFFERS ) ) ;
2009-08-04 07:14:20 +00:00
return NULL ;
}
buffer_new_failed :
{
gint errnosave = errno ;
gst_v4l2_buffer_pool_destroy ( pool ) ;
errno = errnosave ;
return NULL ;
}
}
2009-09-10 07:26:23 +00:00
/**
* gst_v4l2_buffer_pool_destroy :
* @ pool : the pool
*
* Free all resources in the pool and the pool itself .
*/
2009-08-04 07:14:20 +00:00
void
gst_v4l2_buffer_pool_destroy ( GstV4l2BufferPool * pool )
{
gint n ;
2011-07-12 16:13:42 +00:00
GstV4l2Object * obj = pool - > obj ;
2009-08-04 07:14:20 +00:00
GST_V4L2_BUFFER_POOL_LOCK ( pool ) ;
pool - > running = FALSE ;
GST_V4L2_BUFFER_POOL_UNLOCK ( pool ) ;
2011-07-12 16:13:42 +00:00
GST_DEBUG_OBJECT ( obj - > element , " destroy pool " ) ;
2009-08-04 07:14:20 +00:00
/* after this point, no more buffers will be queued or dequeued; no buffer
* from pool - > buffers that is NULL will be set to a buffer , and no buffer that
* is not NULL will be pushed out . */
/* miniobjects have no dispose, so they can't break ref-cycles, as buffers ref
* the pool , we need to unref the buffer to properly finalize te pool */
for ( n = 0 ; n < pool - > buffer_count ; n + + ) {
GstBuffer * buf ;
GST_V4L2_BUFFER_POOL_LOCK ( pool ) ;
2011-07-11 10:04:57 +00:00
buf = pool - > buffers [ n ] ;
2009-08-04 07:14:20 +00:00
GST_V4L2_BUFFER_POOL_UNLOCK ( pool ) ;
if ( buf )
/* we own the ref if the buffer is in pool->buffers; drop it. */
gst_buffer_unref ( buf ) ;
}
2011-02-24 12:51:32 +00:00
g_object_unref ( pool ) ;
2009-08-04 07:14:20 +00:00
}
/**
2009-09-10 07:26:23 +00:00
* gst_v4l2_buffer_pool_get :
2010-04-04 11:26:50 +00:00
* @ pool : the " this " object
* @ blocking : should this call suspend until there is a buffer available
* in the buffer pool ?
2009-08-04 07:14:20 +00:00
*
2009-09-10 07:26:23 +00:00
* Get an available buffer in the pool
2009-08-04 07:14:20 +00:00
*/
2011-02-24 12:51:32 +00:00
GstBuffer *
2010-04-04 11:26:50 +00:00
gst_v4l2_buffer_pool_get ( GstV4l2BufferPool * pool , gboolean blocking )
2009-08-04 07:14:20 +00:00
{
2011-02-24 12:51:32 +00:00
GstBuffer * buf ;
2010-04-04 11:26:50 +00:00
if ( blocking ) {
buf = g_async_queue_pop ( pool - > avail_buffers ) ;
} else {
buf = g_async_queue_try_pop ( pool - > avail_buffers ) ;
}
2009-08-04 07:14:20 +00:00
2010-04-04 11:24:41 +00:00
if ( buf ) {
2011-02-27 18:43:13 +00:00
GstMetaV4l2 * meta = GST_META_V4L2_GET ( buf ) ;
2011-02-25 15:29:38 +00:00
2010-04-04 11:39:52 +00:00
GST_V4L2_BUFFER_POOL_LOCK ( pool ) ;
2011-07-08 10:49:12 +00:00
gst_buffer_resize ( buf , 0 , meta - > vbuffer . length ) ;
2010-04-04 11:24:41 +00:00
GST_BUFFER_FLAG_UNSET ( buf , 0xffffffff ) ;
2010-04-04 11:39:52 +00:00
GST_V4L2_BUFFER_POOL_UNLOCK ( pool ) ;
2010-04-04 11:24:41 +00:00
}
2009-08-04 07:14:20 +00:00
pool - > running = TRUE ;
return buf ;
}
/**
2009-09-10 07:26:23 +00:00
* gst_v4l2_buffer_pool_qbuf :
* @ pool : the pool
* @ buf : the buffer to queue
*
2009-08-04 07:14:20 +00:00
* Queue a buffer to the driver
*
2009-09-10 07:26:23 +00:00
* Returns : % TRUE for success
2009-08-04 07:14:20 +00:00
*/
gboolean
2011-02-24 12:51:32 +00:00
gst_v4l2_buffer_pool_qbuf ( GstV4l2BufferPool * pool , GstBuffer * buf )
2009-08-04 07:14:20 +00:00
{
2011-02-25 15:29:38 +00:00
GstMetaV4l2 * meta ;
2011-07-12 16:13:42 +00:00
GstV4l2Object * obj = pool - > obj ;
2011-02-25 15:29:38 +00:00
2011-02-27 18:43:13 +00:00
meta = GST_META_V4L2_GET ( buf ) ;
2011-02-24 12:51:32 +00:00
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element , " enqueue pool buffer %d " , meta - > vbuffer . index ) ;
2009-08-04 07:14:20 +00:00
2011-02-25 15:29:38 +00:00
if ( v4l2_ioctl ( pool - > video_fd , VIDIOC_QBUF , & meta - > vbuffer ) < 0 )
2011-07-11 10:04:57 +00:00
goto queue_failed ;
2009-08-04 07:14:20 +00:00
pool - > num_live_buffers - - ;
2011-07-12 16:13:42 +00:00
GST_DEBUG_OBJECT ( obj - > element , " num_live_buffers--: %d " ,
2009-08-04 07:14:20 +00:00
pool - > num_live_buffers ) ;
return TRUE ;
2011-07-11 10:04:57 +00:00
/* ERRORS */
queue_failed :
{
2011-07-12 16:13:42 +00:00
GST_WARNING_OBJECT ( obj - > element , " could not queue a buffer " ) ;
2011-07-11 10:04:57 +00:00
return FALSE ;
}
2009-08-04 07:14:20 +00:00
}
/**
2009-09-10 07:26:23 +00:00
* gst_v4l2_buffer_pool_dqbuf :
* @ pool : the pool
*
2009-08-04 07:14:20 +00:00
* Dequeue a buffer from the driver . Some generic error handling is done in
* this function , but any error handling specific to v4l2src ( capture ) or
* v4l2sink ( output ) can be done outside this function by checking ' errno '
*
2009-09-10 07:26:23 +00:00
* Returns : a buffer
2009-08-04 07:14:20 +00:00
*/
2011-02-24 12:51:32 +00:00
GstBuffer *
2009-08-04 07:14:20 +00:00
gst_v4l2_buffer_pool_dqbuf ( GstV4l2BufferPool * pool )
{
2011-02-24 12:51:32 +00:00
GstBuffer * pool_buffer ;
2009-08-04 07:14:20 +00:00
struct v4l2_buffer buffer ;
2011-07-12 16:13:42 +00:00
GstV4l2Object * obj = pool - > obj ;
2009-08-04 07:14:20 +00:00
memset ( & buffer , 0x00 , sizeof ( buffer ) ) ;
buffer . type = pool - > type ;
buffer . memory = V4L2_MEMORY_MMAP ;
2011-07-11 10:04:57 +00:00
if ( v4l2_ioctl ( pool - > video_fd , VIDIOC_DQBUF , & buffer ) < 0 )
goto error ;
2009-08-04 07:14:20 +00:00
2011-07-11 10:04:57 +00:00
GST_V4L2_BUFFER_POOL_LOCK ( pool ) ;
2009-08-04 07:14:20 +00:00
2011-07-11 10:04:57 +00:00
/* get our GstBuffer with that index from the pool, if the buffer was
* outstanding we have a serious problem .
*/
pool_buffer = pool - > buffers [ buffer . index ] ;
2009-08-04 07:14:20 +00:00
2011-07-11 10:04:57 +00:00
if ( pool_buffer = = NULL )
goto no_buffers ;
2009-08-04 07:14:20 +00:00
2011-07-12 16:13:42 +00:00
GST_LOG_OBJECT ( obj - > element ,
2011-07-11 10:04:57 +00:00
" grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p " ,
buffer . sequence , buffer . index , buffer . flags , pool - > num_live_buffers ,
pool_buffer ) ;
2009-08-04 07:14:20 +00:00
2011-07-11 10:04:57 +00:00
pool - > num_live_buffers + + ;
2011-07-12 16:13:42 +00:00
GST_DEBUG_OBJECT ( obj - > element , " num_live_buffers++: %d " ,
2011-07-11 10:04:57 +00:00
pool - > num_live_buffers ) ;
2010-11-04 18:31:45 +00:00
2011-07-11 10:04:57 +00:00
/* set top/bottom field first if v4l2_buffer has the information */
if ( buffer . field = = V4L2_FIELD_INTERLACED_TB )
GST_BUFFER_FLAG_SET ( pool_buffer , GST_VIDEO_BUFFER_TFF ) ;
if ( buffer . field = = V4L2_FIELD_INTERLACED_BT )
GST_BUFFER_FLAG_UNSET ( pool_buffer , GST_VIDEO_BUFFER_TFF ) ;
2009-08-04 07:14:20 +00:00
2011-07-11 10:04:57 +00:00
/* this can change at every frame, esp. with jpeg */
gst_buffer_resize ( pool_buffer , 0 , buffer . bytesused ) ;
2010-04-04 11:39:52 +00:00
2011-07-11 10:04:57 +00:00
GST_V4L2_BUFFER_POOL_UNLOCK ( pool ) ;
2009-08-04 07:14:20 +00:00
2011-07-11 10:04:57 +00:00
return pool_buffer ;
2009-08-04 07:14:20 +00:00
2011-07-11 10:04:57 +00:00
/* ERRORS */
error :
{
2011-07-12 16:13:42 +00:00
GST_WARNING_OBJECT ( obj - > element ,
2011-07-11 10:04:57 +00:00
" problem grabbing frame %d (ix=%d), pool-ct=%d, buf.flags=%d " ,
buffer . sequence , buffer . index ,
GST_MINI_OBJECT_REFCOUNT ( pool ) , buffer . flags ) ;
switch ( errno ) {
case EAGAIN :
2011-07-12 16:13:42 +00:00
GST_WARNING_OBJECT ( obj - > element ,
2011-07-11 10:04:57 +00:00
" Non-blocking I/O has been selected using O_NONBLOCK and "
2011-07-12 16:13:42 +00:00
" no buffer was in the outgoing queue. device %s " , obj - > videodev ) ;
2011-07-11 10:04:57 +00:00
break ;
case EINVAL :
2011-07-12 16:13:42 +00:00
GST_ELEMENT_ERROR ( obj - > element , RESOURCE , FAILED ,
2011-07-11 10:04:57 +00:00
( _ ( " Failed trying to get video frames from device '%s'. " ) ,
2011-07-12 16:13:42 +00:00
obj - > videodev ) ,
( _ ( " The buffer type is not supported, or the index is out of bounds, " " or no buffers have been allocated yet, or the userptr " " or length are invalid. device %s " ) , obj - > videodev ) ) ;
2011-07-11 10:04:57 +00:00
break ;
case ENOMEM :
2011-07-12 16:13:42 +00:00
GST_ELEMENT_ERROR ( obj - > element , RESOURCE , FAILED ,
( _ ( " Failed trying to get video frames from device '%s'. Not enough memory. " ) , obj - > videodev ) , ( _ ( " insufficient memory to enqueue a user pointer buffer. device %s. " ) , obj - > videodev ) ) ;
2011-07-11 10:04:57 +00:00
break ;
case EIO :
2011-07-12 16:13:42 +00:00
GST_INFO_OBJECT ( obj - > element ,
2011-07-11 10:04:57 +00:00
" VIDIOC_DQBUF failed due to an internal error. "
" Can also indicate temporary problems like signal loss. "
" Note the driver might dequeue an (empty) buffer despite "
" returning an error, or even stop capturing. "
2011-07-12 16:13:42 +00:00
" device %s " , obj - > videodev ) ;
2011-07-11 10:04:57 +00:00
/* have we de-queued a buffer ? */
if ( ! ( buffer . flags & ( V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE ) ) ) {
2011-07-12 16:13:42 +00:00
GST_DEBUG_OBJECT ( obj - > element , " reenqueing buffer " ) ;
2011-07-11 10:04:57 +00:00
/* FIXME ... should we do something here? */
}
break ;
case EINTR :
2011-07-12 16:13:42 +00:00
GST_WARNING_OBJECT ( obj - > element ,
" could not sync on a buffer on device %s " , obj - > videodev ) ;
2011-07-11 10:04:57 +00:00
break ;
default :
2011-07-12 16:13:42 +00:00
GST_WARNING_OBJECT ( obj - > element ,
2011-07-11 10:04:57 +00:00
" Grabbing frame got interrupted on %s unexpectedly. %d: %s. " ,
2011-07-12 16:13:42 +00:00
obj - > videodev , errno , g_strerror ( errno ) ) ;
2011-07-11 10:04:57 +00:00
break ;
}
return NULL ;
}
no_buffers :
{
2011-07-12 16:13:42 +00:00
GST_ELEMENT_ERROR ( obj - > element , RESOURCE , FAILED ,
2011-07-11 10:04:57 +00:00
( _ ( " Failed trying to get video frames from device '%s'. " ) ,
2011-07-12 16:13:42 +00:00
obj - > videodev ) ,
2011-07-11 10:04:57 +00:00
( _ ( " No free buffers found in the pool at index %d. " ) , buffer . index ) ) ;
GST_V4L2_BUFFER_POOL_UNLOCK ( pool ) ;
return NULL ;
2009-08-04 07:14:20 +00:00
}
}
2009-08-04 07:22:29 +00:00
/**
* gst_v4l2_buffer_pool_available_buffers :
2009-09-10 07:26:23 +00:00
* @ pool : the pool
*
* Check the number of buffers available to the driver , ie . buffers that
2009-08-04 07:22:29 +00:00
* have been QBUF ' d but not yet DQBUF ' d .
2009-09-10 07:26:23 +00:00
*
* Returns : the number of buffers available .
2009-08-04 07:22:29 +00:00
*/
2009-08-04 07:14:20 +00:00
gint
gst_v4l2_buffer_pool_available_buffers ( GstV4l2BufferPool * pool )
{
return pool - > buffer_count - pool - > num_live_buffers ;
}