mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-08 16:35:40 +00:00
appsink: add propose_allocation support
Adding propose_allocation is to meet the requirement of Application to request buffers. Application sometimes need to create buffer pool and request buffers to maintain buffer management itself, and Gstreamer plugin import Application's buffers to use. So, add propose_allocation in appsink like waylandsink and kmssink etc. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4185>
This commit is contained in:
parent
c798f01fae
commit
96a46e31c7
4 changed files with 179 additions and 15 deletions
|
@ -374,6 +374,16 @@
|
|||
"return-type": "gboolean",
|
||||
"when": "last"
|
||||
},
|
||||
"propose-allocation": {
|
||||
"args": [
|
||||
{
|
||||
"name": "arg0",
|
||||
"type": "GstQuery"
|
||||
}
|
||||
],
|
||||
"return-type": "gboolean",
|
||||
"when": "last"
|
||||
},
|
||||
"pull-preroll": {
|
||||
"action": true,
|
||||
"args": [],
|
||||
|
|
|
@ -155,6 +155,7 @@ enum
|
|||
SIGNAL_TRY_PULL_PREROLL,
|
||||
SIGNAL_TRY_PULL_SAMPLE,
|
||||
SIGNAL_TRY_PULL_OBJECT,
|
||||
SIGNAL_PROPOSE_ALLOCATION,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
@ -212,6 +213,8 @@ static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink,
|
|||
GstBufferList * list);
|
||||
static gboolean gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps);
|
||||
static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter);
|
||||
static gboolean gst_app_sink_propose_allocation (GstBaseSink * bsink,
|
||||
GstQuery * query);
|
||||
|
||||
static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -335,6 +338,23 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
|
|||
G_STRUCT_OFFSET (GstAppSinkClass, new_sample),
|
||||
NULL, NULL, NULL, GST_TYPE_FLOW_RETURN, 0, G_TYPE_NONE);
|
||||
|
||||
/**
|
||||
* GstAppSink::propose-allocation:
|
||||
* @appsink: the appsink element that emitted the signal
|
||||
* @query: the allocation query
|
||||
*
|
||||
* Signal that a new propose_allocation query is available.
|
||||
*
|
||||
* This signal is emitted from the streaming thread and only when the
|
||||
* "emit-signals" property is %TRUE.
|
||||
*
|
||||
* Since: 1.24
|
||||
*/
|
||||
gst_app_sink_signals[SIGNAL_PROPOSE_ALLOCATION] =
|
||||
g_signal_new ("propose-allocation", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAppSinkClass, propose_allocation),
|
||||
NULL, NULL, NULL, G_TYPE_BOOLEAN, 1,
|
||||
GST_TYPE_QUERY | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
/**
|
||||
* GstAppSink::new-serialized-event:
|
||||
* @appsink: the appsink element that emitted the signal
|
||||
|
@ -539,6 +559,7 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
|
|||
basesink_class->get_caps = gst_app_sink_getcaps;
|
||||
basesink_class->set_caps = gst_app_sink_setcaps;
|
||||
basesink_class->query = gst_app_sink_query;
|
||||
basesink_class->propose_allocation = gst_app_sink_propose_allocation;
|
||||
|
||||
klass->pull_preroll = gst_app_sink_pull_preroll;
|
||||
klass->pull_sample = gst_app_sink_pull_sample;
|
||||
|
@ -2047,3 +2068,32 @@ gst_app_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
|
|||
iface->set_uri = gst_app_sink_uri_set_uri;
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_app_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GstAppSink *appsink = GST_APP_SINK_CAST (bsink);
|
||||
GstAppSinkPrivate *priv = appsink->priv;
|
||||
Callbacks *callbacks = NULL;
|
||||
gboolean emit;
|
||||
|
||||
g_mutex_lock (&priv->mutex);
|
||||
emit = priv->emit_signals;
|
||||
if (priv->callbacks)
|
||||
callbacks = callbacks_ref (priv->callbacks);
|
||||
g_mutex_unlock (&priv->mutex);
|
||||
|
||||
if (callbacks && callbacks->callbacks.propose_allocation) {
|
||||
ret =
|
||||
callbacks->callbacks.propose_allocation (appsink, query,
|
||||
callbacks->user_data);
|
||||
} else if (emit) {
|
||||
g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_PROPOSE_ALLOCATION], 0,
|
||||
query, &ret);
|
||||
}
|
||||
|
||||
g_clear_pointer (&callbacks, callbacks_unref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -67,18 +67,25 @@ typedef struct _GstAppSinkPrivate GstAppSinkPrivate;
|
|||
* The callback should return %TRUE if the event has been handled,
|
||||
* %FALSE otherwise.
|
||||
* Since: 1.20
|
||||
* @propose_allocation: Called when the propose_allocation query is available.
|
||||
* This callback is called from the streaming thread.
|
||||
* The allocation query can be retrieved with
|
||||
* gst_app_sink_propose_allocation() either from this callback
|
||||
* or from any other thread.
|
||||
* Since: 1.24
|
||||
*
|
||||
* A set of callbacks that can be installed on the appsink with
|
||||
* gst_app_sink_set_callbacks().
|
||||
*/
|
||||
typedef struct {
|
||||
void (*eos) (GstAppSink *appsink, gpointer user_data);
|
||||
GstFlowReturn (*new_preroll) (GstAppSink *appsink, gpointer user_data);
|
||||
GstFlowReturn (*new_sample) (GstAppSink *appsink, gpointer user_data);
|
||||
gboolean (*new_event) (GstAppSink *appsink, gpointer user_data);
|
||||
void (*eos) (GstAppSink *appsink, gpointer user_data);
|
||||
GstFlowReturn (*new_preroll) (GstAppSink *appsink, gpointer user_data);
|
||||
GstFlowReturn (*new_sample) (GstAppSink *appsink, gpointer user_data);
|
||||
gboolean (*new_event) (GstAppSink *appsink, gpointer user_data);
|
||||
gboolean (*propose_allocation) (GstAppSink *appsink, GstQuery *query, gpointer user_data);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING - 1];
|
||||
gpointer _gst_reserved[GST_PADDING - 2];
|
||||
} GstAppSinkCallbacks;
|
||||
|
||||
struct _GstAppSink
|
||||
|
@ -97,16 +104,16 @@ struct _GstAppSinkClass
|
|||
GstBaseSinkClass basesink_class;
|
||||
|
||||
/* signals */
|
||||
void (*eos) (GstAppSink *appsink);
|
||||
GstFlowReturn (*new_preroll) (GstAppSink *appsink);
|
||||
GstFlowReturn (*new_sample) (GstAppSink *appsink);
|
||||
void (*eos) (GstAppSink *appsink);
|
||||
GstFlowReturn (*new_preroll) (GstAppSink *appsink);
|
||||
GstFlowReturn (*new_sample) (GstAppSink *appsink);
|
||||
/* new_event is missing as we ran out padding */
|
||||
|
||||
/* actions */
|
||||
GstSample * (*pull_preroll) (GstAppSink *appsink);
|
||||
GstSample * (*pull_sample) (GstAppSink *appsink);
|
||||
GstSample * (*try_pull_preroll) (GstAppSink *appsink, GstClockTime timeout);
|
||||
GstSample * (*try_pull_sample) (GstAppSink *appsink, GstClockTime timeout);
|
||||
GstSample * (*pull_preroll) (GstAppSink *appsink);
|
||||
GstSample * (*pull_sample) (GstAppSink *appsink);
|
||||
GstSample * (*try_pull_preroll) (GstAppSink *appsink, GstClockTime timeout);
|
||||
GstSample * (*try_pull_sample) (GstAppSink *appsink, GstClockTime timeout);
|
||||
/**
|
||||
* GstAppSinkClass::try_pull_object:
|
||||
*
|
||||
|
@ -114,10 +121,18 @@ struct _GstAppSinkClass
|
|||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
GstMiniObject * (*try_pull_object) (GstAppSink *appsink, GstClockTime timeout);
|
||||
|
||||
|
||||
GstMiniObject * (*try_pull_object) (GstAppSink *appsink, GstClockTime timeout);
|
||||
/**
|
||||
* GstAppSinkClass::propose_allocation:
|
||||
*
|
||||
* See #GstAppSink::propose-allocation: signal.
|
||||
*
|
||||
* Since: 1.24
|
||||
*/
|
||||
gboolean (*propose_allocation) (GstAppSink *appsink, GstQuery *query);
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING - 3];
|
||||
gpointer _gst_reserved[GST_PADDING - 4];
|
||||
};
|
||||
|
||||
GST_APP_API
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <gst/check/gstcheck.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
gint global_testdata;
|
||||
|
||||
|
@ -1068,6 +1069,92 @@ GST_START_TEST (test_caps_before_flush_race_condition)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
static gboolean
|
||||
propose_allocation_cb (GstAppSink * appsink, GstQuery * query,
|
||||
gpointer callback_data)
|
||||
{
|
||||
guint *allocation_query_count = callback_data;
|
||||
*allocation_query_count += 1;
|
||||
fail_unless (gst_query_is_writable (query));
|
||||
fail_unless (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
|
||||
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Verifies that the allocation query callback is called */
|
||||
GST_START_TEST (test_query_allocation_callback)
|
||||
{
|
||||
GstElement *sink;
|
||||
GstAppSinkCallbacks callbacks = { NULL };
|
||||
GstAppSink *app_sink;
|
||||
GstQuery *query = NULL;
|
||||
guint allocation_query_count = 0;
|
||||
GstPad *sinkpad;
|
||||
|
||||
sink = setup_appsink ();
|
||||
app_sink = GST_APP_SINK (sink);
|
||||
|
||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||
fail_unless (sinkpad);
|
||||
|
||||
callbacks.propose_allocation = propose_allocation_cb;
|
||||
gst_app_sink_set_callbacks (app_sink, &callbacks, &allocation_query_count,
|
||||
NULL);
|
||||
|
||||
query = gst_query_new_allocation (NULL, FALSE);
|
||||
fail_unless (gst_pad_query (sinkpad, query));
|
||||
|
||||
fail_unless_equals_int (allocation_query_count, 1);
|
||||
fail_unless (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE,
|
||||
NULL));
|
||||
|
||||
ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
|
||||
|
||||
gst_object_unref (sinkpad);
|
||||
gst_query_unref (query);
|
||||
|
||||
GST_DEBUG ("cleaning up appsink");
|
||||
ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
|
||||
cleanup_appsink (sink);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_query_allocation_signals)
|
||||
{
|
||||
GstElement *sink;
|
||||
GstQuery *query = NULL;
|
||||
guint allocation_query_count = 0;
|
||||
GstPad *sinkpad;
|
||||
|
||||
sink = setup_appsink ();
|
||||
|
||||
g_object_set (sink, "emit-signals", TRUE, NULL);
|
||||
g_signal_connect (sink, "propose-allocation",
|
||||
G_CALLBACK (propose_allocation_cb), &allocation_query_count);
|
||||
|
||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||
fail_unless (sinkpad);
|
||||
query = gst_query_new_allocation (NULL, FALSE);
|
||||
fail_unless (gst_pad_query (sinkpad, query));
|
||||
|
||||
fail_unless_equals_int (allocation_query_count, 1);
|
||||
fail_unless (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE,
|
||||
NULL));
|
||||
|
||||
ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
|
||||
|
||||
gst_object_unref (sinkpad);
|
||||
if (query)
|
||||
gst_query_unref (query);
|
||||
|
||||
GST_DEBUG ("cleaning up appsink");
|
||||
ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
|
||||
cleanup_appsink (sink);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
appsink_suite (void)
|
||||
{
|
||||
|
@ -1094,6 +1181,8 @@ appsink_suite (void)
|
|||
tcase_add_test (tc_chain, test_event_paused);
|
||||
tcase_add_test (tc_chain, test_reverse_stepping);
|
||||
tcase_add_test (tc_chain, test_caps_before_flush_race_condition);
|
||||
tcase_add_test (tc_chain, test_query_allocation_callback);
|
||||
tcase_add_test (tc_chain, test_query_allocation_signals);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue