+2005-10-18 Wim Taymans <wim@fluendo.com>
+
+ * check/gst/gstbin.c: (GST_START_TEST):
+ * check/gst/gstmessage.c: (GST_START_TEST):
+ * check/gst/gstpipeline.c: (GST_START_TEST), (message_received):
+ * gst/gstbin.c: (bin_bus_handler):
+ * gst/gstelement.c: (gst_element_commit_state),
+ (gst_element_lost_state):
+ * gst/gstmessage.c: (gst_message_new_state_changed),
+ (gst_message_new_segment_start), (gst_message_new_segment_done),
+ (gst_message_new_duration), (gst_message_parse_state_changed),
+ (gst_message_parse_segment_start),
+ (gst_message_parse_segment_done), (gst_message_parse_duration):
+ * gst/gstmessage.h:
+ * tools/gst-launch.c: (event_loop):
+ Make messages future proof.
+ state-change gets a flag if it was a message comming from the
+ streaming thread.
+ segment-start/stop can also be specified in other formats.
+ A message to notify an app that a pipeline changed playback
+ duration.
+ Also fix a GstMessage leak in -launch
+
2005-10-18 Andy Wingo <wingo@pobox.com>
* gst/gstelement.c (gst_element_dispose): More helpful message.
{ \
GstMessage *msg; \
GstState old = 0, new = 0, pending = 0; \
+ gboolean async; \
msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND); \
fail_if (msg == NULL, "No state change message within 1 second (#" \
G_STRINGIFY (num) ")"); \
- gst_message_parse_state_changed (msg, &old, &new, &pending); \
+ gst_message_parse_state_changed (msg, &async, &old, &new, &pending); \
fail_if (msg->src != GST_OBJECT (element), G_STRINGIFY(element) \
" should have changed state next (#" G_STRINGIFY (num) ")"); \
fail_if (old != old_state || new != new_state, "state change is not " \
{
GstMessage *msg;
GstState old = 0, new = 0, pending = 0;
+ gboolean async;
GstObject *first, *second;
msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND);
fail_if (msg == NULL, "No state change message within 1 second (#201)");
- gst_message_parse_state_changed (msg, &old, &new, &pending);
+ gst_message_parse_state_changed (msg, &async, &old, &new, &pending);
first = gst_object_ref (msg->src);
fail_if (first != GST_OBJECT (sink1) && first != GST_OBJECT (sink2),
msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND);
fail_if (msg == NULL, "No state change message within 1 second (#201)");
- gst_message_parse_state_changed (msg, &old, &new, &pending);
+ gst_message_parse_state_changed (msg, &async, &old, &new, &pending);
second = gst_object_ref (msg->src);
fail_if (second != GST_OBJECT (sink1) && second != GST_OBJECT (sink2),
/* GST_MESSAGE_STATE_CHANGED */
{
GstState oldstate, newstate, pending;
+ gboolean async;
+ async = TRUE;
oldstate = GST_STATE_PAUSED;
newstate = GST_STATE_PLAYING;
pending = GST_STATE_VOID_PENDING;
- message = gst_message_new_state_changed (NULL, oldstate, newstate, pending);
+ message =
+ gst_message_new_state_changed (NULL, async, oldstate, newstate,
+ pending);
fail_if (message == NULL);
fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STATE_CHANGED);
fail_unless (GST_MESSAGE_SRC (message) == NULL);
/* set some wrong values to check if the parse method overwrites them
* with the good values */
+ async = FALSE;
oldstate = GST_STATE_READY;
newstate = GST_STATE_READY;
pending = GST_STATE_READY;
- gst_message_parse_state_changed (message, &oldstate, &newstate, &pending);
+ gst_message_parse_state_changed (message, &async, &oldstate, &newstate,
+ &pending);
+ fail_unless (async == TRUE);
fail_unless (oldstate == GST_STATE_PAUSED);
fail_unless (newstate == GST_STATE_PLAYING);
fail_unless (pending == GST_STATE_VOID_PENDING);
while (!done) {
GstMessage *message;
GstState old, new, pending;
+ gboolean async;
message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
if (message) {
- gst_message_parse_state_changed (message, &old, &new, &pending);
+ gst_message_parse_state_changed (message, &async, &old, &new, &pending);
GST_DEBUG_OBJECT (message->src, "state change from %d to %d", old, new);
if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING)
done = TRUE;
case GST_MESSAGE_STATE_CHANGED:
{
GstState old, new, pending;
+ gboolean async;
GST_DEBUG ("state change message received");
- gst_message_parse_state_changed (message, &old, &new, &pending);
+ gst_message_parse_state_changed (message, &async, &old, &new, &pending);
GST_DEBUG ("new state %d", new);
if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING) {
GST_DEBUG ("quitting main loop");
{
GstState old, new, pending;
GstObject *src;
+ gboolean async;
- gst_message_parse_state_changed (message, &old, &new, &pending);
+ gst_message_parse_state_changed (message, &async, &old, &new, &pending);
src = GST_MESSAGE_SRC (message);
/* ref src, as we need it after we post the message up */
gst_object_ref (src);
gst_element_state_get_name (pending));
message = gst_message_new_state_changed (GST_OBJECT (element),
- old_state, next, pending);
+ FALSE, old_state, next, pending);
gst_element_post_message (element, message);
if (pending != GST_STATE_VOID_PENDING) {
GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC;
message = gst_message_new_state_changed (GST_OBJECT (element),
- current_state, current_state, current_state);
+ FALSE, current_state, current_state, current_state);
gst_element_post_message (element, message);
}
}
{GST_MESSAGE_ELEMENT, "element", 0},
{GST_MESSAGE_SEGMENT_START, "segment-start", 0},
{GST_MESSAGE_SEGMENT_DONE, "segment-done", 0},
+ {GST_MESSAGE_DURATION, "duration", 0},
{0, NULL, 0}
};
/**
* gst_message_new_state_changed:
* @src: the object originating the message
+ * @async: if this is a state change from a streaming thread
* @oldstate: the previous state
* @newstate: the new (current) state
* @pending: the pending (target) state
* MT safe.
*/
GstMessage *
-gst_message_new_state_changed (GstObject * src,
+gst_message_new_state_changed (GstObject * src, gboolean async,
GstState oldstate, GstState newstate, GstState pending)
{
GstMessage *message;
message = gst_message_new_custom (GST_MESSAGE_STATE_CHANGED, src,
gst_structure_new ("GstMessageState",
+ "async", G_TYPE_BOOLEAN, async,
"old-state", GST_TYPE_STATE, (gint) oldstate,
"new-state", GST_TYPE_STATE, (gint) newstate,
"pending-state", GST_TYPE_STATE, (gint) pending, NULL));
/**
* gst_message_new_segment_start:
* @src: The object originating the message.
- * @timestamp: The timestamp of the segment being played
+ * @format: The format of the position being played
+ * @position: The position of the segment being played
*
* Create a new segment message. This message is posted by elements that
* start playback of a segment as a result of a segment seek. This message
* MT safe.
*/
GstMessage *
-gst_message_new_segment_start (GstObject * src, GstClockTime timestamp)
+gst_message_new_segment_start (GstObject * src, GstFormat format,
+ gint64 position)
{
GstMessage *message;
message = gst_message_new_custom (GST_MESSAGE_SEGMENT_START, src,
- gst_structure_new ("GstMessageSegmentStart", "timestamp", G_TYPE_INT64,
- (gint64) timestamp, NULL));
+ gst_structure_new ("GstMessageSegmentStart",
+ "format", GST_TYPE_FORMAT, format,
+ "position", G_TYPE_INT64, position, NULL));
return message;
}
/**
* gst_message_new_segment_done:
* @src: The object originating the message.
- * @timestamp: The timestamp of the segment being played
+ * @format: The format of the position being done
+ * @position: The position of the segment being done
*
* Create a new segment done message. This message is posted by elements that
* finish playback of a segment as a result of a segment seek. This message
* MT safe.
*/
GstMessage *
-gst_message_new_segment_done (GstObject * src, GstClockTime timestamp)
+gst_message_new_segment_done (GstObject * src, GstFormat format,
+ gint64 position)
{
GstMessage *message;
message = gst_message_new_custom (GST_MESSAGE_SEGMENT_DONE, src,
- gst_structure_new ("GstMessageSegmentDone", "timestamp", G_TYPE_INT64,
- (gint64) timestamp, NULL));
+ gst_structure_new ("GstMessageSegmentDone",
+ "format", GST_TYPE_FORMAT, format,
+ "position", G_TYPE_INT64, position, NULL));
return message;
}
}
/**
+ * gst_message_new_duration:
+ * @src: The object originating the message.
+ * @format: The format of the duration
+ * @duration: The new duration
+ *
+ * Create a new duration message. This message is posted by elements that
+ * know the duration of a stream in a specific format. This message
+ * is received by bins and is used to calculate the total duration of a
+ * pipeline.
+ *
+ * Returns: The new duration message.
+ *
+ * MT safe.
+ */
+GstMessage *
+gst_message_new_duration (GstObject * src, GstFormat format, gint64 duration)
+{
+ GstMessage *message;
+
+ message = gst_message_new_custom (GST_MESSAGE_DURATION, src,
+ gst_structure_new ("GstMessageDuration",
+ "format", GST_TYPE_FORMAT, format,
+ "duration", G_TYPE_INT64, duration, NULL));
+
+ return message;
+}
+
+/**
* gst_message_get_structure:
* @message: The #GstMessage.
*
/**
* gst_message_parse_state_changed:
* @message: a valid #GstMessage of type GST_MESSAGE_STATE_CHANGED
+ * @async: is this an async state change
* @oldstate: the previous state
* @newstate: the new (current) state
* @pending: the pending (target) state
* MT safe.
*/
void
-gst_message_parse_state_changed (GstMessage * message, GstState * oldstate,
- GstState * newstate, GstState * pending)
+gst_message_parse_state_changed (GstMessage * message, gboolean * async,
+ GstState * oldstate, GstState * newstate, GstState * pending)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STATE_CHANGED);
+ if (async)
+ gst_structure_get_boolean (message->structure, "async", async);
if (oldstate)
gst_structure_get_enum (message->structure, "old-state",
GST_TYPE_STATE, (gint *) oldstate);
/**
* gst_message_parse_segment_start:
* @message: A valid #GstMessage of type GST_MESSAGE_SEGMENT_START.
- * @timestamp: Result location for the timestamp
+ * @format: Result location for the format
+ * @position: Result location for the position
*
- * Extracts the timestamp from the segment start message.
+ * Extracts the position and format from the segment start message.
*
* MT safe.
*/
void
-gst_message_parse_segment_start (GstMessage * message, GstClockTime * timestamp)
+gst_message_parse_segment_start (GstMessage * message, GstFormat * format,
+ gint64 * position)
{
- const GValue *time_gvalue;
+ const GstStructure *structure;
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_SEGMENT_START);
- time_gvalue = gst_structure_get_value (message->structure, "timstamp");
- g_return_if_fail (time_gvalue != NULL);
- g_return_if_fail (G_VALUE_TYPE (time_gvalue) == G_TYPE_INT64);
-
- if (timestamp)
- *timestamp = (GstClockTime) g_value_get_int64 (time_gvalue);
+ structure = gst_message_get_structure (message);
+ if (format)
+ *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
+ if (position)
+ *position =
+ g_value_get_int64 (gst_structure_get_value (structure, "position"));
}
/**
* gst_message_parse_segment_done:
* @message: A valid #GstMessage of type GST_MESSAGE_SEGMENT_DONE.
- * @timestamp: Result location for the timestamp
+ * @format: Result location for the format
+ * @position: Result location for the position
*
- * Extracts the timestamp from the segment done message.
+ * Extracts the position and format from the segment start message.
*
* MT safe.
*/
void
-gst_message_parse_segment_done (GstMessage * message, GstClockTime * timestamp)
+gst_message_parse_segment_done (GstMessage * message, GstFormat * format,
+ gint64 * position)
{
- const GValue *time_gvalue;
+ const GstStructure *structure;
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_SEGMENT_DONE);
- time_gvalue = gst_structure_get_value (message->structure, "timstamp");
- g_return_if_fail (time_gvalue != NULL);
- g_return_if_fail (G_VALUE_TYPE (time_gvalue) == G_TYPE_INT64);
+ structure = gst_message_get_structure (message);
+ if (format)
+ *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
+ if (position)
+ *position =
+ g_value_get_int64 (gst_structure_get_value (structure, "position"));
+}
- if (timestamp)
- *timestamp = (GstClockTime) g_value_get_int64 (time_gvalue);
+/**
+ * gst_message_parse_duration:
+ * @message: A valid #GstMessage of type GST_MESSAGE_DURATION.
+ * @format: Result location for the format
+ * @duration: Result location for the duration
+ *
+ * Extracts the duration and format from the duration message.
+ *
+ * MT safe.
+ */
+void
+gst_message_parse_duration (GstMessage * message, GstFormat * format,
+ gint64 * duration)
+{
+ const GstStructure *structure;
+
+ g_return_if_fail (GST_IS_MESSAGE (message));
+ g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_DURATION);
+
+ structure = gst_message_get_structure (message);
+ if (format)
+ *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
+ if (duration)
+ *duration =
+ g_value_get_int64 (gst_structure_get_value (structure, "duration"));
}
* documentation
* @GST_MESSAGE_SEGMENT_START: pipeline started playback of a segment.
* @GST_MESSAGE_SEGMENT_DONE: pipeline completed playback of a segment.
+ * @GST_MESSAGE_DURATION: The duration of a pipeline changed.
* @GST_MESSAGE_ANY: mask for all of the above messages.
*/
/* NOTE: keep in sync with quark registration in gstmessage.c */
GST_MESSAGE_ELEMENT = (1 << 14),
GST_MESSAGE_SEGMENT_START = (1 << 15),
GST_MESSAGE_SEGMENT_DONE = (1 << 16),
+ GST_MESSAGE_DURATION = (1 << 17),
GST_MESSAGE_ANY = 0xffffffff
} GstMessageType;
GstMessage * gst_message_new_error (GstObject * src, GError * error, gchar * debug);
GstMessage * gst_message_new_warning (GstObject * src, GError * error, gchar * debug);
GstMessage * gst_message_new_tag (GstObject * src, GstTagList * tag_list);
-GstMessage * gst_message_new_state_changed (GstObject * src, GstState oldstate,
+GstMessage * gst_message_new_state_changed (GstObject * src, gboolean async, GstState oldstate,
GstState newstate, GstState pending);
GstMessage * gst_message_new_clock_provide (GstObject * src, GstClock *clock, gboolean ready);
GstMessage * gst_message_new_clock_lost (GstObject * src, GstClock *clock);
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);
GstMessage * gst_message_new_element (GstObject * src, GstStructure * structure);
+GstMessage * gst_message_new_segment_start (GstObject * src, GstFormat format, gint64 position);
+GstMessage * gst_message_new_segment_done (GstObject * src, GstFormat format, gint64 position);
+GstMessage * gst_message_new_duration (GstObject * src, GstFormat format, gint64 duration);
GstMessage * gst_message_new_custom (GstMessageType type,
GstObject * src,
GstStructure * structure);
void gst_message_parse_error (GstMessage *message, GError **gerror, gchar **debug);
void gst_message_parse_warning (GstMessage *message, GError **gerror, gchar **debug);
void gst_message_parse_tag (GstMessage *message, GstTagList **tag_list);
-void gst_message_parse_state_changed (GstMessage *message, GstState *oldstate,
+void gst_message_parse_state_changed (GstMessage *message, gboolean *async, GstState *oldstate,
GstState *newstate, GstState *pending);
void gst_message_parse_clock_provide (GstMessage *message, GstClock **clock, gboolean *ready);
void gst_message_parse_clock_lost (GstMessage *message, GstClock **clock);
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);
+void gst_message_parse_segment_start (GstMessage *message, GstFormat *format, gint64 *position);
+void gst_message_parse_segment_done (GstMessage *message, GstFormat *format, gint64 *position);
+void gst_message_parse_duration (GstMessage *message, GstFormat *format, gint64 *duration);
const GstStructure * gst_message_get_structure (GstMessage *message);
{ \
GstMessage *msg; \
GstState old = 0, new = 0, pending = 0; \
+ gboolean async; \
msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND); \
fail_if (msg == NULL, "No state change message within 1 second (#" \
G_STRINGIFY (num) ")"); \
- gst_message_parse_state_changed (msg, &old, &new, &pending); \
+ gst_message_parse_state_changed (msg, &async, &old, &new, &pending); \
fail_if (msg->src != GST_OBJECT (element), G_STRINGIFY(element) \
" should have changed state next (#" G_STRINGIFY (num) ")"); \
fail_if (old != old_state || new != new_state, "state change is not " \
{
GstMessage *msg;
GstState old = 0, new = 0, pending = 0;
+ gboolean async;
GstObject *first, *second;
msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND);
fail_if (msg == NULL, "No state change message within 1 second (#201)");
- gst_message_parse_state_changed (msg, &old, &new, &pending);
+ gst_message_parse_state_changed (msg, &async, &old, &new, &pending);
first = gst_object_ref (msg->src);
fail_if (first != GST_OBJECT (sink1) && first != GST_OBJECT (sink2),
msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND);
fail_if (msg == NULL, "No state change message within 1 second (#201)");
- gst_message_parse_state_changed (msg, &old, &new, &pending);
+ gst_message_parse_state_changed (msg, &async, &old, &new, &pending);
second = gst_object_ref (msg->src);
fail_if (second != GST_OBJECT (sink1) && second != GST_OBJECT (sink2),
/* GST_MESSAGE_STATE_CHANGED */
{
GstState oldstate, newstate, pending;
+ gboolean async;
+ async = TRUE;
oldstate = GST_STATE_PAUSED;
newstate = GST_STATE_PLAYING;
pending = GST_STATE_VOID_PENDING;
- message = gst_message_new_state_changed (NULL, oldstate, newstate, pending);
+ message =
+ gst_message_new_state_changed (NULL, async, oldstate, newstate,
+ pending);
fail_if (message == NULL);
fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STATE_CHANGED);
fail_unless (GST_MESSAGE_SRC (message) == NULL);
/* set some wrong values to check if the parse method overwrites them
* with the good values */
+ async = FALSE;
oldstate = GST_STATE_READY;
newstate = GST_STATE_READY;
pending = GST_STATE_READY;
- gst_message_parse_state_changed (message, &oldstate, &newstate, &pending);
+ gst_message_parse_state_changed (message, &async, &oldstate, &newstate,
+ &pending);
+ fail_unless (async == TRUE);
fail_unless (oldstate == GST_STATE_PAUSED);
fail_unless (newstate == GST_STATE_PLAYING);
fail_unless (pending == GST_STATE_VOID_PENDING);
while (!done) {
GstMessage *message;
GstState old, new, pending;
+ gboolean async;
message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
if (message) {
- gst_message_parse_state_changed (message, &old, &new, &pending);
+ gst_message_parse_state_changed (message, &async, &old, &new, &pending);
GST_DEBUG_OBJECT (message->src, "state change from %d to %d", old, new);
if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING)
done = TRUE;
case GST_MESSAGE_STATE_CHANGED:
{
GstState old, new, pending;
+ gboolean async;
GST_DEBUG ("state change message received");
- gst_message_parse_state_changed (message, &old, &new, &pending);
+ gst_message_parse_state_changed (message, &async, &old, &new, &pending);
GST_DEBUG ("new state %d", new);
if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING) {
GST_DEBUG ("quitting main loop");
gst_message_parse_new_clock (message, &clock);
g_print ("New clock: %s\n", GST_OBJECT_NAME (clock));
+ gst_message_unref (message);
break;
}
case GST_MESSAGE_EOS:
}
case GST_MESSAGE_STATE_CHANGED:{
GstState old, new, pending;
+ gboolean async;
- gst_message_parse_state_changed (message, &old, &new, &pending);
+ gst_message_parse_state_changed (message, &async, &old, &new, &pending);
if (!(old == GST_STATE_PLAYING && new == GST_STATE_PAUSED &&
GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline))) {
gst_message_unref (message);