From: <wt...@ke...> - 2008-10-13 17:19:49
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Mon Oct 13 2008 17:19:39 UTC Log message: * docs/design/part-TODO.txt: Remove item from the todo list because it was fixed with the latency state change rewrites. * docs/design/part-seeking.txt: * docs/design/part-segments.txt: Update some docs. * gst/gstevent.c: (gst_event_new_new_segment_full), (gst_event_parse_new_segment_full), (gst_event_new_buffer_size), (gst_event_parse_buffer_size), (gst_event_new_qos), (gst_event_parse_qos), (gst_event_new_seek), (gst_event_parse_seek), (gst_event_new_latency), (gst_event_parse_latency): Use quarks to construct and parse events. * gst/gstquark.c: (_priv_gst_quarks_initialize): * gst/gstquark.h: Add some more quarks to the table. Emit a warning when the quark tables are not in sync. * tests/check/gst/gstbus.c: (GST_START_TEST): Add an assert. Modified files: . : ChangeLog docs/design : part-TODO.txt part-seeking.txt part-segments.txt gst : gstevent.c gstquark.c gstquark.h tests/check/gst : gstbus.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.4104&r2=1.4105 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/docs/design/part-TODO.txt.diff?r1=1.32&r2=1.33 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/docs/design/part-seeking.txt.diff?r1=1.7&r2=1.8 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/docs/design/part-segments.txt.diff?r1=1.4&r2=1.5 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstevent.c.diff?r1=1.116&r2=1.117 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstquark.c.diff?r1=1.4&r2=1.5 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstquark.h.diff?r1=1.4&r2=1.5 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/tests/check/gst/gstbus.c.diff?r1=1.15&r2=1.16 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.4104 retrieving revision 1.4105 diff -u -d -r1.4104 -r1.4105 --- ChangeLog 13 Oct 2008 16:47:48 -0000 1.4104 +++ ChangeLog 13 Oct 2008 17:19:22 -0000 1.4105 @@ -1,3 +1,29 @@ +2008-10-13 Wim Taymans <wim...@co...> + + * docs/design/part-TODO.txt: + Remove item from the todo list because it was fixed with the latency + state change rewrites. + * docs/design/part-seeking.txt: + * docs/design/part-segments.txt: + Update some docs. + * gst/gstevent.c: (gst_event_new_new_segment_full), + (gst_event_parse_new_segment_full), (gst_event_new_buffer_size), + (gst_event_parse_buffer_size), (gst_event_new_qos), + (gst_event_parse_qos), (gst_event_new_seek), + (gst_event_parse_seek), (gst_event_new_latency), + (gst_event_parse_latency): + Use quarks to construct and parse events. + * gst/gstquark.c: (_priv_gst_quarks_initialize): + * gst/gstquark.h: + Add some more quarks to the table. + Emit a warning when the quark tables are not in sync. + * tests/check/gst/gstbus.c: (GST_START_TEST): + Add an assert. 2008-10-13 Stefan Kost <en...@us...> * plugins/elements/Makefile.am: Index: part-TODO.txt RCS file: /cvs/gstreamer/gstreamer/docs/design/part-TODO.txt,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- part-TODO.txt 10 Oct 2008 14:31:03 -0000 1.32 +++ part-TODO.txt 13 Oct 2008 17:19:24 -0000 1.33 @@ -59,12 +59,6 @@ - Make serialisation of structures more consistent, readable and nicer code-wise. -- When a seekable live source does a flushing seek, it needs a new base_time to - timestamp new data. The pipeline however does not know that there is a live - source in the pipeline and thus does not select a new base_time automatically. - There needs to be a mechanism for a live source to request a new base_time or - pipeline restart. - - pad block has several issues: * can't block on selected things, like push, pull, pad_alloc, events, ... * can't check why the block happened. We should also be able to get the item/ Index: part-seeking.txt RCS file: /cvs/gstreamer/gstreamer/docs/design/part-seeking.txt,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- part-seeking.txt 24 Sep 2007 11:22:25 -0000 1.7 +++ part-seeking.txt 13 Oct 2008 17:19:24 -0000 1.8 @@ -2,46 +2,63 @@ ------- Seeking in GStreamer means configuring the pipeline for playback of the -media between a certain start and stop time, called a segment. +media between a certain start and stop time, called a segment. By default a +pipeline will play from position 0 to the total duration of the media at a rate +of 1.0. -Different kinds of seeking exist: +A seek is performed by sending a seek event to the sink elements of a +pipeline. Sending the seek event to a bin will by default forward +the event to all sinks in the bin. - - immediate seeking with low latency (FLUSH seek) - - seeking without flush, playback will start from the new - position after all the queues are emptied with old data. - - segment seeking with and without FLUSH, this can be used to - implement seamless looping or NLE functionality. +When performing a seek, the start and stop values of the segment can be +specified as absoulte positions or relative to the currently configured +playback segment. Note that it is not possible to seek relative to the current +playback position. +Feedback of the seek operation can be immediatly using the GST_SEEK_FLAG_FLUSH +flag. With this flag, all pending data in the pipeline is discarded and playback +starts from the new position immediatly. +When the FLUSH flag is not set, the seek will be queued and executed as +soon as possible, which might be after all queues are emptied. Seeking can be performed in different formats such as time, frames or samples. -Seeking can be performed to an absolute position or relative to the -currently configured segment. +The seeking can be performed to a nearby key unit or to the exact +(estimated) unit in the media (GST_SEEK_FLAG_KEY_UNIT). -For seeking to work reliably, all plugins in the pipeline need to follow -the well-defined rules in this document. +The seeking can be performed by using an estimated target position or in an +accurate way (GST_SEEK_FLAG_ACCURATE). For some formats this can result in +having to scan the complete file in order to accurately find the target unit. Non segment seeking will make the pipeline emit EOS when the configured segment has been played. -Segment seeking will not emit an EOS at the end of the range but will -post a SEGMENT_DONE message on the bus. This message is posted by the -earliest element in the pipeline, typically a demuxer. After receiving -the message, the application can reconnect the pipeline or issue other -seek events in the pipeline. Since the message is posted as early as -possible in the pipeline, the application has some time to issue a new -seek to make the transition seamless. Typically the allowed delay is -defined by the buffer sizes of the sinks as well as the size of any -queues in the pipeline. +Segment seeking (using the GST_SEEK_FLAG_SEGMENT) will not emit an EOS at +the end of the playback segment but will post a SEGMENT_DONE message on the +bus. This message is posted by the element driving the playback in the +pipeline, typically a demuxer. After receiving the message, the application +can reconnect the pipeline or issue other seek events in the pipeline. +Since the message is posted as early as possible in the pipeline, the +application has some time to issue a new seek to make the transition seamless. +Typically the allowed delay is defined by the buffer sizes of the sinks as well +as the size of any queues in the pipeline. The seek can also change the playback speed of the configured segment. A speed of 1.0 is normal speed, 2.0 is double speed. Negative values mean backward playback. +When performing a seek with a playback rate different from 1.0, the +GST_SEEK_FLAG_SKIP flag can be used to instruct decoders and demuxers that they +are allowed to skip decoding. This can be useful when resource consumption is +more important than accurately producing all frames. Generating seeking events ------------------------- +A seek event is created with gst_event_new_seek (). Index: part-segments.txt RCS file: /cvs/gstreamer/gstreamer/docs/design/part-segments.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- part-segments.txt 22 Oct 2007 15:37:42 -0000 1.4 +++ part-segments.txt 13 Oct 2008 17:19:24 -0000 1.5 @@ -38,6 +38,13 @@ When doing a seek in this pipeline for a segment 1 to 5 seconds, avidemux will perform the seek. + Avidemux starts by sending a FLUSH_START event downstream and upstream. This + will cause its streaming task to PAUSED because _pad_pull_range() and + _pad_push() will return WRONG_STATE. It then waits for the STREAM_LOCK, + which will be unlocked when the streaming task pauses. At this point no + streaming is happening anymore in the pipeline and a FLUSH_STOP is sent + upstream and downstream. When avidemux starts playback of the segment from second 1 to 5, it pushes out a newsegment with 1 and 5 as start and stop times. The stream_time in the newsegment is also 1 as this is the position we seek to. @@ -57,18 +64,21 @@ When it reaches timestamp 5, it does not decode and push frames anymore. The video sink receives a frame of timestamp 1. It takes the start value of - the previous newsegment and aplies the folowing formula: + the previous newsegment and aplies the folowing (simplified) formula: render_time = BUFFER_TIMESTAMP - segment_start + element->base_time - It then syncs against the clock with this render_time. Not that + It then syncs against the clock with this render_time. Note that BUFFER_TIMESTAMP is always >= segment_start or else it would fall outside of the configure segment. - Videosink reports its current position as: + Videosink reports its current position as (simplified): current_position = clock_time - element->base_time + segment_time + See part-synchronisation.txt for a more detailed and accurate explanation of + synchronisation and position reporting. Since after a flushing seek the stream_time is reset to 0, the new buffer will be rendered immediatly after the seek and the current_position will be the stream_time of the seek that was performed. Index: gstevent.c RCS file: /cvs/gstreamer/gstreamer/gst/gstevent.c,v retrieving revision 1.116 retrieving revision 1.117 diff -u -d -r1.116 -r1.117 --- gstevent.c 1 Jul 2008 05:53:31 -0000 1.116 +++ gstevent.c 13 Oct 2008 17:19:24 -0000 1.117 @@ -83,6 +83,7 @@ #include "gstevent.h" #include "gstenumtypes.h" #include "gstutils.h" +#include "gstquark.h" static void gst_event_init (GTypeInstance * instance, gpointer g_class); static void gst_event_class_init (gpointer g_class, gpointer class_data); @@ -545,6 +546,9 @@ gdouble applied_rate, GstFormat format, gint64 start, gint64 stop, gint64 position) { + GstEvent *event; + GstStructure *structure; g_return_val_if_fail (rate != 0.0, NULL); g_return_val_if_fail (applied_rate != 0.0, NULL); @@ -568,15 +572,18 @@ if (stop != -1) g_return_val_if_fail (start <= stop, NULL); - return gst_event_new_custom (GST_EVENT_NEWSEGMENT, - gst_structure_new ("GstEventNewsegment", - "update", G_TYPE_BOOLEAN, update, - "rate", G_TYPE_DOUBLE, rate, - "applied_rate", G_TYPE_DOUBLE, applied_rate, - "format", GST_TYPE_FORMAT, format, - "start", G_TYPE_INT64, start, - "stop", G_TYPE_INT64, stop, - "position", G_TYPE_INT64, position, NULL)); + structure = gst_structure_empty_new ("GstEventNewsegment"); + gst_structure_id_set (structure, + GST_QUARK (UPDATE), G_TYPE_BOOLEAN, update, + GST_QUARK (RATE), G_TYPE_DOUBLE, rate, + GST_QUARK (APPLIED_RATE), G_TYPE_DOUBLE, applied_rate, + GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, + GST_QUARK (START), G_TYPE_INT64, start, + GST_QUARK (STOP), G_TYPE_INT64, stop, + GST_QUARK (POSITION), G_TYPE_INT64, position, NULL); + event = gst_event_new_custom (GST_EVENT_NEWSEGMENT, structure); + return event; } /** @@ -609,22 +616,32 @@ structure = gst_event_get_structure (event); if (G_LIKELY (update)) *update = - g_value_get_boolean (gst_structure_get_value (structure, "update")); + g_value_get_boolean (gst_structure_id_get_value (structure, + GST_QUARK (UPDATE))); if (G_LIKELY (rate)) - *rate = g_value_get_double (gst_structure_get_value (structure, "rate")); + *rate = + g_value_get_double (gst_structure_id_get_value (structure, + GST_QUARK (RATE))); if (G_LIKELY (applied_rate)) *applied_rate = - g_value_get_double (gst_structure_get_value (structure, - "applied_rate")); + GST_QUARK (APPLIED_RATE))); if (G_LIKELY (format)) - *format = g_value_get_enum (gst_structure_get_value (structure, "format")); + *format = + g_value_get_enum (gst_structure_id_get_value (structure, + GST_QUARK (FORMAT))); if (G_LIKELY (start)) - *start = g_value_get_int64 (gst_structure_get_value (structure, "start")); + *start = + g_value_get_int64 (gst_structure_id_get_value (structure, + GST_QUARK (START))); if (G_LIKELY (stop)) - *stop = g_value_get_int64 (gst_structure_get_value (structure, "stop")); + *stop = + GST_QUARK (STOP))); if (G_LIKELY (position)) *position = - g_value_get_int64 (gst_structure_get_value (structure, "position")); + GST_QUARK (POSITION))); @@ -679,17 +696,23 @@ gst_event_new_buffer_size (GstFormat format, gint64 minsize, gint64 maxsize, gboolean async) GST_CAT_INFO (GST_CAT_EVENT, "creating buffersize format %s, minsize %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT ", async %d", gst_format_get_name (format), minsize, maxsize, async); - return gst_event_new_custom (GST_EVENT_BUFFERSIZE, - gst_structure_new ("GstEventBufferSize", - "minsize", G_TYPE_INT64, minsize, - "maxsize", G_TYPE_INT64, maxsize, - "async", G_TYPE_BOOLEAN, async, NULL)); + structure = gst_structure_empty_new ("GstEventBufferSize"); + GST_QUARK (MINSIZE), G_TYPE_INT64, minsize, + GST_QUARK (MAXSIZE), G_TYPE_INT64, maxsize, + GST_QUARK (ASYNC), G_TYPE_BOOLEAN, async, NULL); + event = gst_event_new_custom (GST_EVENT_BUFFERSIZE, structure); @@ -713,15 +736,21 @@ if (format) if (minsize) *minsize = - g_value_get_int64 (gst_structure_get_value (structure, "minsize")); + GST_QUARK (MINSIZE))); if (maxsize) *maxsize = - g_value_get_int64 (gst_structure_get_value (structure, "maxsize")); + GST_QUARK (MAXSIZE))); if (async) - *async = g_value_get_boolean (gst_structure_get_value (structure, "async")); + *async = + GST_QUARK (ASYNC))); @@ -770,6 +799,9 @@ gst_event_new_qos (gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp) /* diff must be positive or timestamp + diff must be positive */ g_return_val_if_fail (diff >= 0 || -diff <= timestamp, NULL); @@ -778,11 +810,14 @@ ", timestamp %" GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp)); - return gst_event_new_custom (GST_EVENT_QOS, - gst_structure_new ("GstEventQOS", - "proportion", G_TYPE_DOUBLE, proportion, - "diff", G_TYPE_INT64, diff, - "timestamp", G_TYPE_UINT64, timestamp, NULL)); + structure = gst_structure_empty_new ("GstEventQOS"); + GST_QUARK (PROPORTION), G_TYPE_DOUBLE, proportion, + GST_QUARK (DIFF), G_TYPE_INT64, diff, + GST_QUARK (TIMESTAMP), G_TYPE_UINT64, timestamp, NULL); + event = gst_event_new_custom (GST_EVENT_QOS, structure); @@ -807,12 +842,16 @@ if (proportion) *proportion = - g_value_get_double (gst_structure_get_value (structure, "proportion")); + GST_QUARK (PROPORTION))); if (diff) - *diff = g_value_get_int64 (gst_structure_get_value (structure, "diff")); + *diff = + GST_QUARK (DIFF))); if (timestamp) *timestamp = - g_value_get_uint64 (gst_structure_get_value (structure, "timestamp")); + g_value_get_uint64 (gst_structure_id_get_value (structure, + GST_QUARK (TIMESTAMP))); @@ -841,9 +880,9 @@ * configured playback segment can be queried with #GST_QUERY_SEGMENT. * * @start_type and @stop_type specify how to adjust the currently configured - * start and stop fields in @segment. Adjustments can be made relative or - * absolute to the last configured values. A type of #GST_SEEK_TYPE_NONE means - * that the position should not be updated. + * start and stop fields in playback segment. Adjustments can be made relative + * or absolute to the last configured values. A type of #GST_SEEK_TYPE_NONE + * means that the position should not be updated. * When the rate is positive and @start has been updated, playback will start * from the newly configured start position. @@ -855,7 +894,7 @@ * It is not possible to seek relative to the current playback position, to do * this, PAUSE the pipeline, query the current playback position with * #GST_QUERY_POSITION and update the playback segment current position with a - * #GST_SEEK_TYPE_SET to the desired position. + * #GST_SEEK_TYPE_SET to the desired position. * Returns: A new seek event. */ @@ -863,6 +902,9 @@ gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags, GstSeekType start_type, gint64 start, GstSeekType stop_type, gint64 stop) if (format == GST_FORMAT_TIME) { @@ -881,14 +923,18 @@ stop); } - return gst_event_new_custom (GST_EVENT_SEEK, - gst_structure_new ("GstEventSeek", "rate", G_TYPE_DOUBLE, rate, - "flags", GST_TYPE_SEEK_FLAGS, flags, - "cur_type", GST_TYPE_SEEK_TYPE, start_type, - "cur", G_TYPE_INT64, start, - "stop_type", GST_TYPE_SEEK_TYPE, stop_type, - "stop", G_TYPE_INT64, stop, NULL)); + structure = gst_structure_empty_new ("GstEventSeek"); + GST_QUARK (FLAGS), GST_TYPE_SEEK_FLAGS, flags, + GST_QUARK (CUR_TYPE), GST_TYPE_SEEK_TYPE, start_type, + GST_QUARK (CUR), G_TYPE_INT64, start, + GST_QUARK (STOP_TYPE), GST_TYPE_SEEK_TYPE, stop_type, + GST_QUARK (STOP), G_TYPE_INT64, stop, NULL); + event = gst_event_new_custom (GST_EVENT_SEEK, structure); @@ -916,21 +962,33 @@ if (rate) if (flags) - *flags = g_value_get_flags (gst_structure_get_value (structure, "flags")); + *flags = + g_value_get_flags (gst_structure_id_get_value (structure, + GST_QUARK (FLAGS))); if (start_type) *start_type = - g_value_get_enum (gst_structure_get_value (structure, "cur_type")); + GST_QUARK (CUR_TYPE))); if (start) - *start = g_value_get_int64 (gst_structure_get_value (structure, "cur")); + GST_QUARK (CUR))); if (stop_type) *stop_type = - g_value_get_enum (gst_structure_get_value (structure, "stop_type")); + GST_QUARK (STOP_TYPE))); if (stop) @@ -968,12 +1026,18 @@ GstEvent * gst_event_new_latency (GstClockTime latency) "creating latency event %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); - return gst_event_new_custom (GST_EVENT_LATENCY, - gst_structure_new ("GstEventLatency", - "latency", G_TYPE_UINT64, latency, NULL)); + structure = gst_structure_empty_new ("GstEventLatency"); + GST_QUARK (LATENCY), G_TYPE_UINT64, latency, NULL); + event = gst_event_new_custom (GST_EVENT_LATENCY, structure); @@ -996,5 +1060,6 @@ if (latency) *latency = - g_value_get_uint64 (gst_structure_get_value (structure, "latency")); + GST_QUARK (LATENCY))); Index: gstquark.c RCS file: /cvs/gstreamer/gstreamer/gst/gstquark.c,v --- gstquark.c 6 Oct 2008 15:21:14 -0000 1.4 +++ gstquark.c 13 Oct 2008 17:19:25 -0000 1.5 @@ -34,7 +34,10 @@ "avg-in-rate", "avg-out-rate", "buffering-left", "estimated-total", "old-state", "new-state", "pending-state", "clock", "ready", "position", "new-base-time", "live", "min-latency", - "max-latency", "busy", "type", "owner" + "max-latency", "busy", "type", "owner", "update", "applied-rate", + "start", "stop", "minsize", "maxsize", "async", "proportion", + "diff", "timestamp", "flags", "cur-type", "cur", "stop-type", + "latency" }; GQuark _priv_gst_quark_table[GST_QUARK_MAX]; @@ -44,6 +47,10 @@ gint i; + if (G_N_ELEMENTS (_quark_strings) != GST_QUARK_MAX) + g_warning ("the quark table is not consistent! %ld != %d", + G_N_ELEMENTS (_quark_strings), GST_QUARK_MAX); for (i = 0; i < GST_QUARK_MAX; i++) { _priv_gst_quark_table[i] = g_quark_from_static_string (_quark_strings[i]); Index: gstquark.h RCS file: /cvs/gstreamer/gstreamer/gst/gstquark.h,v --- gstquark.h 6 Oct 2008 15:21:14 -0000 1.4 +++ gstquark.h 13 Oct 2008 17:19:25 -0000 1.5 @@ -62,8 +62,23 @@ GST_QUARK_BUSY = 33, GST_QUARK_TYPE = 34, GST_QUARK_OWNER = 35, + GST_QUARK_UPDATE = 36, + GST_QUARK_APPLIED_RATE = 37, + GST_QUARK_START = 38, + GST_QUARK_STOP = 39, + GST_QUARK_MINSIZE = 40, + GST_QUARK_MAXSIZE = 41, + GST_QUARK_ASYNC = 42, + GST_QUARK_PROPORTION = 43, + GST_QUARK_DIFF = 44, + GST_QUARK_TIMESTAMP = 45, + GST_QUARK_FLAGS = 46, + GST_QUARK_CUR_TYPE = 47, + GST_QUARK_CUR = 48, + GST_QUARK_STOP_TYPE = 49, + GST_QUARK_LATENCY = 50, - GST_QUARK_MAX = 36 + GST_QUARK_MAX = 51 } GstQuarkId; extern GQuark _priv_gst_quark_table[GST_QUARK_MAX]; Index: gstbus.c RCS file: /cvs/gstreamer/gstreamer/tests/check/gst/gstbus.c,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- gstbus.c 29 Feb 2008 13:59:20 -0000 1.15 +++ gstbus.c 13 Oct 2008 17:19:25 -0000 1.16 @@ -165,6 +165,7 @@ main_loop = g_main_loop_new (NULL, FALSE); id = gst_bus_add_watch (test_bus, gst_bus_async_signal_func, NULL); + fail_if (id == 0); g_signal_connect (test_bus, "message::eos", (GCallback) message_func_eos, NULL); g_signal_connect (test_bus, "message::application", |