Added buffer list support.

This commit is contained in:
Branko Subasic 2009-06-17 11:12:08 +02:00 committed by Wim Taymans
parent fb0fd53212
commit 6518d283d5

View file

@ -84,6 +84,7 @@
#include <gst/gst.h>
#include <gst/base/gstbasesink.h>
#include <gst/gstbuffer.h>
#include <gst/gstbufferlist.h>
#include <string.h>
@ -166,9 +167,14 @@ static gboolean gst_app_sink_stop (GstBaseSink * psink);
static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
GstBuffer * buffer);
static GstFlowReturn gst_app_sink_render_common (GstBaseSink * psink,
GstMiniObject * data, gboolean is_list);
static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
GstBuffer * buffer);
static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink,
GstBufferList * list);
static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink);
static GstMiniObject *gst_app_sink_pull_object (GstAppSink * appsink);
static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
@ -388,10 +394,12 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
basesink_class->event = gst_app_sink_event;
basesink_class->preroll = gst_app_sink_preroll;
basesink_class->render = gst_app_sink_render;
basesink_class->render_list = gst_app_sink_render_list;
basesink_class->get_caps = gst_app_sink_getcaps;
klass->pull_preroll = gst_app_sink_pull_preroll;
klass->pull_buffer = gst_app_sink_pull_buffer;
klass->pull_buffer_list = gst_app_sink_pull_buffer_list;
g_type_class_add_private (klass, sizeof (GstAppSinkPrivate));
}
@ -415,7 +423,7 @@ static void
gst_app_sink_dispose (GObject * obj)
{
GstAppSink *appsink = GST_APP_SINK (obj);
GstBuffer *buffer;
GstMiniObject *queue_obj;
GST_OBJECT_LOCK (appsink);
if (appsink->priv->caps) {
@ -435,8 +443,8 @@ gst_app_sink_dispose (GObject * obj)
gst_buffer_unref (appsink->priv->preroll);
appsink->priv->preroll = NULL;
}
while ((buffer = g_queue_pop_head (appsink->priv->queue)))
gst_buffer_unref (buffer);
while ((queue_obj = g_queue_pop_head (appsink->priv->queue)))
gst_mini_object_unref (queue_obj);
g_mutex_unlock (appsink->priv->mutex);
G_OBJECT_CLASS (parent_class)->dispose (obj);
@ -545,13 +553,13 @@ gst_app_sink_unlock_stop (GstBaseSink * bsink)
static void
gst_app_sink_flush_unlocked (GstAppSink * appsink)
{
GstBuffer *buffer;
GstMiniObject *obj;
GST_DEBUG_OBJECT (appsink, "flush stop appsink");
appsink->priv->is_eos = FALSE;
gst_buffer_replace (&appsink->priv->preroll, NULL);
while ((buffer = g_queue_pop_head (appsink->priv->queue)))
gst_buffer_unref (buffer);
while ((obj = g_queue_pop_head (appsink->priv->queue)))
gst_mini_object_unref (obj);
g_cond_signal (appsink->priv->cond);
}
@ -657,9 +665,9 @@ flushing:
}
static GstFlowReturn
gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
gst_app_sink_render_common (GstBaseSink * psink, GstMiniObject * data,
gboolean is_list)
{
GstFlowReturn res = GST_FLOW_OK;
GstAppSink *appsink = GST_APP_SINK (psink);
gboolean emit;
@ -667,18 +675,18 @@ gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
if (appsink->priv->flushing)
goto flushing;
GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue (%d)",
buffer, appsink->priv->queue->length);
GST_DEBUG_OBJECT (appsink, "pushing render buffer%s %p on queue (%d)",
is_list ? " list" : "", data, appsink->priv->queue->length);
while (appsink->priv->max_buffers > 0 &&
appsink->priv->queue->length >= appsink->priv->max_buffers) {
if (appsink->priv->drop) {
GstBuffer *buf;
GstMiniObject *obj;
/* we need to drop the oldest buffer and try again */
buf = g_queue_pop_head (appsink->priv->queue);
GST_DEBUG_OBJECT (appsink, "dropping old buffer %p", buf);
gst_buffer_unref (buf);
/* we need to drop the oldest buffer/list and try again */
obj = g_queue_pop_head (appsink->priv->queue);
GST_DEBUG_OBJECT (appsink, "dropping old buffer/list %p", obj);
gst_mini_object_unref (obj);
} else {
GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d",
appsink->priv->queue->length, appsink->priv->max_buffers);
@ -689,19 +697,22 @@ gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
}
}
/* we need to ref the buffer when pushing it in the queue */
g_queue_push_tail (appsink->priv->queue, gst_buffer_ref (buffer));
g_queue_push_tail (appsink->priv->queue, gst_mini_object_ref (data));
g_cond_signal (appsink->priv->cond);
emit = appsink->priv->emit_signals;
g_mutex_unlock (appsink->priv->mutex);
if (appsink->priv->callbacks.new_buffer)
res =
appsink->priv->callbacks.new_buffer (appsink, appsink->priv->user_data);
else if (emit)
g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0);
return res;
if (is_list) {
if (appsink->priv->callbacks.new_buffer_list)
appsink->priv->callbacks.new_buffer_list (appsink,
appsink->priv->user_data);
} else {
if (appsink->priv->callbacks.new_buffer)
appsink->priv->callbacks.new_buffer (appsink, appsink->priv->user_data);
else if (emit)
g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0);
}
return GST_FLOW_OK;
flushing:
{
@ -711,6 +722,19 @@ flushing:
}
}
static GstFlowReturn
gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
{
return gst_app_sink_render_common (psink, GST_MINI_OBJECT_CAST (buffer),
FALSE);
}
static GstFlowReturn
gst_app_sink_render_list (GstBaseSink * psink, GstBufferList * list)
{
return gst_app_sink_render_common (psink, GST_MINI_OBJECT_CAST (list), TRUE);
}
static GstCaps *
gst_app_sink_getcaps (GstBaseSink * psink)
{
@ -727,6 +751,53 @@ gst_app_sink_getcaps (GstBaseSink * psink)
return caps;
}
static GstMiniObject *
gst_app_sink_pull_object (GstAppSink * appsink)
{
GstMiniObject *obj = NULL;
g_return_val_if_fail (appsink != NULL, NULL);
g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
g_mutex_lock (appsink->priv->mutex);
while (TRUE) {
GST_DEBUG_OBJECT (appsink, "trying to grab a buffer/list");
if (!appsink->priv->started)
goto not_started;
if (!g_queue_is_empty (appsink->priv->queue))
break;
if (appsink->priv->is_eos)
goto eos;
/* nothing to return, wait */
GST_DEBUG_OBJECT (appsink, "waiting for a buffer/list");
g_cond_wait (appsink->priv->cond, appsink->priv->mutex);
}
obj = g_queue_pop_head (appsink->priv->queue);
GST_DEBUG_OBJECT (appsink, "we have a buffer/list %p", obj);
g_cond_signal (appsink->priv->cond);
g_mutex_unlock (appsink->priv->mutex);
return obj;
/* special conditions */
eos:
{
GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
g_mutex_unlock (appsink->priv->mutex);
return NULL;
}
not_started:
{
GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
g_mutex_unlock (appsink->priv->mutex);
return NULL;
}
}
/* external API */
/**
@ -1070,51 +1141,38 @@ not_started:
*
* Since: 0.10.22
*/
GstBuffer *
gst_app_sink_pull_buffer (GstAppSink * appsink)
{
GstBuffer *buf = NULL;
GST_DEBUG_OBJECT (appsink, "pull a buffer");
return GST_BUFFER_CAST (gst_app_sink_pull_object (appsink));
}
g_return_val_if_fail (appsink != NULL, NULL);
g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
g_mutex_lock (appsink->priv->mutex);
while (TRUE) {
GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
if (!appsink->priv->started)
goto not_started;
if (!g_queue_is_empty (appsink->priv->queue))
break;
if (appsink->priv->is_eos)
goto eos;
/* nothing to return, wait */
GST_DEBUG_OBJECT (appsink, "waiting for a buffer");
g_cond_wait (appsink->priv->cond, appsink->priv->mutex);
}
buf = g_queue_pop_head (appsink->priv->queue);
GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buf);
g_cond_signal (appsink->priv->cond);
g_mutex_unlock (appsink->priv->mutex);
return buf;
/* special conditions */
eos:
{
GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
g_mutex_unlock (appsink->priv->mutex);
return NULL;
}
not_started:
{
GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
g_mutex_unlock (appsink->priv->mutex);
return NULL;
}
/**
* gst_app_sink_pull_buffer_list:
* @appsink: a #GstAppSink
*
* This function blocks until a buffer list or EOS becomes available or the
* appsink element is set to the READY/NULL state.
*
* This function will only return buffer lists when the appsink is in the
* PLAYING state. All rendered buffer lists will be put in a queue so that
* the application can pull buffer lists at its own rate. Note that when
* the application does not pull buffer lists fast enough, the queued buffer
* lists could consume a lot of memory, especially when dealing with raw
* video frames.
*
* If an EOS event was received before any buffer lists, this function returns
* %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
*
* Returns: a #GstBufferList or NULL when the appsink is stopped or EOS.
*/
GstBufferList *
gst_app_sink_pull_buffer_list (GstAppSink * appsink)
{
GST_DEBUG_OBJECT (appsink, "pull a buffer list");
return GST_BUFFER_LIST_CAST (gst_app_sink_pull_object (appsink));
}
/**