autoconvert: Support installing identity as the initial child

Add the 'initial-identity' property, which inserts identity for
at startup for event passing, and replaces it with a new child
when the first buffer (and caps) actually arrives.

https://bugzilla.gnome.org/show_bug.cgi?id=599469
This commit is contained in:
Jan Schmidt 2009-10-24 12:38:14 +01:00
parent 55a3f6a08c
commit 32ebb79f0b
2 changed files with 128 additions and 62 deletions

View file

@ -45,6 +45,8 @@
GST_DEBUG_CATEGORY (autoconvert_debug);
#define GST_CAT_DEFAULT (autoconvert_debug)
#define DEFAULT_INITIAL_IDENTITY FALSE
#define GST_AUTOCONVERT_LOCK(ac) GST_OBJECT_LOCK (ac)
#define GST_AUTOCONVERT_UNLOCK(ac) GST_OBJECT_UNLOCK (ac)
@ -81,7 +83,8 @@ enum
enum
{
PROP_0,
PROP_FACTORIES
PROP_FACTORIES,
PROP_INITIAL_IDENTITY
};
static void gst_auto_convert_set_property (GObject * object,
@ -94,7 +97,7 @@ static GstStateChangeReturn gst_auto_convert_change_state (GstElement * element,
GstStateChange transition);
static GstElement *gst_auto_convert_get_subelement (GstAutoConvert *
autoconvert);
autoconvert, gboolean query_only);
static GstPad *gst_auto_convert_get_internal_sinkpad (GstAutoConvert *
autoconvert);
static GstPad *gst_auto_convert_get_internal_srcpad (GstAutoConvert *
@ -137,6 +140,11 @@ static const GstQueryType *gst_auto_convert_internal_src_query_type (GstPad *
pad);
static GList *gst_auto_convert_load_factories (GstAutoConvert * autoconvert);
static GstElement
* gst_auto_convert_get_or_make_element_from_factory (GstAutoConvert *
autoconvert, GstElementFactory * factory);
static gboolean gst_auto_convert_activate_element (GstAutoConvert * autoconvert,
GstElement * element, GstCaps * caps);
static GQuark internal_srcpad_quark = 0;
static GQuark internal_sinkpad_quark = 0;
@ -191,6 +199,13 @@ gst_auto_convert_class_init (GstAutoConvertClass * klass)
" elements), can only be set once",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_INITIAL_IDENTITY,
g_param_spec_boolean ("initial-identity",
"Install identity initially",
"If true, then the identity element will be installed initially "
"and used for event passing until the first data buffer arrives ",
DEFAULT_INITIAL_IDENTITY, G_PARAM_READWRITE));
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_auto_convert_change_state);
}
@ -229,6 +244,8 @@ gst_auto_convert_init (GstAutoConvert * autoconvert,
gst_element_add_pad (GST_ELEMENT (autoconvert), autoconvert->srcpad);
gst_segment_init (&autoconvert->sink_segment, GST_FORMAT_UNDEFINED);
autoconvert->initial_identity = DEFAULT_INITIAL_IDENTITY;
}
static void
@ -279,6 +296,11 @@ gst_auto_convert_set_property (GObject * object,
" have been set or auto-discovered");
GST_AUTOCONVERT_UNLOCK (autoconvert);
break;
case PROP_INITIAL_IDENTITY:
GST_AUTOCONVERT_LOCK (autoconvert);
autoconvert->initial_identity = g_value_get_boolean (value);
GST_AUTOCONVERT_UNLOCK (autoconvert);
break;
}
}
@ -297,6 +319,11 @@ gst_auto_convert_get_property (GObject * object,
g_value_set_pointer (value, &autoconvert->factories);
GST_AUTOCONVERT_UNLOCK (autoconvert);
break;
case PROP_INITIAL_IDENTITY:
GST_AUTOCONVERT_LOCK (autoconvert);
g_value_set_boolean (value, autoconvert->initial_identity);
GST_AUTOCONVERT_UNLOCK (autoconvert);
break;
}
}
@ -440,15 +467,41 @@ get_pad_by_direction (GstElement * element, GstPadDirection direction)
}
static GstElement *
gst_auto_convert_get_subelement (GstAutoConvert * autoconvert)
gst_auto_convert_get_subelement (GstAutoConvert * autoconvert,
gboolean query_only)
{
GstElement *element = NULL;
gboolean initial_identity;
GST_AUTOCONVERT_LOCK (autoconvert);
if (autoconvert->current_subelement)
element = gst_object_ref (autoconvert->current_subelement);
initial_identity = autoconvert->initial_identity;
GST_AUTOCONVERT_UNLOCK (autoconvert);
if (G_UNLIKELY (!query_only && element == NULL && initial_identity)) {
/* No current sub-element - create an identity and install it */
GstElementFactory *identity_feature;
GstElement *identity;
GST_INFO_OBJECT (autoconvert,
"No existing child element - instantiating identity");
/* if the identity feature doesn't exist - something is very wrong */
identity_feature =
GST_ELEMENT_FACTORY_CAST (gst_default_registry_find_feature ("identity",
GST_TYPE_ELEMENT_FACTORY));
identity =
gst_auto_convert_get_or_make_element_from_factory (autoconvert,
identity_feature);
if (identity
&& gst_auto_convert_activate_element (autoconvert, identity, NULL)) {
GST_AUTOCONVERT_LOCK (autoconvert);
if (autoconvert->current_subelement)
element = gst_object_ref (autoconvert->current_subelement);
GST_AUTOCONVERT_UNLOCK (autoconvert);
}
}
return element;
}
@ -509,8 +562,6 @@ gst_auto_convert_add_element (GstAutoConvert * autoconvert,
return NULL;
}
gst_object_ref (element);
srcpad = get_pad_by_direction (element, GST_PAD_SRC);
if (!srcpad) {
GST_ERROR_OBJECT (autoconvert, "Could not find source in %s",
@ -595,11 +646,13 @@ gst_auto_convert_add_element (GstAutoConvert * autoconvert,
/* Iffy */
gst_element_sync_state_with_parent (element);
/* Increment the reference count we will return to the caller */
gst_object_ref (element);
return element;
error:
gst_bin_remove (GST_BIN (autoconvert), element);
gst_object_unref (element);
return NULL;
}
@ -686,6 +739,52 @@ factory_can_intersect (GstAutoConvert * autoconvert,
return ret;
}
static gboolean
gst_auto_convert_activate_element (GstAutoConvert * autoconvert,
GstElement * element, GstCaps * caps)
{
GstPad *internal_srcpad = g_object_get_qdata (G_OBJECT (element),
internal_srcpad_quark);
GstPad *internal_sinkpad = g_object_get_qdata (G_OBJECT (element),
internal_sinkpad_quark);
if (caps) {
/* check if the element can really accept said caps */
if (!gst_pad_peer_accept_caps (internal_srcpad, caps)) {
GST_DEBUG_OBJECT (autoconvert, "Could not set %s:%s to %"
GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (internal_srcpad), caps);
return FALSE;
}
}
gst_pad_set_fixatecaps_function (autoconvert->sinkpad,
gst_auto_convert_sink_fixatecaps);
GST_AUTOCONVERT_LOCK (autoconvert);
autoconvert->current_subelement = element;
autoconvert->current_internal_srcpad = internal_srcpad;
autoconvert->current_internal_sinkpad = internal_sinkpad;
GST_AUTOCONVERT_UNLOCK (autoconvert);
GST_INFO_OBJECT (autoconvert,
"Selected element %s",
GST_OBJECT_NAME (GST_OBJECT (autoconvert->current_subelement)));
/* Send new-segment event if we have one */
if (autoconvert->sink_segment.format != GST_FORMAT_UNDEFINED) {
GstEvent *event;
GstSegment *seg = &autoconvert->sink_segment;
event = gst_event_new_new_segment_full (TRUE,
seg->rate, seg->applied_rate, seg->format, seg->start,
seg->stop, seg->time);
autoconvert->drop_newseg = TRUE;
gst_pad_push_event (internal_srcpad, event);
autoconvert->drop_newseg = FALSE;
}
return TRUE;
}
/*
* If there is already an internal element, it will try to call set_caps on it
*
@ -706,7 +805,7 @@ gst_auto_convert_sink_setcaps (GstPad * pad, GstCaps * caps)
g_return_val_if_fail (autoconvert != NULL, FALSE);
subelement = gst_auto_convert_get_subelement (autoconvert);
subelement = gst_auto_convert_get_subelement (autoconvert, TRUE);
if (subelement) {
if (gst_pad_peer_accept_caps (autoconvert->current_internal_srcpad, caps)) {
/* If we can set the new caps on the current element,
@ -750,8 +849,6 @@ gst_auto_convert_sink_setcaps (GstPad * pad, GstCaps * caps)
for (elem = factories; elem; elem = g_list_next (elem)) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (elem->data);
GstElement *element;
GstPad *internal_srcpad = NULL;
GstPad *internal_sinkpad = NULL;
/* Lets first check if according to the static pad templates on the factory
* these caps have any chance of success
@ -774,55 +871,15 @@ gst_auto_convert_sink_setcaps (GstPad * pad, GstCaps * caps)
}
/* The element had a chance of success, lets make it */
element =
gst_auto_convert_get_or_make_element_from_factory (autoconvert,
factory);
if (!element) {
if (!element)
continue;
}
internal_srcpad = g_object_get_qdata (G_OBJECT (element),
internal_srcpad_quark);
internal_sinkpad = g_object_get_qdata (G_OBJECT (element),
internal_sinkpad_quark);
/* Now we check if the element can really accept said caps */
if (!gst_pad_peer_accept_caps (internal_srcpad, caps)) {
GST_DEBUG_OBJECT (autoconvert, "Could not set %s:%s to %" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (internal_srcpad), caps);
goto next_element;
}
gst_pad_set_fixatecaps_function (autoconvert->sinkpad,
gst_auto_convert_sink_fixatecaps);
GST_AUTOCONVERT_LOCK (autoconvert);
autoconvert->current_subelement = element;
autoconvert->current_internal_srcpad = internal_srcpad;
autoconvert->current_internal_sinkpad = internal_sinkpad;
GST_AUTOCONVERT_UNLOCK (autoconvert);
/* Send new-segment event if we have one */
if (autoconvert->sink_segment.format != GST_FORMAT_UNDEFINED) {
GstEvent *event;
GstSegment *seg = &autoconvert->sink_segment;
event = gst_event_new_new_segment_full (TRUE,
seg->rate, seg->applied_rate, seg->format, seg->start,
seg->stop, seg->time);
autoconvert->drop_newseg = TRUE;
gst_pad_push_event (internal_srcpad, event);
autoconvert->drop_newseg = FALSE;
}
GST_INFO_OBJECT (autoconvert,
"Selected element %s",
GST_OBJECT_NAME (GST_OBJECT (autoconvert->current_subelement)));
break;
next_element:
continue;
/* And make it the current child */
if (gst_auto_convert_activate_element (autoconvert, element, caps))
break;
}
get_out:
@ -979,7 +1036,7 @@ gst_auto_convert_sink_chain (GstPad * pad, GstBuffer * buffer)
ret = gst_pad_push (internal_srcpad, buffer);
gst_object_unref (internal_srcpad);
if (GST_FLOW_IS_FATAL (ret)) {
GstElement *child = gst_auto_convert_get_subelement (autoconvert);
GstElement *child = gst_auto_convert_get_subelement (autoconvert, TRUE);
GST_DEBUG_OBJECT (autoconvert,
"Child element %" GST_PTR_FORMAT "returned flow %s", child,
gst_flow_get_name (ret));
@ -1024,6 +1081,15 @@ gst_auto_convert_sink_event (GstPad * pad, GstEvent * event)
}
internal_srcpad = gst_auto_convert_get_internal_srcpad (autoconvert);
if (internal_srcpad == NULL) {
/* Query the subelement - triggers creation of an identity if necessary */
GstElement *subelement =
gst_auto_convert_get_subelement (autoconvert, FALSE);
if (subelement)
gst_object_unref (subelement);
internal_srcpad = gst_auto_convert_get_internal_srcpad (autoconvert);
}
if (internal_srcpad) {
ret = gst_pad_push_event (internal_srcpad, event);
gst_object_unref (internal_srcpad);
@ -1063,7 +1129,7 @@ gst_auto_convert_sink_query (GstPad * pad, GstQuery * query)
GstAutoConvert *autoconvert = GST_AUTO_CONVERT (gst_pad_get_parent (pad));
GstElement *subelement;
subelement = gst_auto_convert_get_subelement (autoconvert);
subelement = gst_auto_convert_get_subelement (autoconvert, TRUE);
if (subelement) {
GstPad *sub_sinkpad = get_pad_by_direction (subelement, GST_PAD_SINK);
@ -1090,7 +1156,7 @@ gst_auto_convert_sink_query_type (GstPad * pad)
GstAutoConvert *autoconvert = GST_AUTO_CONVERT (gst_pad_get_parent (pad));
GstElement *subelement;
subelement = gst_auto_convert_get_subelement (autoconvert);
subelement = gst_auto_convert_get_subelement (autoconvert, TRUE);
if (subelement) {
GstPad *sub_sinkpad = get_pad_by_direction (subelement, GST_PAD_SINK);
@ -1113,7 +1179,7 @@ gst_auto_convert_sink_fixatecaps (GstPad * pad, GstCaps * caps)
GstAutoConvert *autoconvert = GST_AUTO_CONVERT (gst_pad_get_parent (pad));
GstElement *subelement;
subelement = gst_auto_convert_get_subelement (autoconvert);
subelement = gst_auto_convert_get_subelement (autoconvert, TRUE);
if (subelement) {
GstPad *sinkpad = get_pad_by_direction (subelement, GST_PAD_SINK);
gst_pad_fixate_caps (sinkpad, caps);
@ -1187,10 +1253,8 @@ gst_auto_convert_sink_getcaps (GstPad * pad)
element =
gst_auto_convert_get_or_make_element_from_factory (autoconvert,
factory);
if (!element) {
if (!element)
continue;
}
internal_srcpad = g_object_get_qdata (G_OBJECT (element),
internal_srcpad_quark);
@ -1297,7 +1361,7 @@ gst_auto_convert_src_query (GstPad * pad, GstQuery * query)
GstAutoConvert *autoconvert = GST_AUTO_CONVERT (gst_pad_get_parent (pad));
GstElement *subelement;
subelement = gst_auto_convert_get_subelement (autoconvert);
subelement = gst_auto_convert_get_subelement (autoconvert, TRUE);
if (subelement) {
GstPad *sub_srcpad = get_pad_by_direction (subelement, GST_PAD_SRC);
@ -1324,7 +1388,7 @@ gst_auto_convert_src_query_type (GstPad * pad)
GstAutoConvert *autoconvert = GST_AUTO_CONVERT (gst_pad_get_parent (pad));
GstElement *subelement;
subelement = gst_auto_convert_get_subelement (autoconvert);
subelement = gst_auto_convert_get_subelement (autoconvert, TRUE);
if (subelement) {
GstPad *sub_srcpad = get_pad_by_direction (subelement, GST_PAD_SRC);

View file

@ -56,6 +56,8 @@ struct _GstAutoConvert
GList *cached_events;
GstSegment sink_segment;
gboolean drop_newseg;
gboolean initial_identity;
};
struct _GstAutoConvertClass