Commit d8e49cf6 authored by Seungha Yang's avatar Seungha Yang 🐑

message: Add NEED_CONTEXT_ALL message type

GstElement can store multiple persistent context even if they are
all identical type. But GstBin will response the very first context
from NEED_CONTEXT message. This NEED_CONTEXT_ALL message will be used
for requesting all available specific contexts.
parent b50abd9f
Pipeline #52411 passed with stages
in 51 minutes and 22 seconds
......@@ -4004,9 +4004,12 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
break;
}
case GST_MESSAGE_NEED_CONTEXT:{
case GST_MESSAGE_NEED_CONTEXT:
case GST_MESSAGE_NEED_CONTEXT_ALL:
{
const gchar *context_type;
GList *l, *contexts;
gboolean find_all = (type == GST_MESSAGE_NEED_CONTEXT_ALL);
gst_message_parse_context_type (message, &context_type);
GST_OBJECT_LOCK (bin);
......@@ -4018,12 +4021,14 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
if (strcmp (context_type, tmp_type) == 0) {
gst_element_set_context (GST_ELEMENT (src), l->data);
break;
if (!find_all)
break;
}
}
GST_OBJECT_UNLOCK (bin);
/* Forward if we couldn't answer the message */
/* Forward if we couldn't answer the message or
* in case of GST_MESSAGE_NEED_CONTEXT_ALL */
if (l == NULL) {
goto forward;
} else {
......
......@@ -41,12 +41,14 @@
* 1. Check if the element already has a context
* 2. Query downstream with GST_QUERY_CONTEXT for the context
* 3. Query upstream with GST_QUERY_CONTEXT for the context
* 4. Post a GST_MESSAGE_NEED_CONTEXT message on the bus with the required
* 4. Post a GST_MESSAGE_NEED_CONTEXT or GST_MESSAGE_NEED_CONTEXT_ALL
* message on the bus with the required
* context types and afterwards check if a usable context was set now
* 5. Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT message
* on the bus.
*
* Bins will catch GST_MESSAGE_NEED_CONTEXT messages and will set any previously
* Bins will catch GST_MESSAGE_NEED_CONTEXT and GST_MESSAGE_NEED_CONTEXT_ALL
* messages and will set any previously
* known context on the element that asks for it if possible. Otherwise the
* application should provide one if it can.
*
......
......@@ -104,6 +104,7 @@ static GstMessageQuarks message_quarks[] = {
{GST_MESSAGE_RESET_TIME, "reset-time", 0},
{GST_MESSAGE_STREAM_START, "stream-start", 0},
{GST_MESSAGE_NEED_CONTEXT, "need-context", 0},
{GST_MESSAGE_NEED_CONTEXT_ALL, "need-context-all", 0},
{GST_MESSAGE_HAVE_CONTEXT, "have-context", 0},
{GST_MESSAGE_DEVICE_ADDED, "device-added", 0},
{GST_MESSAGE_DEVICE_REMOVED, "device-removed", 0},
......@@ -2508,7 +2509,7 @@ gst_message_new_need_context (GstObject * src, const gchar * context_type)
/**
* gst_message_parse_context_type:
* @message: a GST_MESSAGE_NEED_CONTEXT type message
* @message: a GST_MESSAGE_NEED_CONTEXT or GST_MESSAGE_NEED_CONTEXT_ALL type message
* @context_type: (out) (transfer none) (allow-none): the context type, or %NULL
*
* Parse a context type from an existing GST_MESSAGE_NEED_CONTEXT message.
......@@ -2524,8 +2525,8 @@ gst_message_parse_context_type (GstMessage * message,
GstStructure *structure;
const GValue *value;
g_return_val_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT,
FALSE);
g_return_val_if_fail ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT)
|| (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT_ALL), FALSE);
structure = GST_MESSAGE_STRUCTURE (message);
......@@ -2537,6 +2538,35 @@ gst_message_parse_context_type (GstMessage * message,
return TRUE;
}
/**
* gst_message_new_need_context_all:
* @src: (transfer none) (allow-none): The object originating the message.
* @context_type: The context type that is needed
*
* This message is posted when an element needs all specific #GstContext.
*
* Returns: (transfer full): The new need-context-all message.
*
* MT safe.
*
* Since: 1.18
*/
GstMessage *
gst_message_new_need_context_all (GstObject * src, const gchar * context_type)
{
GstMessage *message;
GstStructure *structure;
g_return_val_if_fail (context_type != NULL, NULL);
structure = gst_structure_new_id (GST_QUARK (MESSAGE_NEED_CONTEXT_ALL),
GST_QUARK (CONTEXT_TYPE), G_TYPE_STRING, context_type, NULL);
message =
gst_message_new_custom (GST_MESSAGE_NEED_CONTEXT_ALL, src, structure);
return message;
}
/**
* gst_message_new_have_context:
* @src: (transfer none) (allow-none): The object originating the message.
......
......@@ -121,6 +121,8 @@ typedef struct _GstMessage GstMessage;
* response is received with a non-HTTP URL inside. (Since: 1.10)
* @GST_MESSAGE_DEVICE_CHANGED: Message indicating a #GstDevice was changed
* a #GstDeviceProvider (Since: 1.16)
* @GST_MESSAGE_NEED_CONTEXT_ALL: Message indicating that an element wants
* all contexts having a specific context type (Since: 1.18)
* @GST_MESSAGE_ANY: mask for all of the above messages.
*
* The different message types that are available.
......@@ -174,6 +176,7 @@ typedef enum
GST_MESSAGE_STREAMS_SELECTED = GST_MESSAGE_EXTENDED + 5,
GST_MESSAGE_REDIRECT = GST_MESSAGE_EXTENDED + 6,
GST_MESSAGE_DEVICE_CHANGED = GST_MESSAGE_EXTENDED + 6,
GST_MESSAGE_NEED_CONTEXT_ALL = GST_MESSAGE_EXTENDED + 8,
GST_MESSAGE_ANY = (gint) (0xffffffff)
} GstMessageType;
......@@ -789,6 +792,11 @@ GstMessage * gst_message_new_need_context (GstObject * src, const gchar *
GST_API
gboolean gst_message_parse_context_type (GstMessage * message, const gchar ** context_type);
/* NEED_CONTEXT_ALL */
GST_API
GstMessage * gst_message_new_need_context_all (GstObject * src, const gchar * context_type) G_GNUC_MALLOC;
/* HAVE_CONTEXT */
GST_API
......
......@@ -77,6 +77,7 @@ static const gchar *_quark_strings[] = {
"redirect-entry-taglists", "redirect-entry-structures",
"GstEventStreamGroupDone", "GstQueryBitrate", "nominal-bitrate",
"GstMessageDeviceChanged", "device-changed", "trickmode-interval",
"GstMessageNeedContextAll"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
......@@ -222,7 +222,8 @@ typedef enum _GstQuarkId
GST_QUARK_MESSAGE_DEVICE_CHANGED = 191,
GST_QUARK_DEVICE_CHANGED = 192,
GST_QUARK_TRICKMODE_INTERVAL = 193,
GST_QUARK_MAX = 194
GST_QUARK_MESSAGE_NEED_CONTEXT_ALL = 194,
GST_QUARK_MAX = 195
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
......@@ -59,9 +59,12 @@ typedef struct
GstElement parent;
gboolean set_before_ready;
gboolean set_from_need_context;
gboolean set_from_need_context_all;
gboolean create_self;
gboolean have_foobar;
gboolean have_other_foobar[2];
gint foobar_id[3];
} GstContextElement;
typedef struct
......@@ -76,8 +79,28 @@ G_DEFINE_TYPE (GstContextElement, gst_context_element, GST_TYPE_ELEMENT);
static void
gst_context_element_set_context (GstElement * element, GstContext * context)
{
if (strcmp (gst_context_get_context_type (context), "foobar") == 0)
((GstContextElement *) element)->have_foobar = TRUE;
GstContextElement *self = (GstContextElement *) element;
if (strcmp (gst_context_get_context_type (context), "foobar") == 0) {
self->have_foobar = TRUE;
} else if (strcmp (gst_context_get_context_type (context), "foobar-all") == 0) {
const GstStructure *s;
gint id;
s = gst_context_get_structure (context);
fail_unless (gst_structure_get_int (s, "id", &id));
if (!self->have_foobar) {
self->have_foobar = TRUE;
self->foobar_id[0] = id;
} else if (!self->have_other_foobar[0]) {
self->have_other_foobar[0] = TRUE;
self->foobar_id[1] = id;
} else {
self->have_other_foobar[1] = TRUE;
self->foobar_id[2] = id;
}
}
GST_ELEMENT_CLASS (gst_context_element_parent_class)->set_context (element,
context);
......@@ -99,12 +122,20 @@ gst_context_element_change_state (GstElement * element,
else if (celement->set_before_ready)
goto chain_up;
if (celement->set_from_need_context && have_foobar)
if ((celement->set_from_need_context || celement->set_from_need_context_all)
&& have_foobar)
return GST_STATE_CHANGE_FAILURE;
if (!have_foobar) {
/* Here we would first query downstream for a context but we have no pads */
msg = gst_message_new_need_context (GST_OBJECT (element), "foobar");
if (celement->set_from_need_context_all) {
msg =
gst_message_new_need_context_all (GST_OBJECT (element),
"foobar-all");
} else {
msg = gst_message_new_need_context (GST_OBJECT (element), "foobar");
}
gst_element_post_message (element, msg);
have_foobar = celement->have_foobar;
......@@ -115,6 +146,14 @@ gst_context_element_change_state (GstElement * element,
else if (celement->set_from_need_context)
goto chain_up;
if (celement->set_from_need_context_all) {
if (!have_foobar || celement->have_other_foobar[0] != TRUE ||
celement->have_other_foobar[1] == TRUE)
return GST_STATE_CHANGE_FAILURE;
goto chain_up;
}
if (celement->create_self && have_foobar)
return GST_STATE_CHANGE_FAILURE;
......@@ -203,6 +242,22 @@ sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
context = gst_context_new ("foobar", FALSE);
gst_element_set_context (element, context);
gst_context_unref (context);
} else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT_ALL) {
const gchar *type;
GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message));
GstContext *context;
GstStructure *s;
gint i;
fail_unless (gst_message_parse_context_type (message, &type));
fail_unless_equals_string (type, "foobar-all");
for (i = 0; i < 2; i++) {
context = gst_context_new ("foobar-all", TRUE);
s = gst_context_writable_structure (context);
gst_structure_set (s, "id", G_TYPE_INT, i + 1, NULL);
gst_element_set_context (element, context);
gst_context_unref (context);
}
}
return GST_BUS_PASS;
......@@ -432,6 +487,46 @@ GST_START_TEST (test_add_element_to_bin_collision)
GST_END_TEST;
GST_START_TEST (test_need_context_all)
{
GstBus *bus;
GstElement *element;
GstMessage *msg;
element = g_object_new (gst_context_element_get_type (), NULL);
bus = gst_bus_new ();
gst_bus_set_sync_handler (bus, sync_handler, NULL, NULL);
gst_element_set_bus (element, bus);
((GstContextElement *) element)->set_from_need_context_all = TRUE;
fail_unless (gst_element_set_state (element,
GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS);
fail_unless ((msg =
gst_bus_pop_filtered (bus, GST_MESSAGE_NEED_CONTEXT_ALL)) != NULL);
gst_message_unref (msg);
fail_unless ((msg =
gst_bus_pop_filtered (bus, GST_MESSAGE_STATE_CHANGED)) != NULL);
gst_message_unref (msg);
fail_if (gst_bus_pop (bus) != NULL);
fail_unless (((GstContextElement *) element)->have_foobar);
fail_unless (((GstContextElement *) element)->have_other_foobar[0]);
fail_if (((GstContextElement *) element)->have_other_foobar[1]);
fail_unless (((GstContextElement *) element)->foobar_id[0] == 1);
fail_unless (((GstContextElement *) element)->foobar_id[1] == 2);
gst_element_set_bus (element, NULL);
fail_unless (gst_element_set_state (element,
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
gst_object_unref (bus);
gst_object_unref (element);
}
GST_END_TEST;
static Suite *
gst_context_suite (void)
{
......@@ -448,6 +543,7 @@ gst_context_suite (void)
tcase_add_test (tc_chain, test_element_bin_caching);
tcase_add_test (tc_chain, test_add_element_to_bin);
tcase_add_test (tc_chain, test_add_element_to_bin_collision);
tcase_add_test (tc_chain, test_need_context_all);
return s;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment