mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-13 02:45: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/gst.h>
|
||||||
#include <gst/base/gstbasesink.h>
|
#include <gst/base/gstbasesink.h>
|
||||||
#include <gst/gstbuffer.h>
|
#include <gst/gstbuffer.h>
|
||||||
|
#include <gst/gstbufferlist.h>
|
||||||
|
|
||||||
#include <string.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 gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
|
||||||
static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
|
static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
|
static GstFlowReturn gst_app_sink_render_common (GstBaseSink * psink,
|
||||||
|
GstMiniObject * data, gboolean is_list);
|
||||||
static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
|
static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
|
static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink,
|
||||||
|
GstBufferList * list);
|
||||||
static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink);
|
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 };
|
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->event = gst_app_sink_event;
|
||||||
basesink_class->preroll = gst_app_sink_preroll;
|
basesink_class->preroll = gst_app_sink_preroll;
|
||||||
basesink_class->render = gst_app_sink_render;
|
basesink_class->render = gst_app_sink_render;
|
||||||
|
basesink_class->render_list = gst_app_sink_render_list;
|
||||||
basesink_class->get_caps = gst_app_sink_getcaps;
|
basesink_class->get_caps = gst_app_sink_getcaps;
|
||||||
|
|
||||||
klass->pull_preroll = gst_app_sink_pull_preroll;
|
klass->pull_preroll = gst_app_sink_pull_preroll;
|
||||||
klass->pull_buffer = gst_app_sink_pull_buffer;
|
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));
|
g_type_class_add_private (klass, sizeof (GstAppSinkPrivate));
|
||||||
}
|
}
|
||||||
|
@ -415,7 +423,7 @@ static void
|
||||||
gst_app_sink_dispose (GObject * obj)
|
gst_app_sink_dispose (GObject * obj)
|
||||||
{
|
{
|
||||||
GstAppSink *appsink = GST_APP_SINK (obj);
|
GstAppSink *appsink = GST_APP_SINK (obj);
|
||||||
GstBuffer *buffer;
|
GstMiniObject *queue_obj;
|
||||||
|
|
||||||
GST_OBJECT_LOCK (appsink);
|
GST_OBJECT_LOCK (appsink);
|
||||||
if (appsink->priv->caps) {
|
if (appsink->priv->caps) {
|
||||||
|
@ -435,8 +443,8 @@ gst_app_sink_dispose (GObject * obj)
|
||||||
gst_buffer_unref (appsink->priv->preroll);
|
gst_buffer_unref (appsink->priv->preroll);
|
||||||
appsink->priv->preroll = NULL;
|
appsink->priv->preroll = NULL;
|
||||||
}
|
}
|
||||||
while ((buffer = g_queue_pop_head (appsink->priv->queue)))
|
while ((queue_obj = g_queue_pop_head (appsink->priv->queue)))
|
||||||
gst_buffer_unref (buffer);
|
gst_mini_object_unref (queue_obj);
|
||||||
g_mutex_unlock (appsink->priv->mutex);
|
g_mutex_unlock (appsink->priv->mutex);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (obj);
|
G_OBJECT_CLASS (parent_class)->dispose (obj);
|
||||||
|
@ -545,13 +553,13 @@ gst_app_sink_unlock_stop (GstBaseSink * bsink)
|
||||||
static void
|
static void
|
||||||
gst_app_sink_flush_unlocked (GstAppSink * appsink)
|
gst_app_sink_flush_unlocked (GstAppSink * appsink)
|
||||||
{
|
{
|
||||||
GstBuffer *buffer;
|
GstMiniObject *obj;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (appsink, "flush stop appsink");
|
GST_DEBUG_OBJECT (appsink, "flush stop appsink");
|
||||||
appsink->priv->is_eos = FALSE;
|
appsink->priv->is_eos = FALSE;
|
||||||
gst_buffer_replace (&appsink->priv->preroll, NULL);
|
gst_buffer_replace (&appsink->priv->preroll, NULL);
|
||||||
while ((buffer = g_queue_pop_head (appsink->priv->queue)))
|
while ((obj = g_queue_pop_head (appsink->priv->queue)))
|
||||||
gst_buffer_unref (buffer);
|
gst_mini_object_unref (obj);
|
||||||
g_cond_signal (appsink->priv->cond);
|
g_cond_signal (appsink->priv->cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,9 +665,9 @@ flushing:
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
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);
|
GstAppSink *appsink = GST_APP_SINK (psink);
|
||||||
gboolean emit;
|
gboolean emit;
|
||||||
|
|
||||||
|
@ -667,18 +675,18 @@ gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
|
||||||
if (appsink->priv->flushing)
|
if (appsink->priv->flushing)
|
||||||
goto flushing;
|
goto flushing;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue (%d)",
|
GST_DEBUG_OBJECT (appsink, "pushing render buffer%s %p on queue (%d)",
|
||||||
buffer, appsink->priv->queue->length);
|
is_list ? " list" : "", data, appsink->priv->queue->length);
|
||||||
|
|
||||||
while (appsink->priv->max_buffers > 0 &&
|
while (appsink->priv->max_buffers > 0 &&
|
||||||
appsink->priv->queue->length >= appsink->priv->max_buffers) {
|
appsink->priv->queue->length >= appsink->priv->max_buffers) {
|
||||||
if (appsink->priv->drop) {
|
if (appsink->priv->drop) {
|
||||||
GstBuffer *buf;
|
GstMiniObject *obj;
|
||||||
|
|
||||||
/* we need to drop the oldest buffer and try again */
|
/* we need to drop the oldest buffer/list and try again */
|
||||||
buf = g_queue_pop_head (appsink->priv->queue);
|
obj = g_queue_pop_head (appsink->priv->queue);
|
||||||
GST_DEBUG_OBJECT (appsink, "dropping old buffer %p", buf);
|
GST_DEBUG_OBJECT (appsink, "dropping old buffer/list %p", obj);
|
||||||
gst_buffer_unref (buf);
|
gst_mini_object_unref (obj);
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d",
|
GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d",
|
||||||
appsink->priv->queue->length, appsink->priv->max_buffers);
|
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 */
|
/* 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);
|
g_cond_signal (appsink->priv->cond);
|
||||||
emit = appsink->priv->emit_signals;
|
emit = appsink->priv->emit_signals;
|
||||||
g_mutex_unlock (appsink->priv->mutex);
|
g_mutex_unlock (appsink->priv->mutex);
|
||||||
|
|
||||||
|
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)
|
if (appsink->priv->callbacks.new_buffer)
|
||||||
res =
|
|
||||||
appsink->priv->callbacks.new_buffer (appsink, appsink->priv->user_data);
|
appsink->priv->callbacks.new_buffer (appsink, appsink->priv->user_data);
|
||||||
else if (emit)
|
else if (emit)
|
||||||
g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0);
|
g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0);
|
||||||
|
}
|
||||||
return res;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
flushing:
|
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 *
|
static GstCaps *
|
||||||
gst_app_sink_getcaps (GstBaseSink * psink)
|
gst_app_sink_getcaps (GstBaseSink * psink)
|
||||||
{
|
{
|
||||||
|
@ -727,6 +751,53 @@ gst_app_sink_getcaps (GstBaseSink * psink)
|
||||||
return caps;
|
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 */
|
/* external API */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1070,51 +1141,38 @@ not_started:
|
||||||
*
|
*
|
||||||
* Since: 0.10.22
|
* Since: 0.10.22
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GstBuffer *
|
GstBuffer *
|
||||||
gst_app_sink_pull_buffer (GstAppSink * appsink)
|
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;
|
/**
|
||||||
|
* gst_app_sink_pull_buffer_list:
|
||||||
/* special conditions */
|
* @appsink: a #GstAppSink
|
||||||
eos:
|
*
|
||||||
|
* 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, "we are EOS, return NULL");
|
GST_DEBUG_OBJECT (appsink, "pull a buffer list");
|
||||||
g_mutex_unlock (appsink->priv->mutex);
|
return GST_BUFFER_LIST_CAST (gst_app_sink_pull_object (appsink));
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
not_started:
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
|
|
||||||
g_mutex_unlock (appsink->priv->mutex);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue