v4l2: Let the bufferpool own the V4l2Object

Keep track of the currently configured format and setting in the
v4l2object.
Pass the v4l2object to the bufferpool constructor so that the bufferpool can
know everything about the currently configured settings. This also allows us
to remove some awkward code.
This commit is contained in:
Wim Taymans 2011-07-12 18:13:42 +02:00
parent f55656dcfc
commit 0dcf0aebb0
6 changed files with 113 additions and 126 deletions

View file

@ -75,20 +75,23 @@ gst_v4l2_buffer_dispose (GstBuffer * buffer)
gboolean resuscitated = FALSE; gboolean resuscitated = FALSE;
gint index; gint index;
GstMetaV4l2 *meta; GstMetaV4l2 *meta;
GstV4l2Object *obj;
meta = GST_META_V4L2_GET (buffer); meta = GST_META_V4L2_GET (buffer);
g_assert (meta != NULL); g_assert (meta != NULL);
pool = meta->pool; pool = meta->pool;
index = meta->vbuffer.index; index = meta->vbuffer.index;
obj = pool->obj;
GST_LOG_OBJECT (pool->v4l2elem, "finalizing buffer %p %d", buffer, index); GST_LOG_OBJECT (obj->element, "finalizing buffer %p %d", buffer, index);
GST_V4L2_BUFFER_POOL_LOCK (pool); GST_V4L2_BUFFER_POOL_LOCK (pool);
if (pool->running) { if (pool->running) {
if (pool->requeuebuf) { if (pool->requeuebuf) {
if (!gst_v4l2_buffer_pool_qbuf (pool, buffer)) { if (!gst_v4l2_buffer_pool_qbuf (pool, buffer)) {
GST_WARNING ("could not requeue buffer %p %d", buffer, index); GST_WARNING_OBJECT (obj->element, "could not requeue buffer %p %d",
buffer, index);
} else { } else {
resuscitated = TRUE; resuscitated = TRUE;
} }
@ -101,11 +104,11 @@ gst_v4l2_buffer_dispose (GstBuffer * buffer)
g_async_queue_push (pool->avail_buffers, buffer); g_async_queue_push (pool->avail_buffers, buffer);
} }
} else { } else {
GST_LOG_OBJECT (pool->v4l2elem, "the pool is shutting down"); GST_LOG_OBJECT (obj->element, "the pool is shutting down");
} }
if (resuscitated) { if (resuscitated) {
GST_LOG_OBJECT (pool->v4l2elem, "reviving buffer %p, %d", buffer, index); GST_LOG_OBJECT (obj->element, "reviving buffer %p, %d", buffer, index);
gst_buffer_ref (buffer); gst_buffer_ref (buffer);
pool->buffers[index] = buffer; pool->buffers[index] = buffer;
} }
@ -113,7 +116,7 @@ gst_v4l2_buffer_dispose (GstBuffer * buffer)
GST_V4L2_BUFFER_POOL_UNLOCK (pool); GST_V4L2_BUFFER_POOL_UNLOCK (pool);
if (!resuscitated) { if (!resuscitated) {
GST_LOG_OBJECT (pool->v4l2elem, GST_LOG_OBJECT (obj->element,
"buffer %p (data %p, len %u) not recovered, unmapping", "buffer %p (data %p, len %u) not recovered, unmapping",
buffer, meta->mem, meta->vbuffer.length); buffer, meta->mem, meta->vbuffer.length);
v4l2_munmap (meta->mem, meta->vbuffer.length); v4l2_munmap (meta->mem, meta->vbuffer.length);
@ -127,6 +130,9 @@ gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index)
{ {
GstBuffer *ret; GstBuffer *ret;
GstMetaV4l2 *meta; GstMetaV4l2 *meta;
GstV4l2Object *obj;
obj = pool->obj;
ret = gst_buffer_new (); ret = gst_buffer_new ();
GST_MINI_OBJECT_CAST (ret)->dispose = GST_MINI_OBJECT_CAST (ret)->dispose =
@ -134,7 +140,7 @@ gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index)
meta = GST_META_V4L2_ADD (ret); meta = GST_META_V4L2_ADD (ret);
GST_LOG_OBJECT (pool->v4l2elem, "creating buffer %u, %p in pool %p", index, GST_LOG_OBJECT (obj->element, "creating buffer %u, %p in pool %p", index,
ret, pool); ret, pool);
meta->pool = (GstV4l2BufferPool *) g_object_ref (pool); meta->pool = (GstV4l2BufferPool *) g_object_ref (pool);
@ -146,17 +152,16 @@ gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index)
if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &meta->vbuffer) < 0) if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &meta->vbuffer) < 0)
goto querybuf_failed; goto querybuf_failed;
GST_LOG_OBJECT (pool->v4l2elem, " index: %u", meta->vbuffer.index); GST_LOG_OBJECT (obj->element, " index: %u", meta->vbuffer.index);
GST_LOG_OBJECT (pool->v4l2elem, " type: %d", meta->vbuffer.type); GST_LOG_OBJECT (obj->element, " type: %d", meta->vbuffer.type);
GST_LOG_OBJECT (pool->v4l2elem, " bytesused: %u", meta->vbuffer.bytesused); GST_LOG_OBJECT (obj->element, " bytesused: %u", meta->vbuffer.bytesused);
GST_LOG_OBJECT (pool->v4l2elem, " flags: %08x", meta->vbuffer.flags); GST_LOG_OBJECT (obj->element, " flags: %08x", meta->vbuffer.flags);
GST_LOG_OBJECT (pool->v4l2elem, " field: %d", meta->vbuffer.field); GST_LOG_OBJECT (obj->element, " field: %d", meta->vbuffer.field);
GST_LOG_OBJECT (pool->v4l2elem, " memory: %d", meta->vbuffer.memory); GST_LOG_OBJECT (obj->element, " memory: %d", meta->vbuffer.memory);
if (meta->vbuffer.memory == V4L2_MEMORY_MMAP) if (meta->vbuffer.memory == V4L2_MEMORY_MMAP)
GST_LOG_OBJECT (pool->v4l2elem, " MMAP offset: %u", GST_LOG_OBJECT (obj->element, " MMAP offset: %u", meta->vbuffer.m.offset);
meta->vbuffer.m.offset); GST_LOG_OBJECT (obj->element, " length: %u", meta->vbuffer.length);
GST_LOG_OBJECT (pool->v4l2elem, " length: %u", meta->vbuffer.length); GST_LOG_OBJECT (obj->element, " input: %u", meta->vbuffer.input);
GST_LOG_OBJECT (pool->v4l2elem, " input: %u", meta->vbuffer.input);
meta->mem = v4l2_mmap (0, meta->vbuffer.length, meta->mem = v4l2_mmap (0, meta->vbuffer.length,
PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd,
@ -168,6 +173,11 @@ gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index)
gst_memory_new_wrapped (0, gst_memory_new_wrapped (0,
meta->mem, NULL, meta->vbuffer.length, 0, meta->vbuffer.length)); meta->mem, NULL, meta->vbuffer.length, 0, meta->vbuffer.length));
/* add metadata to buffers */
return ret; return ret;
/* ERRORS */ /* ERRORS */
@ -235,27 +245,9 @@ gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
object_class->finalize = gst_v4l2_buffer_pool_finalize; object_class->finalize = gst_v4l2_buffer_pool_finalize;
} }
/* this is somewhat of a hack.. but better to keep the hack in
* one place than copy/pasting it around..
*/
static GstV4l2Object *
get_v4l2_object (GstElement * v4l2elem)
{
GstV4l2Object *v4l2object = NULL;
if (GST_IS_V4L2SRC (v4l2elem)) {
v4l2object = (GST_V4L2SRC (v4l2elem))->v4l2object;
} else if (GST_IS_V4L2SINK (v4l2elem)) {
v4l2object = (GST_V4L2SINK (v4l2elem))->v4l2object;
} else {
GST_ERROR_OBJECT (v4l2elem, "unknown v4l2 element");
}
return v4l2object;
}
/** /**
* gst_v4l2_buffer_pool_new: * gst_v4l2_buffer_pool_new:
* @v4l2elem: the v4l2 element (src or sink) that owns this pool * @obj: the v4l2 object owning the pool
* @fd: the video device file descriptor
* @num_buffers: the requested number of buffers in the pool * @num_buffers: the requested number of buffers in the pool
* @requeuebuf: if %TRUE, and if the pool is still in the running state, a * @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 * buffer with no remaining references is immediately passed back to v4l2
@ -267,8 +259,8 @@ get_v4l2_object (GstElement * v4l2elem)
* Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources * Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources
*/ */
GstV4l2BufferPool * GstV4l2BufferPool *
gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers, gst_v4l2_buffer_pool_new (GstV4l2Object * obj, gint num_buffers,
gboolean requeuebuf, enum v4l2_buf_type type) gboolean requeuebuf)
{ {
GstV4l2BufferPool *pool; GstV4l2BufferPool *pool;
gint n; gint n;
@ -276,37 +268,37 @@ gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers,
pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL); pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL);
pool->video_fd = v4l2_dup (fd); pool->video_fd = v4l2_dup (obj->video_fd);
if (pool->video_fd < 0) if (pool->video_fd < 0)
goto dup_failed; goto dup_failed;
/* first, lets request buffers, and see how many we can get: */ /* first, lets request buffers, and see how many we can get: */
GST_DEBUG_OBJECT (v4l2elem, "STREAMING, requesting %d MMAP buffers", GST_DEBUG_OBJECT (obj->element, "STREAMING, requesting %d MMAP buffers",
num_buffers); num_buffers);
memset (&breq, 0, sizeof (struct v4l2_requestbuffers)); memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
breq.type = type; breq.type = obj->type;
breq.count = num_buffers; breq.count = num_buffers;
breq.memory = V4L2_MEMORY_MMAP; breq.memory = V4L2_MEMORY_MMAP;
if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &breq) < 0) if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0)
goto reqbufs_failed; goto reqbufs_failed;
GST_LOG_OBJECT (v4l2elem, " count: %u", breq.count); GST_LOG_OBJECT (obj->element, " count: %u", breq.count);
GST_LOG_OBJECT (v4l2elem, " type: %d", breq.type); GST_LOG_OBJECT (obj->element, " type: %d", breq.type);
GST_LOG_OBJECT (v4l2elem, " memory: %d", breq.memory); GST_LOG_OBJECT (obj->element, " memory: %d", breq.memory);
if (breq.count < GST_V4L2_MIN_BUFFERS) if (breq.count < GST_V4L2_MIN_BUFFERS)
goto no_buffers; goto no_buffers;
if (num_buffers != breq.count) { if (num_buffers != breq.count) {
GST_WARNING_OBJECT (v4l2elem, "using %u buffers instead", breq.count); GST_WARNING_OBJECT (obj->element, "using %u buffers instead", breq.count);
num_buffers = breq.count; num_buffers = breq.count;
} }
pool->v4l2elem = v4l2elem; pool->obj = obj;
pool->requeuebuf = requeuebuf; pool->requeuebuf = requeuebuf;
pool->type = type; pool->type = obj->type;
pool->buffer_count = num_buffers; pool->buffer_count = num_buffers;
pool->buffers = g_new0 (GstBuffer *, num_buffers); pool->buffers = g_new0 (GstBuffer *, num_buffers);
pool->avail_buffers = g_async_queue_new (); pool->avail_buffers = g_async_queue_new ();
@ -335,21 +327,19 @@ dup_failed:
} }
reqbufs_failed: reqbufs_failed:
{ {
GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); GST_ELEMENT_ERROR (obj->element, RESOURCE, READ,
GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ,
(_("Could not get buffers from device '%s'."), (_("Could not get buffers from device '%s'."),
v4l2object->videodev), obj->videodev),
("error requesting %d buffers: %s", num_buffers, g_strerror (errno))); ("error requesting %d buffers: %s", num_buffers, g_strerror (errno)));
return NULL; return NULL;
} }
no_buffers: no_buffers:
{ {
GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); GST_ELEMENT_ERROR (obj->element, RESOURCE, READ,
GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ,
(_("Could not get enough buffers from device '%s'."), (_("Could not get enough buffers from device '%s'."),
v4l2object->videodev), obj->videodev),
("we received %d from device '%s', we want at least %d", ("we received %d from device '%s', we want at least %d",
breq.count, v4l2object->videodev, GST_V4L2_MIN_BUFFERS)); breq.count, obj->videodev, GST_V4L2_MIN_BUFFERS));
return NULL; return NULL;
} }
buffer_new_failed: buffer_new_failed:
@ -374,12 +364,13 @@ void
gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool) gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool)
{ {
gint n; gint n;
GstV4l2Object *obj = pool->obj;
GST_V4L2_BUFFER_POOL_LOCK (pool); GST_V4L2_BUFFER_POOL_LOCK (pool);
pool->running = FALSE; pool->running = FALSE;
GST_V4L2_BUFFER_POOL_UNLOCK (pool); GST_V4L2_BUFFER_POOL_UNLOCK (pool);
GST_DEBUG_OBJECT (pool->v4l2elem, "destroy pool"); GST_DEBUG_OBJECT (obj->element, "destroy pool");
/* after this point, no more buffers will be queued or dequeued; no buffer /* 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 * from pool->buffers that is NULL will be set to a buffer, and no buffer that
@ -449,17 +440,17 @@ gboolean
gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf) gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
{ {
GstMetaV4l2 *meta; GstMetaV4l2 *meta;
GstV4l2Object *obj = pool->obj;
meta = GST_META_V4L2_GET (buf); meta = GST_META_V4L2_GET (buf);
GST_LOG_OBJECT (pool->v4l2elem, "enqueue pool buffer %d", GST_LOG_OBJECT (obj->element, "enqueue pool buffer %d", meta->vbuffer.index);
meta->vbuffer.index);
if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &meta->vbuffer) < 0) if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &meta->vbuffer) < 0)
goto queue_failed; goto queue_failed;
pool->num_live_buffers--; pool->num_live_buffers--;
GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers--: %d", GST_DEBUG_OBJECT (obj->element, "num_live_buffers--: %d",
pool->num_live_buffers); pool->num_live_buffers);
return TRUE; return TRUE;
@ -467,7 +458,7 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
/* ERRORS */ /* ERRORS */
queue_failed: queue_failed:
{ {
GST_WARNING_OBJECT (pool->v4l2elem, "could not queue a buffer"); GST_WARNING_OBJECT (obj->element, "could not queue a buffer");
return FALSE; return FALSE;
} }
} }
@ -485,9 +476,9 @@ queue_failed:
GstBuffer * GstBuffer *
gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool) gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool)
{ {
GstV4l2Object *v4l2object = get_v4l2_object (pool->v4l2elem);
GstBuffer *pool_buffer; GstBuffer *pool_buffer;
struct v4l2_buffer buffer; struct v4l2_buffer buffer;
GstV4l2Object *obj = pool->obj;
memset (&buffer, 0x00, sizeof (buffer)); memset (&buffer, 0x00, sizeof (buffer));
buffer.type = pool->type; buffer.type = pool->type;
@ -506,13 +497,13 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool)
if (pool_buffer == NULL) if (pool_buffer == NULL)
goto no_buffers; goto no_buffers;
GST_LOG_OBJECT (pool->v4l2elem, GST_LOG_OBJECT (obj->element,
"grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p", "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p",
buffer.sequence, buffer.index, buffer.flags, pool->num_live_buffers, buffer.sequence, buffer.index, buffer.flags, pool->num_live_buffers,
pool_buffer); pool_buffer);
pool->num_live_buffers++; pool->num_live_buffers++;
GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers++: %d", GST_DEBUG_OBJECT (obj->element, "num_live_buffers++: %d",
pool->num_live_buffers); pool->num_live_buffers);
/* set top/bottom field first if v4l2_buffer has the information */ /* set top/bottom field first if v4l2_buffer has the information */
@ -531,58 +522,57 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool)
/* ERRORS */ /* ERRORS */
error: error:
{ {
GST_WARNING_OBJECT (pool->v4l2elem, GST_WARNING_OBJECT (obj->element,
"problem grabbing frame %d (ix=%d), pool-ct=%d, buf.flags=%d", "problem grabbing frame %d (ix=%d), pool-ct=%d, buf.flags=%d",
buffer.sequence, buffer.index, buffer.sequence, buffer.index,
GST_MINI_OBJECT_REFCOUNT (pool), buffer.flags); GST_MINI_OBJECT_REFCOUNT (pool), buffer.flags);
switch (errno) { switch (errno) {
case EAGAIN: case EAGAIN:
GST_WARNING_OBJECT (pool->v4l2elem, GST_WARNING_OBJECT (obj->element,
"Non-blocking I/O has been selected using O_NONBLOCK and" "Non-blocking I/O has been selected using O_NONBLOCK and"
" no buffer was in the outgoing queue. device %s", " no buffer was in the outgoing queue. device %s", obj->videodev);
v4l2object->videodev);
break; break;
case EINVAL: case EINVAL:
GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, GST_ELEMENT_ERROR (obj->element, RESOURCE, FAILED,
(_("Failed trying to get video frames from device '%s'."), (_("Failed trying to get video frames from device '%s'."),
v4l2object->videodev), 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"), v4l2object->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));
break; break;
case ENOMEM: case ENOMEM:
GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, GST_ELEMENT_ERROR (obj->element, RESOURCE, FAILED,
(_("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)); (_("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));
break; break;
case EIO: case EIO:
GST_INFO_OBJECT (pool->v4l2elem, GST_INFO_OBJECT (obj->element,
"VIDIOC_DQBUF failed due to an internal error." "VIDIOC_DQBUF failed due to an internal error."
" Can also indicate temporary problems like signal loss." " Can also indicate temporary problems like signal loss."
" Note the driver might dequeue an (empty) buffer despite" " Note the driver might dequeue an (empty) buffer despite"
" returning an error, or even stop capturing." " returning an error, or even stop capturing."
" device %s", v4l2object->videodev); " device %s", obj->videodev);
/* have we de-queued a buffer ? */ /* have we de-queued a buffer ? */
if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) { if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) {
GST_DEBUG_OBJECT (pool->v4l2elem, "reenqueing buffer"); GST_DEBUG_OBJECT (obj->element, "reenqueing buffer");
/* FIXME ... should we do something here? */ /* FIXME ... should we do something here? */
} }
break; break;
case EINTR: case EINTR:
GST_WARNING_OBJECT (pool->v4l2elem, GST_WARNING_OBJECT (obj->element,
"could not sync on a buffer on device %s", v4l2object->videodev); "could not sync on a buffer on device %s", obj->videodev);
break; break;
default: default:
GST_WARNING_OBJECT (pool->v4l2elem, GST_WARNING_OBJECT (obj->element,
"Grabbing frame got interrupted on %s unexpectedly. %d: %s.", "Grabbing frame got interrupted on %s unexpectedly. %d: %s.",
v4l2object->videodev, errno, g_strerror (errno)); obj->videodev, errno, g_strerror (errno));
break; break;
} }
return NULL; return NULL;
} }
no_buffers: no_buffers:
{ {
GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, GST_ELEMENT_ERROR (obj->element, RESOURCE, FAILED,
(_("Failed trying to get video frames from device '%s'."), (_("Failed trying to get video frames from device '%s'."),
v4l2object->videodev), obj->videodev),
(_("No free buffers found in the pool at index %d."), buffer.index)); (_("No free buffers found in the pool at index %d."), buffer.index));
GST_V4L2_BUFFER_POOL_UNLOCK (pool); GST_V4L2_BUFFER_POOL_UNLOCK (pool);
return NULL; return NULL;

View file

@ -47,7 +47,7 @@ struct _GstV4l2BufferPool
{ {
GObject parent; GObject parent;
GstElement *v4l2elem; /* the v4l2 src/sink that owns us.. maybe we should be owned by v4l2object? */ GstV4l2Object *obj; /* the v4l2 object */
gboolean requeuebuf; /* if true, unusued buffers are automatically re-QBUF'd */ gboolean requeuebuf; /* if true, unusued buffers are automatically re-QBUF'd */
enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */ enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */
@ -83,8 +83,7 @@ const GstMetaInfo * gst_meta_v4l2_get_info (void);
#define GST_META_V4L2_ADD(buf) ((GstMetaV4l2 *)gst_buffer_add_meta(buf,gst_meta_v4l2_get_info(),NULL)) #define GST_META_V4L2_ADD(buf) ((GstMetaV4l2 *)gst_buffer_add_meta(buf,gst_meta_v4l2_get_info(),NULL))
void gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool); void gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool);
GstV4l2BufferPool *gst_v4l2_buffer_pool_new (GstElement *v4l2elem, gint fd, gint num_buffers, gboolean requeuebuf, enum v4l2_buf_type type); GstV4l2BufferPool *gst_v4l2_buffer_pool_new (GstV4l2Object *obj, gint num_buffers, gboolean requeuebuf);
GstBuffer *gst_v4l2_buffer_pool_get (GstV4l2BufferPool *pool, gboolean blocking); GstBuffer *gst_v4l2_buffer_pool_get (GstV4l2BufferPool *pool, gboolean blocking);
gboolean gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool *pool, GstBuffer *buf); gboolean gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool *pool, GstBuffer *buf);

View file

@ -2061,10 +2061,10 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
gboolean gboolean
gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat, gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
guint32 width, guint32 height, gboolean interlaced, guint32 * bytesperline) guint32 width, guint32 height, gboolean interlaced)
{ {
gint fd = v4l2object->video_fd; gint fd = v4l2object->video_fd;
struct v4l2_format format; struct v4l2_format *format;
enum v4l2_field field; enum v4l2_field field;
if (interlaced) { if (interlaced) {
@ -2089,22 +2089,24 @@ gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
(pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))) (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')))
return TRUE; return TRUE;
memset (&format, 0x00, sizeof (struct v4l2_format)); format = &v4l2object->format;
format.type = v4l2object->type;
if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0) memset (format, 0x00, sizeof (struct v4l2_format));
format->type = v4l2object->type;
if (v4l2_ioctl (fd, VIDIOC_G_FMT, format) < 0)
goto get_fmt_failed; goto get_fmt_failed;
GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format " GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
"%" GST_FOURCC_FORMAT " stride %d", format.fmt.pix.width, "%" GST_FOURCC_FORMAT " stride %d", format->fmt.pix.width,
format.fmt.pix.height, GST_FOURCC_ARGS (format.fmt.pix.pixelformat), format->fmt.pix.height, GST_FOURCC_ARGS (format->fmt.pix.pixelformat),
format.fmt.pix.bytesperline); format->fmt.pix.bytesperline);
if (format.type == v4l2object->type && if (format->type == v4l2object->type &&
format.fmt.pix.width == width && format->fmt.pix.width == width &&
format.fmt.pix.height == height && format->fmt.pix.height == height &&
format.fmt.pix.pixelformat == pixelformat && format->fmt.pix.pixelformat == pixelformat &&
format.fmt.pix.field == field) { format->fmt.pix.field == field) {
GST_DEBUG_OBJECT (v4l2object->element, "format was good"); GST_DEBUG_OBJECT (v4l2object->element, "format was good");
/* Nothing to do. We want to succeed immediately /* Nothing to do. We want to succeed immediately
* here because setting the same format back * here because setting the same format back
@ -2115,35 +2117,32 @@ gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
* any caps change would require us to go to NULL * any caps change would require us to go to NULL
* state to close the device and set format. * state to close the device and set format.
*/ */
*bytesperline = format.fmt.pix.bytesperline;
return TRUE; return TRUE;
} }
GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format " GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
"%" GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat)); "%" GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat));
format.type = v4l2object->type; format->type = v4l2object->type;
format.fmt.pix.width = width; format->fmt.pix.width = width;
format.fmt.pix.height = height; format->fmt.pix.height = height;
format.fmt.pix.pixelformat = pixelformat; format->fmt.pix.pixelformat = pixelformat;
format.fmt.pix.field = field; format->fmt.pix.field = field;
if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) if (v4l2_ioctl (fd, VIDIOC_S_FMT, format) < 0)
goto set_fmt_failed; goto set_fmt_failed;
GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format " GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
"%" GST_FOURCC_FORMAT " stride %d", format.fmt.pix.width, "%" GST_FOURCC_FORMAT " stride %d", format->fmt.pix.width,
format.fmt.pix.height, GST_FOURCC_ARGS (format.fmt.pix.pixelformat), format->fmt.pix.height, GST_FOURCC_ARGS (format->fmt.pix.pixelformat),
format.fmt.pix.bytesperline); format->fmt.pix.bytesperline);
if (format.fmt.pix.width != width || format.fmt.pix.height != height) if (format->fmt.pix.width != width || format->fmt.pix.height != height)
goto invalid_dimensions; goto invalid_dimensions;
if (format.fmt.pix.pixelformat != pixelformat) if (format->fmt.pix.pixelformat != pixelformat)
goto invalid_pixelformat; goto invalid_pixelformat;
*bytesperline = format.fmt.pix.bytesperline;
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
@ -2170,7 +2169,7 @@ invalid_dimensions:
(_("Device '%s' cannot capture at %dx%d"), (_("Device '%s' cannot capture at %dx%d"),
v4l2object->videodev, width, height), v4l2object->videodev, width, height),
("Tried to capture at %dx%d, but device returned size %dx%d", ("Tried to capture at %dx%d, but device returned size %dx%d",
width, height, format.fmt.pix.width, format.fmt.pix.height)); width, height, format->fmt.pix.width, format->fmt.pix.height));
return FALSE; return FALSE;
} }
invalid_pixelformat: invalid_pixelformat:
@ -2181,7 +2180,7 @@ invalid_pixelformat:
("Tried to capture in %" GST_FOURCC_FORMAT ("Tried to capture in %" GST_FOURCC_FORMAT
", but device returned format" " %" GST_FOURCC_FORMAT, ", but device returned format" " %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (pixelformat), GST_FOURCC_ARGS (pixelformat),
GST_FOURCC_ARGS (format.fmt.pix.pixelformat))); GST_FOURCC_ARGS (format->fmt.pix.pixelformat)));
return FALSE; return FALSE;
} }
} }

View file

@ -91,6 +91,9 @@ struct _GstV4l2Object {
enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */ enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */
/* the current format */
struct v4l2_format format;
/* the video device's capabilities */ /* the video device's capabilities */
struct v4l2_capability vcap; struct v4l2_capability vcap;
@ -190,7 +193,7 @@ GstCaps* gst_v4l2_object_get_all_caps (void);
GstStructure* gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc); GstStructure* gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc);
gboolean gst_v4l2_object_set_format (GstV4l2Object *v4l2object, guint32 pixelformat, guint32 width, guint32 height, gboolean interlaced, guint32 *bytesperline); gboolean gst_v4l2_object_set_format (GstV4l2Object *v4l2object, guint32 pixelformat, guint32 width, guint32 height, gboolean interlaced);
gboolean gst_v4l2_object_start_streaming (GstV4l2Object *v4l2object); gboolean gst_v4l2_object_start_streaming (GstV4l2Object *v4l2object);
gboolean gst_v4l2_object_stop_streaming (GstV4l2Object *v4l2object); gboolean gst_v4l2_object_stop_streaming (GstV4l2Object *v4l2object);

View file

@ -623,7 +623,6 @@ gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
guint fps_n, fps_d; guint fps_n, fps_d;
guint size; guint size;
GstV4l2BufferPool *newpool; GstV4l2BufferPool *newpool;
guint bytesperline;
LOG_CAPS (v4l2sink, caps); LOG_CAPS (v4l2sink, caps);
@ -660,15 +659,14 @@ gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
} }
if (!gst_v4l2_object_set_format (v4l2sink->v4l2object, format->pixelformat, if (!gst_v4l2_object_set_format (v4l2sink->v4l2object, format->pixelformat,
w, h, interlaced, &bytesperline)) w, h, interlaced))
goto invalid_format; goto invalid_format;
if (!(v4l2sink->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING)) if (!(v4l2sink->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING))
goto no_streaming; goto no_streaming;
newpool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2sink), newpool = gst_v4l2_buffer_pool_new (v4l2sink->v4l2object,
v4l2sink->v4l2object->video_fd, v4l2sink->num_buffers, FALSE);
v4l2sink->num_buffers, FALSE, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (newpool == NULL) if (newpool == NULL)
goto no_pool; goto no_pool;

View file

@ -131,7 +131,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
if (pool_buffer) if (pool_buffer)
break; break;
GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials); GST_WARNING_OBJECT (v4l2src, "trials=%d", trials);
/* if the sync() got interrupted, we can retry */ /* if the sync() got interrupted, we can retry */
switch (errno) { switch (errno) {
@ -182,7 +182,7 @@ no_buffer_pool:
} }
select_error: select_error:
{ {
GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, READ, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
("select error %d: %s (%d)", ret, g_strerror (errno), errno)); ("select error %d: %s (%d)", ret, g_strerror (errno), errno));
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -193,7 +193,7 @@ stopped:
} }
too_many_trials: too_many_trials:
{ {
GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
(_("Failed trying to get video frames from device '%s'."), (_("Failed trying to get video frames from device '%s'."),
v4l2object->videodev), v4l2object->videodev),
(_("Failed after %d tries. device %s. system error: %s"), (_("Failed after %d tries. device %s. system error: %s"),
@ -219,13 +219,12 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat,
{ {
gint fd = v4l2src->v4l2object->video_fd; gint fd = v4l2src->v4l2object->video_fd;
struct v4l2_streamparm stream; struct v4l2_streamparm stream;
guint32 bytesperline;
if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')) if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
return TRUE; return TRUE;
if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width, if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width,
height, interlaced, &bytesperline)) { height, interlaced)) {
/* error already reported */ /* error already reported */
return FALSE; return FALSE;
} }
@ -308,9 +307,8 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
/* Map the buffers */ /* Map the buffers */
GST_LOG_OBJECT (v4l2src, "initiating buffer pool"); GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2src), if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (v4l2src->v4l2object,
v4l2src->v4l2object->video_fd, v4l2src->num_buffers, TRUE)))
v4l2src->num_buffers, TRUE, V4L2_BUF_TYPE_VIDEO_CAPTURE)))
goto buffer_pool_new_failed; goto buffer_pool_new_failed;
GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()"); GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");