diff --git a/ChangeLog b/ChangeLog index 706ff46ae5..d0e88fe961 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2005-10-08 Wim Taymans + + * gst/gstmessage.c: (gst_message_new_custom), + (gst_message_new_eos), (gst_message_new_error), + (gst_message_new_warning), (gst_message_new_tag), + (gst_message_new_state_changed), (gst_message_new_clock_provide), + (gst_message_new_new_clock), (gst_message_new_segment_start), + (gst_message_new_segment_done), (gst_message_parse_state_changed), + (gst_message_parse_clock_provide), (gst_message_parse_new_clock): + * gst/gstmessage.h: + Clean up. + Added clock related messages. + + * gst/gstpipeline.c: (gst_pipeline_change_state): + Post message when the clock changed. + + * tools/gst-launch.c: (event_loop): + Print new clock. + 2005-10-08 Tim-Philipp Müller * tools/gst-inspect.c: (print_element_properties_info): diff --git a/gst/gstmessage.c b/gst/gstmessage.c index 41d1b7c75a..80e25cc12e 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -81,10 +81,13 @@ static GstMessageQuarks message_quarks[] = { {GST_MESSAGE_BUFFERING, "buffering", 0}, {GST_MESSAGE_STATE_CHANGED, "state-changed", 0}, {GST_MESSAGE_STEP_DONE, "step-done", 0}, + {GST_MESSAGE_CLOCK_PROVIDE, "clock-provide", 0}, + {GST_MESSAGE_CLOCK_LOST, "clock-lost", 0}, {GST_MESSAGE_NEW_CLOCK, "new-clock", 0}, {GST_MESSAGE_STRUCTURE_CHANGE, "structure-change", 0}, {GST_MESSAGE_STREAM_STATUS, "stream-status", 0}, {GST_MESSAGE_APPLICATION, "application", 0}, + {GST_MESSAGE_ELEMENT, "element", 0}, {GST_MESSAGE_SEGMENT_START, "segment-start", 0}, {GST_MESSAGE_SEGMENT_DONE, "segment-done", 0}, {0, NULL, 0} @@ -219,8 +222,24 @@ _gst_message_copy (GstMessage * message) return copy; } -static GstMessage * -gst_message_new (GstMessageType type, GstObject * src) +/** + * gst_message_new_custom: + * @type: The #GstMessageType to distinguish messages + * @src: The object originating the message. + * @structure: The structure for the message. The message will take ownership of + * the structure. + * + * Create a new custom-typed message. This can be used for anything not + * handled by other message-specific functions to pass a message to the + * app. The structure field can be NULL. + * + * Returns: The new message. + * + * MT safe. + */ +GstMessage * +gst_message_new_custom (GstMessageType type, GstObject * src, + GstStructure * structure) { GstMessage *message; @@ -237,7 +256,11 @@ gst_message_new (GstMessageType type, GstObject * src) message->src = NULL; GST_CAT_DEBUG (GST_CAT_MESSAGE, "NULL message source"); } - message->structure = NULL; + if (structure) { + gst_structure_set_parent_refcount (structure, + &message->mini_object.refcount); + } + message->structure = structure; return message; } @@ -259,7 +282,7 @@ gst_message_new_eos (GstObject * src) { GstMessage *message; - message = gst_message_new (GST_MESSAGE_EOS, src); + message = gst_message_new_custom (GST_MESSAGE_EOS, src, NULL); return message; } @@ -282,14 +305,10 @@ GstMessage * gst_message_new_error (GstObject * src, GError * error, gchar * debug) { GstMessage *message; - GstStructure *s; - message = gst_message_new (GST_MESSAGE_ERROR, src); - /* gst_structure_new takes copies of the types passed in */ - s = gst_structure_new ("GstMessageError", "gerror", GST_TYPE_G_ERROR, error, - "debug", G_TYPE_STRING, debug, NULL); - gst_structure_set_parent_refcount (s, &message->mini_object.refcount); - message->structure = s; + message = gst_message_new_custom (GST_MESSAGE_ERROR, src, + gst_structure_new ("GstMessageError", "gerror", GST_TYPE_G_ERROR, error, + "debug", G_TYPE_STRING, debug, NULL)); return message; } @@ -311,14 +330,10 @@ GstMessage * gst_message_new_warning (GstObject * src, GError * error, gchar * debug) { GstMessage *message; - GstStructure *s; - message = gst_message_new (GST_MESSAGE_WARNING, src); - /* gst_structure_new takes copies of the types passed in */ - s = gst_structure_new ("GstMessageWarning", "gerror", GST_TYPE_G_ERROR, error, - "debug", G_TYPE_STRING, debug, NULL); - gst_structure_set_parent_refcount (s, &message->mini_object.refcount); - message->structure = s; + message = gst_message_new_custom (GST_MESSAGE_WARNING, src, + gst_structure_new ("GstMessageWarning", "gerror", GST_TYPE_G_ERROR, error, + "debug", G_TYPE_STRING, debug, NULL)); return message; } @@ -342,9 +357,8 @@ gst_message_new_tag (GstObject * src, GstTagList * tag_list) g_return_val_if_fail (GST_IS_STRUCTURE (tag_list), NULL); - message = gst_message_new (GST_MESSAGE_TAG, src); - gst_structure_set_parent_refcount (tag_list, &message->mini_object.refcount); - message->structure = tag_list; + message = + gst_message_new_custom (GST_MESSAGE_TAG, src, (GstStructure *) tag_list); return message; } @@ -368,16 +382,64 @@ gst_message_new_state_changed (GstObject * src, GstState old, GstState new, GstState pending) { GstMessage *message; - GstStructure *s; - message = gst_message_new (GST_MESSAGE_STATE_CHANGED, src); + message = gst_message_new_custom (GST_MESSAGE_STATE_CHANGED, src, + gst_structure_new ("GstMessageState", + "old-state", GST_TYPE_STATE, (gint) old, + "new-state", GST_TYPE_STATE, (gint) new, + "pending-state", GST_TYPE_STATE, (gint) pending, NULL)); - s = gst_structure_new ("GstMessageState", - "old-state", GST_TYPE_STATE, (gint) old, - "new-state", GST_TYPE_STATE, (gint) new, - "pending-state", GST_TYPE_STATE, (gint) pending, NULL); - gst_structure_set_parent_refcount (s, &message->mini_object.refcount); - message->structure = s; + return message; +} + +/** + * gst_message_new_clock_provide: + * @src: The object originating the message. + * @ready: TRUE if the sender can provide a clock + * + * Create a clock provide message. This message is posted whenever an + * element is ready to provide a clock or lost its ability to provide + * a clock (maybe because it paused or became EOS). + * + * This message is mainly used internally to manage the clock + * selection. + * + * Returns: The new provide clock message. + * + * MT safe. + */ +GstMessage * +gst_message_new_clock_provide (GstObject * src, gboolean ready) +{ + GstMessage *message; + + message = gst_message_new_custom (GST_MESSAGE_CLOCK_PROVIDE, src, + gst_structure_new ("GstMessageClockProvide", + "ready", G_TYPE_BOOLEAN, ready, NULL)); + + return message; +} + +/** + * gst_message_new_new_clock: + * @src: The object originating the message. + * @clock: the new selected clock + * + * Create a new clock message. This message is posted whenever the + * pipeline selectes a new clock for the pipeline. + * + * Returns: The new new clock message. + * + * MT safe. + */ +GstMessage * +gst_message_new_new_clock (GstObject * src, GstClock * clock) +{ + GstMessage *message; + + message = gst_message_new_custom (GST_MESSAGE_NEW_CLOCK, src, + gst_structure_new ("GstMessageNewClock", + "clock", GST_TYPE_CLOCK, clock, NULL)); return message; } @@ -400,14 +462,10 @@ GstMessage * gst_message_new_segment_start (GstObject * src, GstClockTime timestamp) { GstMessage *message; - GstStructure *s; - message = gst_message_new (GST_MESSAGE_SEGMENT_START, src); - - s = gst_structure_new ("GstMessageSegmentStart", "timestamp", G_TYPE_INT64, - (gint64) timestamp, NULL); - gst_structure_set_parent_refcount (s, &message->mini_object.refcount); - message->structure = s; + message = gst_message_new_custom (GST_MESSAGE_SEGMENT_START, src, + gst_structure_new ("GstMessageSegmentStart", "timestamp", G_TYPE_INT64, + (gint64) timestamp, NULL)); return message; } @@ -430,14 +488,10 @@ GstMessage * gst_message_new_segment_done (GstObject * src, GstClockTime timestamp) { GstMessage *message; - GstStructure *s; - message = gst_message_new (GST_MESSAGE_SEGMENT_DONE, src); - - s = gst_structure_new ("GstMessageSegmentDone", "timestamp", G_TYPE_INT64, - (gint64) timestamp, NULL); - gst_structure_set_parent_refcount (s, &message->mini_object.refcount); - message->structure = s; + message = gst_message_new_custom (GST_MESSAGE_SEGMENT_DONE, src, + gst_structure_new ("GstMessageSegmentDone", "timestamp", G_TYPE_INT64, + (gint64) timestamp, NULL)); return message; } @@ -478,36 +532,6 @@ gst_message_new_element (GstObject * src, GstStructure * structure) return gst_message_new_custom (GST_MESSAGE_ELEMENT, src, structure); } -/** - * gst_message_new_custom: - * @type: The #GstMessageType to distinguish messages - * @src: The object originating the message. - * @structure: The structure for the message. The message will take ownership of - * the structure. - * - * Create a new custom-typed message. This can be used for anything not - * handled by other message-specific functions to pass a message to the - * app. The structure field can be NULL. - * - * Returns: The new message. - * - * MT safe. - */ -GstMessage * -gst_message_new_custom (GstMessageType type, GstObject * src, - GstStructure * structure) -{ - GstMessage *message; - - message = gst_message_new (type, src); - if (structure) { - gst_structure_set_parent_refcount (structure, - &message->mini_object.refcount); - message->structure = structure; - } - return message; -} - /** * gst_message_get_structure: * @message: The #GstMessage. @@ -575,6 +599,51 @@ gst_message_parse_state_changed (GstMessage * message, GstState * old, GST_TYPE_STATE, (gint *) pending); } +/** + * gst_message_parse_clock_provide: + * @message: A valid #GstMessage of type GST_MESSAGE_CLOCK_PROVIDE. + * @ready: If the src can provide a clock or not. + * + * Extracts the ready flag from the GstMessage. + * + * MT safe. + */ +void +gst_message_parse_clock_provide (GstMessage * message, gboolean * ready) +{ + g_return_if_fail (GST_IS_MESSAGE (message)); + g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_CLOCK_PROVIDE); + + if (ready) + gst_structure_get_boolean (message->structure, "ready", ready); +} + +/** + * gst_message_parse_new_clock: + * @message: A valid #GstMessage of type GST_MESSAGE_NEW_CLOCK. + * @clock: A pointer to hold the selected new clock + * + * Extracts the new clock from the GstMessage. + * The clock object returned remains valid until the message is freed. + * + * MT safe. + */ +void +gst_message_parse_new_clock (GstMessage * message, GstClock ** clock) +{ + const GValue *clock_gvalue; + + g_return_if_fail (GST_IS_MESSAGE (message)); + g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEW_CLOCK); + + clock_gvalue = gst_structure_get_value (message->structure, "clock"); + g_return_if_fail (clock_gvalue != NULL); + g_return_if_fail (G_VALUE_TYPE (clock_gvalue) == GST_TYPE_CLOCK); + + if (clock) + *clock = (GstClock *) g_value_get_object (clock_gvalue); +} + /** * gst_message_parse_error: * @message: A valid #GstMessage of type GST_MESSAGE_ERROR. diff --git a/gst/gstmessage.h b/gst/gstmessage.h index 3138638731..e86d92ba3b 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -38,6 +38,11 @@ typedef struct _GstMessageClass GstMessageClass; * @GST_MESSAGE_BUFFERING: the pipeline is buffering * @GST_MESSAGE_STATE_CHANGED: a state change happened * @GST_MESSAGE_STEP_DONE: a framestep finished. + * @GST_MESSAGE_CLOCK_PROVIDE: an element notifies it capability of providing + * a clock. + * @GST_MESSAGE_CLOCK_LOST: The current clock as selected by the pipeline became + * unusable. The pipeline will select a new clock on the + * next PLAYING state change. * @GST_MESSAGE_NEW_CLOCK: a new clock was selected in the pipeline * @GST_MESSAGE_STRUCTURE_CHANGE: the structure of the pipeline changed. * @GST_MESSAGE_STREAM_STATUS: status about a stream, emitted when it starts, @@ -50,6 +55,7 @@ typedef struct _GstMessageClass GstMessageClass; * @GST_MESSAGE_SEGMENT_DONE: pipeline completed playback of a segment. * @GST_MESSAGE_ANY: mask for all of the above messages. */ +/* NOTE: keep in sync with quark registration in gstmessage.c */ typedef enum { GST_MESSAGE_UNKNOWN = 0, @@ -61,13 +67,15 @@ typedef enum GST_MESSAGE_BUFFERING = (1 << 5), GST_MESSAGE_STATE_CHANGED = (1 << 6), GST_MESSAGE_STEP_DONE = (1 << 7), - GST_MESSAGE_NEW_CLOCK = (1 << 8), - GST_MESSAGE_STRUCTURE_CHANGE = (1 << 9), - GST_MESSAGE_STREAM_STATUS = (1 << 10), - GST_MESSAGE_APPLICATION = (1 << 11), - GST_MESSAGE_ELEMENT = (1 << 12), - GST_MESSAGE_SEGMENT_START = (1 << 13), - GST_MESSAGE_SEGMENT_DONE = (1 << 14), + GST_MESSAGE_CLOCK_PROVIDE = (1 << 8), + GST_MESSAGE_CLOCK_LOST = (1 << 9), + GST_MESSAGE_NEW_CLOCK = (1 << 10), + GST_MESSAGE_STRUCTURE_CHANGE = (1 << 11), + GST_MESSAGE_STREAM_STATUS = (1 << 12), + GST_MESSAGE_APPLICATION = (1 << 13), + GST_MESSAGE_ELEMENT = (1 << 14), + GST_MESSAGE_SEGMENT_START = (1 << 15), + GST_MESSAGE_SEGMENT_DONE = (1 << 16), GST_MESSAGE_ANY = 0xffffffff } GstMessageType; @@ -146,6 +154,9 @@ GstMessage * gst_message_new_warning (GstObject * src, GError * error, gchar * GstMessage * gst_message_new_tag (GstObject * src, GstTagList * tag_list); GstMessage * gst_message_new_state_changed (GstObject * src, GstState old_state, GstState new_state, GstState pending); +GstMessage * gst_message_new_clock_provide (GstObject * src, gboolean ready); +GstMessage * gst_message_new_clock_lost (GstObject * src); +GstMessage * gst_message_new_new_clock (GstObject * src, GstClock *clock); GstMessage * gst_message_new_segment_start (GstObject * src, GstClockTime timestamp); GstMessage * gst_message_new_segment_done (GstObject * src, GstClockTime timestamp); GstMessage * gst_message_new_application (GstObject * src, GstStructure * structure); @@ -159,6 +170,8 @@ void gst_message_parse_warning (GstMessage *message, GError **gerror, gchar **d void gst_message_parse_tag (GstMessage *message, GstTagList **tag_list); void gst_message_parse_state_changed (GstMessage *message, GstState *old_state, GstState *new_state, GstState *pending); +void gst_message_parse_clock_provide (GstMessage *message, gboolean *ready); +void gst_message_parse_new_clock (GstMessage *message, GstClock **clock); void gst_message_parse_segment_start (GstMessage *message, GstClockTime *timestamp); void gst_message_parse_segment_done (GstMessage *message, GstClockTime *timestamp); diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c index c18aa9648f..db7683a87c 100644 --- a/gst/gstpipeline.c +++ b/gst/gstpipeline.c @@ -316,15 +316,13 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition) /* when going to playing, select a clock */ if ((clock = gst_element_provide_clock (element))) { GstClockTime start_time; - - /* distribute the clock */ - gst_element_set_clock (element, clock); + gboolean new_clock; /* get start time */ start_time = gst_clock_get_time (clock); - gst_object_unref (clock); GST_LOCK (element); + new_clock = element->clock != clock; element->base_time = start_time - pipeline->stream_time + pipeline->delay; GST_DEBUG ("stream_time=%" GST_TIME_FORMAT ", start_time=%" @@ -332,6 +330,17 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition) GST_TIME_ARGS (pipeline->stream_time), GST_TIME_ARGS (start_time), GST_TIME_ARGS (element->base_time)); GST_UNLOCK (element); + + /* now distribute the clock */ + gst_element_set_clock (element, clock); + + if (new_clock) { + /* if we selected a new clock, let the app know about it */ + gst_element_post_message (element, + gst_message_new_new_clock (GST_OBJECT_CAST (element), clock)); + } + + gst_object_unref (clock); } else { GST_DEBUG ("no clock, using base time of 0"); gst_element_set_base_time (element, 0); diff --git a/tools/gst-launch.c b/tools/gst-launch.c index 6f2d42dfe7..5bb82be291 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -393,6 +393,15 @@ event_loop (GstElement * pipeline, gboolean blocking) } switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_NEW_CLOCK: + { + GstClock *clock; + + gst_message_parse_new_clock (message, &clock); + + g_print ("new clock: %p\n", clock); + break; + } case GST_MESSAGE_EOS: g_print (_ ("Got EOS from element \"%s\".\n"),