event: Add new GST_EVENT_INSTANT_RATE_CHANGE and GST_SEEK_FLAGS_INSTANT_RATE_CHANGE

A seek with that flag set must be non-flushing, not change the playback
direction and start/stop position. A seek handler will then send the new
GST_EVENT_INSTANT_RATE_CHANGE event downstream for downstream elements
to immediately apply the new playback rate before the new in-band segment
event arrives.
This commit is contained in:
Sebastian Dröge 2018-05-09 15:28:13 +03:00 committed by Jan Schmidt
parent 9707db909d
commit be3c4d00cf
5 changed files with 108 additions and 1 deletions

View file

@ -132,6 +132,7 @@ static GstEventQuarks event_quarks[] = {
{GST_EVENT_CUSTOM_BOTH, "custom-both", 0},
{GST_EVENT_CUSTOM_BOTH_OOB, "custom-both-oob", 0},
{GST_EVENT_STREAM_GROUP_DONE, "stream-group-done", 0},
{GST_EVENT_INSTANT_RATE_CHANGE, "instant-rate-change", 0},
{0, NULL, 0}
};
@ -1270,6 +1271,10 @@ gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags,
GstStructure *structure;
g_return_val_if_fail (rate != 0.0, NULL);
g_return_val_if_fail ((flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) == 0
|| (start_type == GST_SEEK_TYPE_NONE
&& stop_type == GST_SEEK_TYPE_NONE
&& (flags & GST_SEEK_FLAG_FLUSH) == 0), NULL);
/* SNAP flags only make sense in combination with the KEYUNIT flag. Warn
* and unset the SNAP flags if they're set without the KEYUNIT flag */
@ -2167,3 +2172,70 @@ gst_event_parse_segment_done (GstEvent * event, GstFormat * format,
if (position != NULL)
*position = g_value_get_int64 (val);
}
/**
* gst_event_new_instant_rate_change:
* @rate_multiplier: the multiplier to be applied to the playback rate
* @new_flags: A new subset of segment flags to replace in segments
*
* Create a new instant-rate-change event. This event is sent by seek
* handlers (e.g. demuxers) when receiving a seek with the
* %GST_SEEK_FLAG_INSTANT_RATE_CHANGE and signals to downstream elements that
* the playback rate in the existing segment should be immediately multiplied
* by the @rate_multiplier factor.
*
* The flags provided replace any flags in the existing segment, for the
* flags within the %GST_SEGMENT_INSTANT_FLAGS set. Other GstSegmentFlags
* are ignored and not transferred in the event.
*
* Returns: (transfer full): the new instant-rate-change event.
*
* Since: 1.18
*/
GstEvent *
gst_event_new_instant_rate_change (gdouble rate_multiplier,
GstSegmentFlags new_flags)
{
GstEvent *event;
g_return_val_if_fail (rate_multiplier != 0.0, NULL);
new_flags &= GST_SEGMENT_INSTANT_FLAGS;
GST_CAT_TRACE (GST_CAT_EVENT, "creating instant-rate-change event %lf %08x",
rate_multiplier, new_flags);
event = gst_event_new_custom (GST_EVENT_INSTANT_RATE_CHANGE,
gst_structure_new_id (GST_QUARK (EVENT_INSTANT_RATE_CHANGE),
GST_QUARK (RATE), G_TYPE_DOUBLE, rate_multiplier,
GST_QUARK (FLAGS), GST_TYPE_SEGMENT_FLAGS, new_flags, NULL));
return event;
}
/**
* gst_event_parse_instant_rate_change:
* @event: a #GstEvent of type #GST_EVENT_INSTANT_RATE_CHANGE
* @rate_multiplier: (out) (allow-none): location in which to store the rate
* multiplier of the instant-rate-change event, or %NULL
* @new_flags: (out) (allow-none): location in which to store the new
* segment flags of the instant-rate-change event, or %NULL
*
* Extract rate and flags from an instant-rate-change event.
*
* Since: 1.18
*/
void
gst_event_parse_instant_rate_change (GstEvent * event,
gdouble * rate_multiplier, GstSegmentFlags * new_flags)
{
GstStructure *structure;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_INSTANT_RATE_CHANGE);
structure = GST_EVENT_STRUCTURE (event);
gst_structure_id_get (structure, GST_QUARK (RATE), G_TYPE_DOUBLE,
rate_multiplier, GST_QUARK (FLAGS), GST_TYPE_SEGMENT_FLAGS, new_flags,
NULL);
}

View file

@ -121,6 +121,8 @@ typedef enum {
* @GST_EVENT_RECONFIGURE: A request for upstream renegotiating caps and reconfiguring.
* @GST_EVENT_TOC_SELECT: A request for a new playback position based on TOC
* entry's UID.
* @GST_EVENT_INSTANT_RATE_CHANGE: Notify downstream that a playback rate override
* should be applied as soon as possible. (Since: 1.18)
* @GST_EVENT_CUSTOM_UPSTREAM: Upstream custom event
* @GST_EVENT_CUSTOM_DOWNSTREAM: Downstream custom event that travels in the
* data flow.
@ -163,6 +165,9 @@ typedef enum {
GST_EVENT_SEGMENT_DONE = GST_EVENT_MAKE_TYPE (150, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
GST_EVENT_GAP = GST_EVENT_MAKE_TYPE (160, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/* sticky downstream non-serialized */
GST_EVENT_INSTANT_RATE_CHANGE = GST_EVENT_MAKE_TYPE (180, FLAG(DOWNSTREAM) | FLAG(STICKY)),
/* upstream events */
GST_EVENT_QOS = GST_EVENT_MAKE_TYPE (190, FLAG(UPSTREAM)),
GST_EVENT_SEEK = GST_EVENT_MAKE_TYPE (200, FLAG(UPSTREAM)),
@ -731,6 +736,15 @@ GstEvent* gst_event_new_segment_done (GstFormat format, gint64 positi
GST_API
void gst_event_parse_segment_done (GstEvent *event, GstFormat *format, gint64 *position);
/* instant-rate-change event */
GST_API
GstEvent * gst_event_new_instant_rate_change (gdouble rate_multiplier, GstSegmentFlags new_flags) G_GNUC_MALLOC;
GST_API
void gst_event_parse_instant_rate_change (GstEvent *event,
gdouble *rate_multiplier, GstSegmentFlags *new_flags);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstEvent, gst_event_unref)
G_END_DECLS

View file

@ -77,6 +77,7 @@ static const gchar *_quark_strings[] = {
"redirect-entry-taglists", "redirect-entry-structures",
"GstEventStreamGroupDone", "GstQueryBitrate", "nominal-bitrate",
"GstMessageDeviceChanged", "device-changed", "trickmode-interval",
"GstEventInstantRateChange",
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -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_EVENT_INSTANT_RATE_CHANGE = 194,
GST_QUARK_MAX = 195
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -81,6 +81,10 @@ typedef enum {
* @GST_SEEK_FLAG_TRICKMODE_NO_AUDIO: when doing fast forward or fast reverse
* playback, request that audio decoder elements skip
* decoding and output only gap events or silence. (Since: 1.6)
* @GST_SEEK_FLAG_INSTANT_RATE_CHANGE: Signals that a rate change should be
* applied immediately. Only valid if start/stop position
* are GST_CLOCK_TIME_NONE, the playback direction does not change
* and the seek is not flushing. (Since: 1.18)
* @GST_SEEK_FLAG_SKIP: Deprecated backward compatibility flag, replaced
* by %GST_SEEK_FLAG_TRICKMODE
*
@ -101,6 +105,16 @@ typedef enum {
* continue playback. With this seek method it is possible to perform seamless
* looping or simple linear editing.
*
* When only changing the playback rate and not the direction, the
* %GST_SEEK_FLAG_INSTANT_RATE_CHANGE flag can be used for a non-flushing seek
* to signal that the rate change should be applied immediately. This requires
* special support in the seek handlers (e.g. demuxers) and any elements
* synchronizing to the clock, and in general can't work in all cases (for example
* UDP streaming where the delivery rate is controlled by a remote server). The
* instant-rate-change mode supports changing the trickmode-related GST_SEEK_ flags,
* but can't be used in conjunction with other seek flags that affect the new
* playback position - as the playback position will not be changing.
*
* When doing fast forward (rate > 1.0) or fast reverse (rate < -1.0) trickmode
* playback, the %GST_SEEK_FLAG_TRICKMODE flag can be used to instruct decoders
* and demuxers to adjust the playback rate by skipping frames. This can improve
@ -143,6 +157,7 @@ typedef enum {
GST_SEEK_FLAG_TRICKMODE_KEY_UNITS = (1 << 7),
GST_SEEK_FLAG_TRICKMODE_NO_AUDIO = (1 << 8),
GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED = (1 << 9),
GST_SEEK_FLAG_INSTANT_RATE_CHANGE = (1 << 10),
} GstSeekFlags;
/**
@ -178,6 +193,10 @@ typedef enum { /*< flags >*/
GST_SEGMENT_FLAG_TRICKMODE_NO_AUDIO = GST_SEEK_FLAG_TRICKMODE_NO_AUDIO
} GstSegmentFlags;
/* Flags that are reflected for instant-rate-change seeks */
#define GST_SEGMENT_INSTANT_FLAGS \
(GST_SEGMENT_FLAG_TRICKMODE|GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS|GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED|GST_SEGMENT_FLAG_TRICKMODE_NO_AUDIO)
/**
* GstSegment:
* @flags: flags for this segment