mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-12 18:35:35 +00:00
Added buffer list support.
This commit is contained in:
parent
fb0fd53212
commit
6518d283d5
1 changed files with 123 additions and 65 deletions
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue