diff options
Diffstat (limited to 'gst/gstsegment.c')
-rw-r--r-- | gst/gstsegment.c | 380 |
1 files changed, 109 insertions, 271 deletions
diff --git a/gst/gstsegment.c b/gst/gstsegment.c index 7722badb1..32eacdd79 100644 --- a/gst/gstsegment.c +++ b/gst/gstsegment.c @@ -33,7 +33,7 @@ * @see_also: #GstEvent * * This helper structure holds the relevant values for tracking the region of - * interest in a media file, called a segment. + * interest in a media file, called a segment. * * The structure can be used for two purposes: * <itemizedlist> @@ -41,7 +41,7 @@ * <listitem><para>tracking playback regions (handling newsegment events)</para></listitem> * </itemizedlist> * - * The segment is usually configured by the application with a seek event which + * The segment is usually configured by the application with a seek event which * is propagated upstream and eventually handled by an element that performs the seek. * * The configured segment is then propagated back downstream with a newsegment event. @@ -54,7 +54,7 @@ * * If the segment is used for managing seeks, the segment duration should be set with * gst_segment_set_duration(). The public duration field contains the duration of the - * segment. When using the segment for seeking, the start and time members should + * segment. When using the segment for seeking, the start and time members should * normally be left to their default 0 value. The stop position is left to -1 unless * explicitly configured to a different value after a seek event. * @@ -77,7 +77,7 @@ * to the clock. This function takes into account all accumulated segments as well as * any rate or applied_rate conversions. * - * For elements that need to perform operations on media data in stream_time, + * For elements that need to perform operations on media data in stream_time, * gst_segment_to_stream_time() can be used to convert a timestamp and the segment * info to stream time (which is always between 0 and the duration of the stream). * @@ -97,7 +97,7 @@ * Since: 0.10.20 */ GstSegment * -gst_segment_copy (GstSegment * segment) +gst_segment_copy (const GstSegment * segment) { GstSegment *result = NULL; @@ -107,6 +107,12 @@ gst_segment_copy (GstSegment * segment) return result; } +void +gst_segment_copy_into (const GstSegment * src, GstSegment * dest) +{ + memcpy (dest, src, sizeof (GstSegment)); +} + GType gst_segment_get_type (void) { @@ -123,7 +129,7 @@ gst_segment_get_type (void) /** * gst_segment_new: * - * Allocate a new #GstSegment structure and initialize it using + * Allocate a new #GstSegment structure and initialize it using * gst_segment_init(). * * Free-function: gst_segment_free @@ -169,93 +175,41 @@ gst_segment_init (GstSegment * segment, GstFormat format) { g_return_if_fail (segment != NULL); + segment->flags = 0; segment->rate = 1.0; segment->applied_rate = 1.0; segment->format = format; - segment->flags = 0; + segment->base = 0; segment->start = 0; segment->stop = -1; segment->time = 0; - segment->accum = 0; - segment->last_stop = 0; + segment->position = 0; segment->duration = -1; } /** - * gst_segment_set_duration: - * @segment: a #GstSegment structure. - * @format: the format of the segment. - * @duration: the duration of the segment info or -1 if unknown. - * - * Set the duration of the segment to @duration. This function is mainly - * used by elements that perform seeking and know the total duration of the - * segment. - * - * This field should be set to allow seeking requests relative to the - * duration. - */ -void -gst_segment_set_duration (GstSegment * segment, GstFormat format, - gint64 duration) -{ - g_return_if_fail (segment != NULL); - - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; - else - g_return_if_fail (segment->format == format); - - segment->duration = duration; -} - -/** - * gst_segment_set_last_stop: - * @segment: a #GstSegment structure. - * @format: the format of the segment. - * @position: the position - * - * Set the last observed stop position in the segment to @position. - * - * This field should be set to allow seeking requests relative to the - * current playing position. - */ -void -gst_segment_set_last_stop (GstSegment * segment, GstFormat format, - gint64 position) -{ - g_return_if_fail (segment != NULL); - - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; - else - g_return_if_fail (segment->format == format); - - segment->last_stop = MAX (segment->start, position); -} - -/** - * gst_segment_set_seek: + * gst_segment_do_seek: * @segment: a #GstSegment structure. * @rate: the rate of the segment. * @format: the format of the segment. - * @flags: the seek flags for the segment + * @flags: the segment flags for the segment * @start_type: the seek method * @start: the seek start value * @stop_type: the seek method * @stop: the seek stop value - * @update: boolean holding whether last_stop was updated. + * @update: boolean holding whether position was updated. * * Update the segment structure with the field values of a seek event (see * gst_event_new_seek()). * - * After calling this method, the segment field last_stop and time will + * After calling this method, the segment field position and time will * contain the requested new position in the segment. The new requested - * position in the segment depends on @rate and @start_type and @stop_type. + * position in the segment depends on @rate and @start_type and @stop_type. * * For positive @rate, the new position in the segment is the new @segment * start field when it was updated with a @start_type different from * #GST_SEEK_TYPE_NONE. If no update was performed on @segment start position - * (#GST_SEEK_TYPE_NONE), @start is ignored and @segment last_stop is + * (#GST_SEEK_TYPE_NONE), @start is ignored and @segment position is * unmodified. * * For negative @rate, the new position in the segment is the new @segment @@ -263,33 +217,43 @@ gst_segment_set_last_stop (GstSegment * segment, GstFormat format, * #GST_SEEK_TYPE_NONE. If no stop was previously configured in the segment, the * duration of the segment will be used to update the stop position. * If no update was performed on @segment stop position (#GST_SEEK_TYPE_NONE), - * @stop is ignored and @segment last_stop is unmodified. + * @stop is ignored and @segment position is unmodified. * * The applied rate of the segment will be set to 1.0 by default. * If the caller can apply a rate change, it should update @segment * rate and applied_rate after calling this function. * - * @update will be set to TRUE if a seek should be performed to the segment - * last_stop field. This field can be FALSE if, for example, only the @rate + * @update will be set to TRUE if a seek should be performed to the segment + * position field. This field can be FALSE if, for example, only the @rate * has been changed but not the playback position. + * + * Returns: %TRUE if the seek could be performed. */ -void -gst_segment_set_seek (GstSegment * segment, gdouble rate, +gboolean +gst_segment_do_seek (GstSegment * segment, gdouble rate, GstFormat format, GstSeekFlags flags, - GstSeekType start_type, gint64 start, - GstSeekType stop_type, gint64 stop, gboolean * update) + GstSeekType start_type, guint64 start, + GstSeekType stop_type, guint64 stop, gboolean * update) { gboolean update_stop, update_start; - gint64 last_stop; - - g_return_if_fail (rate != 0.0); - g_return_if_fail (segment != NULL); + guint64 position, base; - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; + g_return_val_if_fail (rate != 0.0, FALSE); + g_return_val_if_fail (segment != NULL, FALSE); + g_return_val_if_fail (segment->format == format, FALSE); update_start = update_stop = TRUE; + base = segment->base; + position = segment->position; + + if (flags & GST_SEEK_FLAG_FLUSH) { + /* flush resets the running_time */ + base = 0; + } else { + base = gst_segment_to_running_time (segment, format, position); + } + /* segment->start is never invalid */ switch (start_type) { case GST_SEEK_TYPE_NONE: @@ -302,16 +266,13 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate, if (start == -1) start = 0; /* start must be 0 or the formats must match */ - g_return_if_fail (start == 0 || segment->format == format); break; case GST_SEEK_TYPE_CUR: - g_return_if_fail (start == 0 || segment->format == format); /* add start to currently configured segment */ start = segment->start + start; break; case GST_SEEK_TYPE_END: if (segment->duration != -1) { - g_return_if_fail (start == 0 || segment->format == format); /* add start to total length */ start = segment->duration + start; } else { @@ -336,12 +297,10 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate, case GST_SEEK_TYPE_SET: /* stop holds required value, if it's not -1, it must be of the same * format as the segment. */ - g_return_if_fail (stop == -1 || segment->format == format); break; case GST_SEEK_TYPE_CUR: if (segment->stop != -1) { /* only add compatible formats or 0 */ - g_return_if_fail (stop == 0 || segment->format == format); stop = segment->stop + stop; } else stop = -1; @@ -349,7 +308,6 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate, case GST_SEEK_TYPE_END: if (segment->duration != -1) { /* only add compatible formats or 0 */ - g_return_if_fail (stop == 0 || segment->format == format); stop = segment->duration + stop; } else { stop = segment->stop; @@ -367,145 +325,42 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate, } /* we can't have stop before start */ - if (stop != -1) - g_return_if_fail (start <= stop); + if (stop != -1) { + if (start > stop) { + g_return_val_if_fail (start <= stop, FALSE); + return FALSE; + } + } segment->rate = rate; segment->applied_rate = 1.0; + segment->base = base; segment->flags = flags; segment->start = start; segment->stop = stop; segment->time = start; - last_stop = segment->last_stop; if (update_start && rate > 0.0) { - last_stop = start; + position = start; } if (update_stop && rate < 0.0) { if (stop != -1) - last_stop = stop; + position = stop; else { if (segment->duration != -1) - last_stop = segment->duration; + position = segment->duration; else - last_stop = 0; + position = 0; } } - /* set update arg to reflect update of last_stop */ + /* set update arg to reflect update of position */ if (update) - *update = last_stop != segment->last_stop; + *update = position != segment->position; /* update new position */ - segment->last_stop = last_stop; -} - -/** - * gst_segment_set_newsegment: - * @segment: a #GstSegment structure. - * @update: flag indicating a new segment is started or updated - * @rate: the rate of the segment. - * @applied_rate: the applied rate of the segment. - * @format: the format of the segment. - * @start: the new start value - * @stop: the new stop value - * @time: the new stream time - * - * Update the segment structure with the field values of a new segment event. - */ -void -gst_segment_set_newsegment (GstSegment * segment, gboolean update, - gdouble rate, gdouble applied_rate, GstFormat format, gint64 start, - gint64 stop, gint64 time) -{ - gint64 duration, last_stop; - gdouble abs_rate; - - g_return_if_fail (rate != 0.0); - g_return_if_fail (applied_rate != 0.0); - g_return_if_fail (segment != NULL); - - GST_DEBUG ("configuring segment update %d, rate %lf, format %s, " - "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", position %" - G_GINT64_FORMAT, update, rate, gst_format_get_name (format), start, - stop, time); - GST_DEBUG ("old segment was: %" GST_SEGMENT_FORMAT, segment); - - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; - - /* any other format with 0 also gives time 0, the other values are - * invalid in the format though. */ - if (format != segment->format && start == 0) { - format = segment->format; - if (stop != 0) - stop = -1; - if (time != 0) - time = -1; - } - - g_return_if_fail (segment->format == format); - - if (update) { - if (G_LIKELY (segment->rate > 0.0)) { - /* an update to the current segment is done, elapsed time is - * difference between the old start and new start. */ - if (start > segment->start) - duration = start - segment->start; - else - duration = 0; - } else { - /* for negative rates, the elapsed duration is the diff between the stop - * positions */ - if (stop != -1 && stop < segment->stop) - duration = segment->stop - stop; - else - duration = 0; - } - /* update last_stop to be a valid value in the updated segment */ - if (start > segment->last_stop) - last_stop = start; - else if (stop != -1 && stop < segment->last_stop) - last_stop = stop; - else - last_stop = segment->last_stop; - } else { - /* the new segment has to be aligned with the old segment. - * We first update the accumulated time of the previous - * segment. the accumulated time is used when syncing to the - * clock. */ - if (segment->stop != -1) { - duration = segment->stop - segment->start; - } else if (segment->last_stop != -1) { - /* else use last seen timestamp as segment stop */ - duration = segment->last_stop - segment->start; - } else { - /* else we don't know and throw a warning.. really, this should - * be fixed in the element. */ - g_warning ("closing segment of unknown duration, assuming duration of 0"); - duration = 0; - } - /* position the last_stop to the next expected position in the new segment, - * which is the start or the stop of the segment */ - if (rate > 0.0) - last_stop = start; - else - last_stop = stop; - } - /* use previous rate to calculate duration */ - abs_rate = ABS (segment->rate); - if (G_LIKELY (abs_rate != 1.0)) - duration /= abs_rate; - - /* accumulate duration */ - segment->accum += duration; + segment->position = position; - /* then update the current segment */ - segment->rate = rate; - segment->applied_rate = applied_rate; - segment->start = start; - segment->last_stop = last_stop; - segment->stop = stop; - segment->time = time; + return TRUE; } /** @@ -514,25 +369,25 @@ gst_segment_set_newsegment (GstSegment * segment, gboolean update, * @format: the format of the segment. * @position: the position in the segment * - * Translate @position to stream time using the currently configured + * Translate @position to stream time using the currently configured * segment. The @position value must be between @segment start and - * stop value. + * stop value. * * This function is typically used by elements that need to operate on * the stream time of the buffers it receives, such as effect plugins. - * In those use cases, @position is typically the buffer timestamp or + * In those use cases, @position is typically the buffer timestamp or * clock time that one wants to convert to the stream time. - * The stream time is always between 0 and the total duration of the - * media stream. + * The stream time is always between 0 and the total duration of the + * media stream. * * Returns: the position in stream_time or -1 when an invalid position * was given. */ -gint64 -gst_segment_to_stream_time (GstSegment * segment, GstFormat format, - gint64 position) +guint64 +gst_segment_to_stream_time (const GstSegment * segment, GstFormat format, + guint64 position) { - gint64 result, start, stop, time; + guint64 result, start, stop, time; gdouble abs_applied_rate; /* format does not matter for -1 */ @@ -540,9 +395,7 @@ gst_segment_to_stream_time (GstSegment * segment, GstFormat format, return -1; g_return_val_if_fail (segment != NULL, -1); - - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; + g_return_val_if_fail (segment->format == format, -1); /* if we have the position for the same format as the segment, we can compare * the start and stop values, otherwise we assume 0 and -1 */ @@ -600,7 +453,7 @@ gst_segment_to_stream_time (GstSegment * segment, GstFormat format, * @format: the format of the segment. * @position: the position in the segment * - * Translate @position to the total running time using the currently configured + * Translate @position to the total running time using the currently configured * and previously accumulated segments. Position is a value between @segment * start and stop time. * @@ -614,32 +467,30 @@ gst_segment_to_stream_time (GstSegment * segment, GstFormat format, * Returns: the position as the total running time or -1 when an invalid position * was given. */ -gint64 -gst_segment_to_running_time (GstSegment * segment, GstFormat format, - gint64 position) +guint64 +gst_segment_to_running_time (const GstSegment * segment, GstFormat format, + guint64 position) { - gint64 result; - gint64 start, stop, accum; + guint64 result; + guint64 start, stop, base; gdouble abs_rate; if (G_UNLIKELY (position == -1)) return -1; g_return_val_if_fail (segment != NULL, -1); - - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; + g_return_val_if_fail (segment->format == format, -1); /* if we have the position for the same format as the segment, we can compare * the start and stop values, otherwise we assume 0 and -1 */ if (G_LIKELY (segment->format == format)) { start = segment->start; stop = segment->stop; - accum = segment->accum; + base = segment->base; } else { start = 0; stop = -1; - accum = 0; + base = 0; } /* before the segment boundary */ @@ -663,14 +514,14 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format, result = stop - position; } - /* scale based on the rate, avoid division by and conversion to + /* scale based on the rate, avoid division by and conversion to * float when not needed */ abs_rate = ABS (segment->rate); if (G_UNLIKELY (abs_rate != 1.0)) result /= abs_rate; - /* correct for accumulated segments */ - result += accum; + /* correct for base of the segment */ + result += base; return result; } @@ -685,7 +536,7 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format, * @clip_stop: (out) (allow-none): the clipped stop position in the segment * * Clip the given @start and @stop values to the segment boundaries given - * in @segment. @start and @stop are compared and clipped to @segment + * in @segment. @start and @stop are compared and clipped to @segment * start and stop values. * * If the function returns FALSE, @start and @stop are known to fall @@ -698,22 +549,18 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format, * Note that when @stop is -1, @clip_stop will be set to the end of the * segment. Depending on the use case, this may or may not be what you want. * - * Returns: TRUE if the given @start and @stop times fall partially or - * completely in @segment, FALSE if the values are completely outside + * Returns: TRUE if the given @start and @stop times fall partially or + * completely in @segment, FALSE if the values are completely outside * of the segment. */ gboolean -gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start, - gint64 stop, gint64 * clip_start, gint64 * clip_stop) +gst_segment_clip (const GstSegment * segment, GstFormat format, guint64 start, + guint64 stop, guint64 * clip_start, guint64 * clip_stop) { g_return_val_if_fail (segment != NULL, FALSE); + g_return_val_if_fail (segment->format == format, FALSE); - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; - else - g_return_val_if_fail (segment->format == format, FALSE); - - /* if we have a stop position and a valid start and start is bigger, + /* if we have a stop position and a valid start and start is bigger, * we're outside of the segment */ if (G_UNLIKELY (segment->stop != -1 && start != -1 && start >= segment->stop)) return FALSE; @@ -737,11 +584,11 @@ gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start, if (stop == -1) *clip_stop = segment->stop; else if (segment->stop == -1) - *clip_stop = MAX (-1, stop); + *clip_stop = stop; else *clip_stop = MIN (stop, segment->stop); - if (segment->duration != -1) + if (segment->duration != -1 && *clip_stop != -1) *clip_stop = MIN (*clip_stop, segment->duration); } @@ -762,40 +609,38 @@ gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start, * * Since: 0.10.24 */ -gint64 -gst_segment_to_position (GstSegment * segment, GstFormat format, - gint64 running_time) +guint64 +gst_segment_to_position (const GstSegment * segment, GstFormat format, + guint64 running_time) { - gint64 result; - gint64 start, stop, accum; + guint64 result; + guint64 start, stop, base; gdouble abs_rate; - g_return_val_if_fail (segment != NULL, -1); - if (G_UNLIKELY (running_time == -1)) return -1; - if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED)) - segment->format = format; + g_return_val_if_fail (segment != NULL, -1); + g_return_val_if_fail (segment->format == format, FALSE); /* if we have the position for the same format as the segment, we can compare * the start and stop values, otherwise we assume 0 and -1 */ if (G_LIKELY (segment->format == format)) { start = segment->start; stop = segment->stop; - accum = segment->accum; + base = segment->base; } else { start = 0; stop = -1; - accum = 0; + base = 0; } /* this running_time was for a previous segment */ - if (running_time < accum) + if (running_time < base) return -1; - /* start by subtracting the accumulated time */ - result = running_time - accum; + /* start by subtracting the base time */ + result = running_time - base; /* move into the segment at the right rate */ abs_rate = ABS (segment->rate); @@ -828,7 +673,7 @@ gst_segment_to_position (GstSegment * segment, GstFormat format, * @format: the format of the segment. * @running_time: the running_time in the segment * - * Adjust the start/stop and accum values of @segment such that the next valid + * Adjust the start/stop and base values of @segment such that the next valid * buffer will be one with @running_time. * * Returns: %TRUE if the segment could be updated successfully. If %FALSE is @@ -838,10 +683,10 @@ gst_segment_to_position (GstSegment * segment, GstFormat format, */ gboolean gst_segment_set_running_time (GstSegment * segment, GstFormat format, - gint64 running_time) + guint64 running_time) { - gint64 position; - gint64 start, stop, last_stop; + guint64 position; + guint64 start, stop; /* start by bringing the running_time into the segment position */ position = gst_segment_to_position (segment, format, running_time); @@ -852,26 +697,19 @@ gst_segment_set_running_time (GstSegment * segment, GstFormat format, start = segment->start; stop = segment->stop; - last_stop = segment->last_stop; if (G_LIKELY (segment->rate > 0.0)) { - /* update the start/last_stop and time values */ + /* update the start and time values */ start = position; - if (last_stop < start) - last_stop = start; } else { /* reverse, update stop */ stop = position; - /* if we were past the position, go back */ - if (last_stop > stop) - last_stop = stop; } - /* and accumulated time is exactly the running time */ + /* and base time is exactly the running time */ segment->time = gst_segment_to_stream_time (segment, format, start); segment->start = start; segment->stop = stop; - segment->last_stop = last_stop; - segment->accum = running_time; + segment->base = running_time; return TRUE; } |