2 * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
4 * gstsegment.c: GstSegment subsystem
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 #include "gst_private.h"
26 #include "gstsegment.h"
30 * @short_description: Structure describing the configured region of interest
32 * @see_also: #GstEvent
34 * This helper structure holds the relevant values for tracking the region of
35 * interest in a media file, called a segment.
37 * Last reviewed on 2005-20-09 (0.9.5)
41 gst_segment_copy (GstSegment * segment)
43 GstSegment *result = NULL;
46 result = gst_segment_new ();
47 memcpy (result, segment, sizeof (GstSegment));
53 gst_segment_get_type (void)
55 static GType gst_segment_type = 0;
57 if (!gst_segment_type) {
58 gst_segment_type = g_boxed_type_register_static ("GstSegment",
59 (GBoxedCopyFunc) gst_segment_copy, (GBoxedFreeFunc) gst_segment_free);
62 return gst_segment_type;
68 * Allocate a new #GstSegment structure and initialize it using
71 * Returns: a new #GstSegment, free with gst_segment_free().
74 gst_segment_new (void)
78 result = g_new0 (GstSegment, 1);
79 gst_segment_init (result, GST_FORMAT_UNDEFINED);
86 * @segment: a #GstSegment
88 * Free the allocated segment @segment.
91 gst_segment_free (GstSegment * segment)
98 * @segment: a #GstSegment structure.
99 * @format: the format of the segment.
101 * Initialize @segment to its default values, which is a rate of 1.0, a
105 gst_segment_init (GstSegment * segment, GstFormat format)
107 g_return_if_fail (segment != NULL);
110 segment->abs_rate = 1.0;
111 segment->format = format;
117 segment->last_stop = -1;
118 segment->duration = -1;
122 * gst_segment_set_duration:
123 * @segment: a #GstSegment structure.
124 * @format: the format of the segment.
125 * @duration: the duration of the segment info.
127 * Set the duration of the segment to @duration. This function is mainly
128 * used by elements that perform seeking and know the total duration of the
132 gst_segment_set_duration (GstSegment * segment, GstFormat format,
135 g_return_if_fail (segment != NULL);
137 if (segment->format == GST_FORMAT_UNDEFINED)
138 segment->format = format;
140 g_return_if_fail (segment->format == format);
142 segment->duration = duration;
146 * gst_segment_set_last_stop:
147 * @segment: a #GstSegment structure.
148 * @format: the format of the segment.
149 * @position: the position
151 * Set the last observed stop position in the segment to @position.
154 gst_segment_set_last_stop (GstSegment * segment, GstFormat format,
157 g_return_if_fail (segment != NULL);
159 if (segment->format == GST_FORMAT_UNDEFINED)
160 segment->format = format;
162 g_return_if_fail (segment->format == format);
164 segment->last_stop = position;
168 * gst_segment_set_seek:
169 * @segment: a #GstSegment structure.
170 * @rate: the rate of the segment.
171 * @format: the format of the segment.
172 * @flags: the seek flags for the segment
173 * @cur_type: the seek method
174 * @cur: the seek start value
175 * @stop_type: the seek method
176 * @stop: the seek stop value
177 * @update: boolean holding whether an update the current segment is
180 * Update the segment structure with the field values of a seek event.
183 gst_segment_set_seek (GstSegment * segment, gdouble rate,
184 GstFormat format, GstSeekFlags flags,
185 GstSeekType cur_type, gint64 cur,
186 GstSeekType stop_type, gint64 stop, gboolean * update)
188 gboolean update_stop, update_start;
190 g_return_if_fail (rate != 0.0);
191 g_return_if_fail (segment != NULL);
193 if (segment->format == GST_FORMAT_UNDEFINED)
194 segment->format = format;
196 g_return_if_fail (segment->format == format);
198 update_stop = update_start = TRUE;
200 /* start is never invalid */
202 case GST_SEEK_TYPE_NONE:
203 /* no update to segment */
204 cur = segment->start;
205 update_start = FALSE;
207 case GST_SEEK_TYPE_SET:
208 /* cur holds desired position */
210 case GST_SEEK_TYPE_CUR:
211 /* add cur to currently configure segment */
212 cur = segment->start + cur;
214 case GST_SEEK_TYPE_END:
215 if (segment->duration != -1) {
216 /* add cur to total length */
217 cur = segment->duration + cur;
219 /* no update if duration unknown */
220 cur = segment->start;
221 update_start = FALSE;
225 /* bring in sane range */
226 if (segment->duration != -1)
227 cur = CLAMP (cur, 0, segment->duration);
231 /* stop can be -1 if we have not configured a stop. */
233 case GST_SEEK_TYPE_NONE:
234 stop = segment->stop;
237 case GST_SEEK_TYPE_SET:
238 /* stop folds required value */
240 case GST_SEEK_TYPE_CUR:
241 if (segment->stop != -1)
242 stop = segment->stop + stop;
246 case GST_SEEK_TYPE_END:
247 if (segment->duration != -1)
248 stop = segment->duration + stop;
250 stop = segment->stop;
256 /* if we have a valid stop time, make sure it is clipped */
258 if (segment->duration != -1)
259 stop = CLAMP (stop, 0, segment->duration);
261 stop = MAX (stop, 0);
264 /* we can't have stop before start */
266 g_return_if_fail (cur <= stop);
268 segment->rate = rate;
269 segment->abs_rate = ABS (rate);
270 segment->flags = flags;
271 segment->start = cur;
272 segment->stop = stop;
275 *update = update_start || update_stop;
279 * gst_segment_set_newsegment:
280 * @segment: a #GstSegment structure.
281 * @update: flag indicating a new segment is started or updated
282 * @rate: the rate of the segment.
283 * @format: the format of the segment.
284 * @start: the new start value
285 * @stop: the new stop value
286 * @time: the new stream time
288 * Update the segment structure with the field values of a new segment event.
291 gst_segment_set_newsegment (GstSegment * segment, gboolean update, gdouble rate,
292 GstFormat format, gint64 start, gint64 stop, gint64 time)
296 g_return_if_fail (rate != 0.0);
297 g_return_if_fail (segment != NULL);
299 if (segment->format == GST_FORMAT_UNDEFINED)
300 segment->format = format;
302 /* any other format with 0 also gives time 0, the other values are
303 * invalid in the format though. */
304 if (format != segment->format && start == 0) {
305 format = segment->format;
312 g_return_if_fail (segment->format == format);
315 /* an update to the current segment is done, elapsed time is
316 * difference between the old start and new start. */
317 duration = start - segment->start;
319 /* the new segment has to be aligned with the old segment.
320 * We first update the accumulated time of the previous
321 * segment. the accumulated time is used when syncing to the
324 if (GST_CLOCK_TIME_IS_VALID (segment->stop)) {
325 duration = segment->stop - segment->start;
326 } else if (GST_CLOCK_TIME_IS_VALID (segment->last_stop)) {
327 /* else use last seen timestamp as segment stop */
328 duration = segment->last_stop - segment->start;
330 /* else we don't know */
334 /* use previous rate to calculate duration */
335 segment->accum += gst_gdouble_to_guint64 (
336 (gst_guint64_to_gdouble (duration) / segment->abs_rate));
337 /* then update the current segment */
338 segment->rate = rate;
339 segment->abs_rate = ABS (rate);
340 segment->start = start;
341 segment->stop = stop;
342 segment->time = time;
346 * gst_segment_to_stream_time:
347 * @segment: a #GstSegment structure.
348 * @format: the format of the segment.
349 * @position: the position in the segment
351 * Translate @position to stream time using the currently configured
354 * This function is typically used by elements that need to operate on
355 * the stream time of the buffers it receives, such as effect plugins.
357 * Returns: the position in stream_time.
360 gst_segment_to_stream_time (GstSegment * segment, GstFormat format,
365 g_return_val_if_fail (segment != NULL, FALSE);
367 if (segment->format == GST_FORMAT_UNDEFINED)
368 segment->format = format;
370 g_return_val_if_fail (segment->format == format, FALSE);
372 if ((time = segment->time) == -1)
376 result = ((position - segment->start) / segment->abs_rate) + time;
384 * gst_segment_to_running_time:
385 * @segment: a #GstSegment structure.
386 * @format: the format of the segment.
387 * @position: the position in the segment
389 * Translate @position to the total running time using the currently configured
392 * This function is typically used by elements that need to synchronize to the
393 * global clock in a pipeline.
395 * Returns: the position as the total running time.
398 gst_segment_to_running_time (GstSegment * segment, GstFormat format,
403 g_return_val_if_fail (segment != NULL, -1);
405 if (segment->format == GST_FORMAT_UNDEFINED)
406 segment->format = format;
408 g_return_val_if_fail (segment->format == format, -1);
411 result = ((position - segment->start) / segment->abs_rate) + segment->accum;
420 * @segment: a #GstSegment structure.
421 * @format: the format of the segment.
422 * @start: the start position in the segment
423 * @stop: the stop position in the segment
424 * @clip_start: the clipped start position in the segment
425 * @clip_stop: the clipped stop position in the segment
427 * Clip the given @start and @stop values to the segment boundaries given
430 * Returns: TRUE if the given @start and @stop times fall partially in
431 * @segment, FALSE if the values are completely outside of the segment.
434 gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start,
435 gint64 stop, gint64 * clip_start, gint64 * clip_stop)
437 g_return_val_if_fail (segment != NULL, FALSE);
439 if (segment->format == GST_FORMAT_UNDEFINED)
440 segment->format = format;
442 g_return_val_if_fail (segment->format == format, FALSE);
444 /* we need a valid start position */
448 /* if we have a stop position and start is bigger, we're
449 * outside of the segment */
450 if (segment->stop != -1 && start >= segment->stop)
453 /* if a stop position is given and is before the segment start,
454 * we're outside of the segment */
455 if (stop != -1 && stop <= segment->start)
459 *clip_start = MAX (start, segment->start);
463 *clip_stop = segment->stop;
464 else if (segment->stop == -1)
465 *clip_stop = MAX (-1, stop);
467 *clip_stop = MIN (stop, segment->stop);
469 if (segment->duration != -1)
470 *clip_stop = MIN (*clip_stop, segment->duration);