fake{video|audio}sink: don't proxy properties at instance init.

Instead proxy properties from the GstBaseSink class at class_init time,
and duplicate the rest of the fakesink properties manually.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1442

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3073>
This commit is contained in:
Mathieu Duponchelle 2022-09-23 18:25:41 +02:00 committed by GStreamer Marge Bot
parent 75872c802b
commit 11c74ccec6
6 changed files with 308 additions and 47 deletions

View file

@ -34716,14 +34716,6 @@
"element-fakesink",
"element-fakesrc",
"element-fakevideosink",
"element-fakevideosink_GstFakeSinkStateError",
"element-fakevideosink_GstFakeSinkStateError::none",
"element-fakevideosink_GstFakeSinkStateError::null-to-ready",
"element-fakevideosink_GstFakeSinkStateError::paused-to-playing",
"element-fakevideosink_GstFakeSinkStateError::paused-to-ready",
"element-fakevideosink_GstFakeSinkStateError::playing-to-paused",
"element-fakevideosink_GstFakeSinkStateError::ready-to-null",
"element-fakevideosink_GstFakeSinkStateError::ready-to-paused",
"element-fbdevsink",
"element-fdkaacdec",
"element-fdkaacenc",

View file

@ -10454,7 +10454,7 @@
"default": "none (0)",
"mutable": "null",
"readable": true,
"type": "GstFakeSinkStateError",
"type": "GstFakeAudioSinkStateError",
"writable": true
},
"stats": {
@ -10816,7 +10816,7 @@
"default": "none (0)",
"mutable": "null",
"readable": true,
"type": "GstFakeSinkStateError",
"type": "GstFakeVideoSinkStateError",
"writable": true
},
"stats": {
@ -11308,7 +11308,7 @@
}
]
},
"GstFakeSinkStateError": {
"GstFakeAudioSinkStateError": {
"kind": "enum",
"values": [
{
@ -11362,6 +11362,46 @@
"value": "0x00000002"
}
]
},
"GstFakeVideoSinkStateError": {
"kind": "enum",
"values": [
{
"desc": "No state change errors",
"name": "none",
"value": "0"
},
{
"desc": "Fail state change from NULL to READY",
"name": "null-to-ready",
"value": "1"
},
{
"desc": "Fail state change from READY to PAUSED",
"name": "ready-to-paused",
"value": "2"
},
{
"desc": "Fail state change from PAUSED to PLAYING",
"name": "paused-to-playing",
"value": "3"
},
{
"desc": "Fail state change from PLAYING to PAUSED",
"name": "playing-to-paused",
"value": "4"
},
{
"desc": "Fail state change from PAUSED to READY",
"name": "paused-to-ready",
"value": "5"
},
{
"desc": "Fail state change from READY to NULL",
"name": "ready-to-null",
"value": "6"
}
]
}
},
"package": "GStreamer Bad Plug-ins",

View file

@ -43,11 +43,80 @@
#include <gst/audio/audio.h>
typedef enum
{
FAKE_SINK_STATE_ERROR_NONE = 0,
FAKE_SINK_STATE_ERROR_NULL_READY,
FAKE_SINK_STATE_ERROR_READY_PAUSED,
FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
FAKE_SINK_STATE_ERROR_PAUSED_READY,
FAKE_SINK_STATE_ERROR_READY_NULL
} GstFakeSinkStateError;
#define DEFAULT_DROP_OUT_OF_SEGMENT TRUE
#define DEFAULT_STATE_ERROR FAKE_SINK_STATE_ERROR_NONE
#define DEFAULT_SILENT TRUE
#define DEFAULT_DUMP FALSE
#define DEFAULT_SIGNAL_HANDOFFS FALSE
#define DEFAULT_LAST_MESSAGE NULL
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
#define DEFAULT_CAN_ACTIVATE_PULL FALSE
#define DEFAULT_NUM_BUFFERS -1
/**
* GstFakeAudioSinkStateError:
*
* Proxy for GstFakeSinkError.
*
* Since: 1.22
*/
#define GST_TYPE_FAKE_AUDIO_SINK_STATE_ERROR (gst_fake_audio_sink_state_error_get_type())
static GType
gst_fake_audio_sink_state_error_get_type (void)
{
static GType fakeaudiosink_state_error_type = 0;
static const GEnumValue fakeaudiosink_state_error[] = {
{FAKE_SINK_STATE_ERROR_NONE, "No state change errors", "none"},
{FAKE_SINK_STATE_ERROR_NULL_READY,
"Fail state change from NULL to READY", "null-to-ready"},
{FAKE_SINK_STATE_ERROR_READY_PAUSED,
"Fail state change from READY to PAUSED", "ready-to-paused"},
{FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
"Fail state change from PAUSED to PLAYING", "paused-to-playing"},
{FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
"Fail state change from PLAYING to PAUSED", "playing-to-paused"},
{FAKE_SINK_STATE_ERROR_PAUSED_READY,
"Fail state change from PAUSED to READY", "paused-to-ready"},
{FAKE_SINK_STATE_ERROR_READY_NULL,
"Fail state change from READY to NULL", "ready-to-null"},
{0, NULL, NULL},
};
if (!fakeaudiosink_state_error_type) {
fakeaudiosink_state_error_type =
g_enum_register_static ("GstFakeAudioSinkStateError",
fakeaudiosink_state_error);
}
return fakeaudiosink_state_error_type;
}
enum
{
PROP_0,
PROP_VOLUME,
PROP_MUTE,
PROP_STATE_ERROR,
PROP_SILENT,
PROP_DUMP,
PROP_SIGNAL_HANDOFFS,
PROP_DROP_OUT_OF_SEGMENT,
PROP_LAST_MESSAGE,
PROP_CAN_ACTIVATE_PUSH,
PROP_CAN_ACTIVATE_PULL,
PROP_NUM_BUFFERS,
PROP_LAST
};
@ -60,28 +129,19 @@ enum
static guint gst_fake_audio_sink_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *pspec_last_message = NULL;
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL)));
G_DEFINE_TYPE_WITH_CODE (GstFakeAudioSink, gst_fake_audio_sink, GST_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL););
G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL);
);
GST_ELEMENT_REGISTER_DEFINE (fakeaudiosink, "fakeaudiosink",
GST_RANK_NONE, gst_fake_audio_sink_get_type ());
static void
gst_fake_audio_sink_proxy_properties (GstFakeAudioSink * self,
GstElement * child)
{
static gsize initialized = 0;
if (g_once_init_enter (&initialized)) {
gst_fake_sink_proxy_properties (GST_ELEMENT_CAST (self), child, PROP_LAST);
g_once_init_leave (&initialized, 1);
}
}
static void
gst_fake_audio_sink_proxy_handoff (GstElement * element, GstBuffer * buffer,
GstPad * pad, GstFakeAudioSink * self)
@ -98,6 +158,12 @@ gst_fake_audio_sink_proxy_preroll_handoff (GstElement * element,
buffer, self->sinkpad);
}
static void
gst_fake_audio_sink_proxy_last_message (GstElement * element)
{
g_object_notify_by_pspec ((GObject *) element, pspec_last_message);
}
static void
gst_fake_audio_sink_init (GstFakeAudioSink * self)
{
@ -126,7 +192,8 @@ gst_fake_audio_sink_init (GstFakeAudioSink * self)
self->child = child;
gst_fake_audio_sink_proxy_properties (self, child);
g_signal_connect (child, "notify::last-message",
G_CALLBACK (gst_fake_audio_sink_proxy_last_message), self);
g_signal_connect (child, "handoff",
G_CALLBACK (gst_fake_audio_sink_proxy_handoff), self);
g_signal_connect (child, "preroll-handoff",
@ -180,6 +247,7 @@ gst_fake_audio_sink_class_init (GstFakeAudioSinkClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GObjectClass *base_sink_class;
object_class->get_property = gst_fake_audio_sink_get_property;
object_class->set_property = gst_fake_audio_sink_set_property;
@ -241,8 +309,56 @@ gst_fake_audio_sink_class_init (GstFakeAudioSinkClass * klass)
preroll_handoff), NULL, NULL, NULL, G_TYPE_NONE, 2,
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
g_object_class_install_property (object_class, PROP_STATE_ERROR,
g_param_spec_enum ("state-error", "State Error",
"Generate a state change error", GST_TYPE_FAKE_AUDIO_SINK_STATE_ERROR,
DEFAULT_STATE_ERROR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
pspec_last_message = g_param_spec_string ("last-message", "Last Message",
"The message describing current status", DEFAULT_LAST_MESSAGE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_LAST_MESSAGE,
pspec_last_message);
g_object_class_install_property (object_class, PROP_SIGNAL_HANDOFFS,
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
"Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_DROP_OUT_OF_SEGMENT,
g_param_spec_boolean ("drop-out-of-segment",
"Drop out-of-segment buffers",
"Drop and don't render / hand off out-of-segment buffers",
DEFAULT_DROP_OUT_OF_SEGMENT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_SILENT,
g_param_spec_boolean ("silent", "Silent",
"Don't produce last_message events", DEFAULT_SILENT,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump buffer contents to stdout",
DEFAULT_DUMP,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PUSH,
g_param_spec_boolean ("can-activate-push", "Can activate push",
"Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PULL,
g_param_spec_boolean ("can-activate-pull", "Can activate pull",
"Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_NUM_BUFFERS,
g_param_spec_int ("num-buffers", "num-buffers",
"Number of buffers to accept going EOS", -1, G_MAXINT,
DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
base_sink_class = g_type_class_ref (GST_TYPE_BASE_SINK);
gst_util_proxy_class_properties (object_class, base_sink_class, PROP_LAST);
g_type_class_unref (base_sink_class);
gst_element_class_add_static_pad_template (element_class, &sink_factory);
gst_element_class_set_static_metadata (element_class, "Fake Audio Sink",
"Audio/Sink", "Fake audio renderer",
"Philippe Normand <philn@igalia.com>");
gst_type_mark_as_plugin_api (GST_TYPE_FAKE_AUDIO_SINK_STATE_ERROR, 0);
}

View file

@ -24,22 +24,20 @@
/* TODO complete the types */
void
gst_fake_sink_proxy_properties (GstElement * self,
GstElement * child, guint property_id_offset)
gst_util_proxy_class_properties (GObjectClass * object_class,
GObjectClass * target_class, guint property_id_offset)
{
GObjectClass *object_class;
GParamSpec **properties;
guint n_properties, i;
object_class = G_OBJECT_CLASS (GST_ELEMENT_GET_CLASS (self));
properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (child),
properties = g_object_class_list_properties (G_OBJECT_CLASS (target_class),
&n_properties);
for (i = 0; i < n_properties; i++) {
guint property_id = i + property_id_offset;
if (properties[i]->owner_type != G_OBJECT_TYPE (child) &&
properties[i]->owner_type != GST_TYPE_BASE_SINK)
if (properties[i]->owner_type == G_TYPE_OBJECT
|| properties[i]->owner_type == GST_TYPE_OBJECT)
continue;
if (G_IS_PARAM_SPEC_BOOLEAN (properties[i])) {

View file

@ -26,7 +26,10 @@
G_BEGIN_DECLS
void gst_fake_sink_proxy_properties (GstElement * self, GstElement * child, guint property_id_offset);
void
gst_util_proxy_class_properties (GObjectClass *object_class,
GObjectClass *target_class,
guint property_id_offset);
G_END_DECLS

View file

@ -70,10 +70,78 @@ gst_fake_video_sink_allocation_meta_flags_get_type (void)
return id;
}
typedef enum
{
FAKE_SINK_STATE_ERROR_NONE = 0,
FAKE_SINK_STATE_ERROR_NULL_READY,
FAKE_SINK_STATE_ERROR_READY_PAUSED,
FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
FAKE_SINK_STATE_ERROR_PAUSED_READY,
FAKE_SINK_STATE_ERROR_READY_NULL
} GstFakeSinkStateError;
#define DEFAULT_DROP_OUT_OF_SEGMENT TRUE
#define DEFAULT_STATE_ERROR FAKE_SINK_STATE_ERROR_NONE
#define DEFAULT_SILENT TRUE
#define DEFAULT_DUMP FALSE
#define DEFAULT_SIGNAL_HANDOFFS FALSE
#define DEFAULT_LAST_MESSAGE NULL
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
#define DEFAULT_CAN_ACTIVATE_PULL FALSE
#define DEFAULT_NUM_BUFFERS -1
/**
* GstFakeVideoSinkStateError:
*
* Proxy for GstFakeSinkError.
*
* Since: 1.22
*/
#define GST_TYPE_FAKE_VIDEO_SINK_STATE_ERROR (gst_fake_video_sink_state_error_get_type())
static GType
gst_fake_video_sink_state_error_get_type (void)
{
static GType fakevideosink_state_error_type = 0;
static const GEnumValue fakevideosink_state_error[] = {
{FAKE_SINK_STATE_ERROR_NONE, "No state change errors", "none"},
{FAKE_SINK_STATE_ERROR_NULL_READY,
"Fail state change from NULL to READY", "null-to-ready"},
{FAKE_SINK_STATE_ERROR_READY_PAUSED,
"Fail state change from READY to PAUSED", "ready-to-paused"},
{FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
"Fail state change from PAUSED to PLAYING", "paused-to-playing"},
{FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
"Fail state change from PLAYING to PAUSED", "playing-to-paused"},
{FAKE_SINK_STATE_ERROR_PAUSED_READY,
"Fail state change from PAUSED to READY", "paused-to-ready"},
{FAKE_SINK_STATE_ERROR_READY_NULL,
"Fail state change from READY to NULL", "ready-to-null"},
{0, NULL, NULL},
};
if (!fakevideosink_state_error_type) {
fakevideosink_state_error_type =
g_enum_register_static ("GstFakeVideoSinkStateError",
fakevideosink_state_error);
}
return fakevideosink_state_error_type;
}
enum
{
PROP_0,
PROP_ALLOCATION_META_FLAGS,
PROP_STATE_ERROR,
PROP_SILENT,
PROP_DUMP,
PROP_SIGNAL_HANDOFFS,
PROP_DROP_OUT_OF_SEGMENT,
PROP_LAST_MESSAGE,
PROP_CAN_ACTIVATE_PUSH,
PROP_CAN_ACTIVATE_PULL,
PROP_NUM_BUFFERS,
PROP_LAST
};
@ -86,6 +154,8 @@ enum
static guint gst_fake_video_sink_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *pspec_last_message = NULL;
#define ALLOCATION_META_DEFAULT_FLAGS GST_ALLOCATION_FLAG_CROP_META | GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
@ -136,18 +206,6 @@ gst_fake_video_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
return TRUE;
}
static void
gst_fake_video_sink_proxy_properties (GstFakeVideoSink * self,
GstElement * child)
{
static gsize initialized = 0;
if (g_once_init_enter (&initialized)) {
gst_fake_sink_proxy_properties (GST_ELEMENT_CAST (self), child, PROP_LAST);
g_once_init_leave (&initialized, 1);
}
}
static void
gst_fake_video_sink_proxy_handoff (GstElement * element, GstBuffer * buffer,
GstPad * pad, GstFakeVideoSink * self)
@ -156,6 +214,12 @@ gst_fake_video_sink_proxy_handoff (GstElement * element, GstBuffer * buffer,
buffer, self->sinkpad);
}
static void
gst_fake_video_sink_proxy_last_message (GstElement * element)
{
g_object_notify_by_pspec ((GObject *) element, pspec_last_message);
}
static void
gst_fake_video_sink_proxy_preroll_handoff (GstElement * element,
GstBuffer * buffer, GstPad * pad, GstFakeVideoSink * self)
@ -195,7 +259,8 @@ gst_fake_video_sink_init (GstFakeVideoSink * self)
self->child = child;
gst_fake_video_sink_proxy_properties (self, child);
g_signal_connect (child, "notify::last-message",
G_CALLBACK (gst_fake_video_sink_proxy_last_message), self);
g_signal_connect (child, "handoff",
G_CALLBACK (gst_fake_video_sink_proxy_handoff), self);
g_signal_connect (child, "preroll-handoff",
@ -247,6 +312,7 @@ gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GObjectClass *base_sink_class;
object_class->get_property = gst_fake_video_sink_get_property;
object_class->set_property = gst_fake_video_sink_set_property;
@ -270,7 +336,6 @@ gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
ALLOCATION_META_DEFAULT_FLAGS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstFakeVideoSink::handoff:
* @fakevideosink: the fakevideosink instance
@ -303,6 +368,53 @@ gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
preroll_handoff), NULL, NULL, NULL, G_TYPE_NONE, 2,
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
g_object_class_install_property (object_class, PROP_STATE_ERROR,
g_param_spec_enum ("state-error", "State Error",
"Generate a state change error", GST_TYPE_FAKE_VIDEO_SINK_STATE_ERROR,
DEFAULT_STATE_ERROR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
pspec_last_message = g_param_spec_string ("last-message", "Last Message",
"The message describing current status", DEFAULT_LAST_MESSAGE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_LAST_MESSAGE,
pspec_last_message);
g_object_class_install_property (object_class, PROP_SIGNAL_HANDOFFS,
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
"Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_DROP_OUT_OF_SEGMENT,
g_param_spec_boolean ("drop-out-of-segment",
"Drop out-of-segment buffers",
"Drop and don't render / hand off out-of-segment buffers",
DEFAULT_DROP_OUT_OF_SEGMENT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_SILENT,
g_param_spec_boolean ("silent", "Silent",
"Don't produce last_message events", DEFAULT_SILENT,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump buffer contents to stdout",
DEFAULT_DUMP,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PUSH,
g_param_spec_boolean ("can-activate-push", "Can activate push",
"Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PULL,
g_param_spec_boolean ("can-activate-pull", "Can activate pull",
"Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_NUM_BUFFERS,
g_param_spec_int ("num-buffers", "num-buffers",
"Number of buffers to accept going EOS", -1, G_MAXINT,
DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
base_sink_class = g_type_class_ref (GST_TYPE_BASE_SINK);
gst_util_proxy_class_properties (object_class, base_sink_class, PROP_LAST);
g_type_class_unref (base_sink_class);
gst_type_mark_as_plugin_api (GST_TYPE_FAKE_VIDEO_SINK_ALLOCATION_META_FLAGS,
0);
gst_type_mark_as_plugin_api (GST_TYPE_FAKE_VIDEO_SINK_STATE_ERROR, 0);
}