v4l2bufferpool: Sanetize buffer refount handling

Buffer refcounting is a bit hard, because of the duality between CAPTURE and
OUTPUT mode. In the long term, we should consider having two seperate pool
instead of this mess. At least state should be better kept this way.
This commit is contained in:
Nicolas Dufresne 2014-04-29 12:57:08 -04:00
parent deb40de4b8
commit f13331e928

View file

@ -314,6 +314,7 @@ gst_v4l2_buffer_pool_prepare_buffer (GstV4l2BufferPool * pool,
GstBuffer * dest, GstBuffer * src) GstBuffer * dest, GstBuffer * src)
{ {
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
gboolean own_src = FALSE;
if (src == NULL) { if (src == NULL) {
if (pool->other_pool == NULL) { if (pool->other_pool == NULL) {
@ -326,6 +327,8 @@ gst_v4l2_buffer_pool_prepare_buffer (GstV4l2BufferPool * pool,
GST_ERROR_OBJECT (pool, "failed to acquire buffer from downstream pool"); GST_ERROR_OBJECT (pool, "failed to acquire buffer from downstream pool");
goto done; goto done;
} }
own_src = TRUE;
} }
switch (pool->obj->mode) { switch (pool->obj->mode) {
@ -343,6 +346,9 @@ gst_v4l2_buffer_pool_prepare_buffer (GstV4l2BufferPool * pool,
break; break;
} }
if (own_src)
gst_buffer_unref (src);
done: done:
return ret; return ret;
} }
@ -1006,15 +1012,13 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
already_queued: already_queued:
{ {
GST_ERROR_OBJECT (pool, "the buffer %i was already queued", index); GST_ERROR_OBJECT (pool, "the buffer %i was already queued", index);
gst_buffer_unref (buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
queue_failed: queue_failed:
{ {
GST_ERROR_OBJECT (pool, "could not queue a buffer %i", index); GST_ERROR_OBJECT (pool, "could not queue a buffer %i", index);
/* Return broken buffer to the allocator */ /* Mark broken buffer to the allocator */
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_TAG_MEMORY); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_TAG_MEMORY);
gst_buffer_unref (buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
} }
@ -1287,7 +1291,9 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
/* queue back in the device */ /* queue back in the device */
if (pool->other_pool) if (pool->other_pool)
gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL); gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL);
gst_v4l2_buffer_pool_qbuf (pool, buffer); if (gst_v4l2_buffer_pool_qbuf (pool, buffer) != GST_FLOW_OK)
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
buffer);
} else { } else {
/* Simply release invalide/modified buffer, the allocator will /* Simply release invalide/modified buffer, the allocator will
* give it back later */ * give it back later */
@ -1584,16 +1590,17 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf)
/* An empty buffer on capture indicates the end of stream */ /* An empty buffer on capture indicates the end of stream */
if (gst_buffer_get_size (tmp) == 0) { if (gst_buffer_get_size (tmp) == 0) {
gst_buffer_unref (tmp); gst_v4l2_buffer_pool_release_buffer (bpool, tmp);
goto eos; goto eos;
} }
if (gst_v4l2_buffer_pool_copy_buffer (pool, buf, tmp) != GST_FLOW_OK) ret = gst_v4l2_buffer_pool_copy_buffer (pool, *buf, tmp);
goto copy_failed;
/* an queue the buffer again after the copy */ /* an queue the buffer again after the copy */
if ((ret = gst_v4l2_buffer_pool_qbuf (pool, tmp)) != GST_FLOW_OK) gst_v4l2_buffer_pool_release_buffer (bpool, tmp);
goto done;
if (ret != GST_FLOW_OK)
goto copy_failed;
break; break;
} }
@ -1644,36 +1651,34 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf)
goto acquire_failed; goto acquire_failed;
ret = gst_v4l2_buffer_pool_prepare_buffer (pool, to_queue, buf); ret = gst_v4l2_buffer_pool_prepare_buffer (pool, to_queue, buf);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK) {
gst_buffer_unref (to_queue);
goto prepare_failed; goto prepare_failed;
}
} }
if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK) if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK)
goto done; goto queue_failed;
/* if we are not streaming yet (this is the first buffer, start /* if we are not streaming yet (this is the first buffer, start
* streaming now */ * streaming now */
if (!pool->streaming) if (!pool->streaming) {
if (!start_streaming (pool)) if (!start_streaming (pool)) {
gst_buffer_unref (to_queue);
goto start_failed; goto start_failed;
}
}
if (pool->num_queued == pool->num_allocated) { if (pool->num_queued == pool->num_allocated) {
GstBuffer *out; GstBuffer *out;
/* all buffers are queued, try to dequeue one and release it back /* all buffers are queued, try to dequeue one and release it back
* into the pool so that _acquire can get to it again. */ * into the pool so that _acquire can get to it again. */
ret = gst_v4l2_buffer_pool_dqbuf (pool, &out); ret = gst_v4l2_buffer_pool_dqbuf (pool, &out);
if (ret != GST_FLOW_OK) { if (ret == GST_FLOW_OK)
gst_buffer_unref (to_queue); /* release the rendered buffer back into the pool. This wakes up any
goto done; * thread waiting for a buffer in _acquire(). */
} gst_buffer_unref (out);
/* release the rendered buffer back into the pool. This wakes up any
* thread waiting for a buffer in _acquire(). If the buffer still has
* a pool then this will happen when the refcount reaches 0 */
if (!out->pool)
gst_v4l2_buffer_pool_release_buffer (bpool, out);
} }
gst_buffer_unref (to_queue);
break; break;
} }
default: default:
@ -1689,6 +1694,16 @@ done:
return ret; return ret;
/* ERRORS */ /* ERRORS */
copy_failed:
{
GST_ERROR_OBJECT (obj->element, "failed to copy buffer");
return ret;
}
eos:
{
GST_DEBUG_OBJECT (obj->element, "end of stream reached");
return GST_FLOW_EOS;
}
acquire_failed: acquire_failed:
{ {
GST_WARNING_OBJECT (obj->element, "failed to acquire a buffer: %s", GST_WARNING_OBJECT (obj->element, "failed to acquire a buffer: %s",
@ -1700,21 +1715,16 @@ prepare_failed:
GST_ERROR_OBJECT (obj->element, "failed to prepare data"); GST_ERROR_OBJECT (obj->element, "failed to prepare data");
return ret; return ret;
} }
queue_failed:
{
GST_ERROR_OBJECT (obj->element, "failed to queue buffer");
return ret;
}
start_failed: start_failed:
{ {
GST_ERROR_OBJECT (obj->element, "failed to start streaming"); GST_ERROR_OBJECT (obj->element, "failed to start streaming");
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
copy_failed:
{
GST_ERROR_OBJECT (obj->element, "failed to copy buffer");
return GST_FLOW_ERROR;
}
eos:
{
GST_DEBUG_OBJECT (obj->element, "end of stream reached");
return GST_FLOW_EOS;
}
} }