gstreamer_core/gst/gstsegment.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
       
     3  *
       
     4  * gstsegment.c: GstSegment subsystem
       
     5  *
       
     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.
       
    10  *
       
    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.
       
    15  *
       
    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.
       
    20  */
       
    21 
       
    22 
       
    23 #include "gst_private.h"
       
    24 
       
    25 #include "gstutils.h"
       
    26 #include "gstsegment.h"
       
    27 
       
    28 /**
       
    29  * SECTION:gstsegment
       
    30  * @short_description: Structure describing the configured region of interest
       
    31  *                     in a media file.
       
    32  * @see_also: #GstEvent
       
    33  *
       
    34  * This helper structure holds the relevant values for tracking the region of
       
    35  * interest in a media file, called a segment. 
       
    36  *
       
    37  * The structure can be used for two purposes:
       
    38  * <itemizedlist>
       
    39  *   <listitem><para>performing seeks (handling seek events)</para></listitem>
       
    40  *   <listitem><para>tracking playback regions (handling newsegment events)</para></listitem>
       
    41  * </itemizedlist>
       
    42  *
       
    43  * The segment is usually configured by the application with a seek event which 
       
    44  * is propagated upstream and eventually handled by an element that performs the seek.
       
    45  *
       
    46  * The configured segment is then propagated back downstream with a newsegment event.
       
    47  * This information is then used to clip media to the segment boundaries.
       
    48  *
       
    49  * A segment structure is initialized with gst_segment_init(), which takes a #GstFormat
       
    50  * that will be used as the format of the segment values. The segment will be configured
       
    51  * with a start value of 0 and a stop/duration of -1, which is undefined. The default
       
    52  * rate and applied_rate is 1.0.
       
    53  *
       
    54  * If the segment is used for managing seeks, the segment duration should be set with
       
    55  * gst_segment_set_duration(). The public duration field contains the duration of the
       
    56  * segment. When using the segment for seeking, the start and time members should 
       
    57  * normally be left to their default 0 value. The stop position is left to -1 unless
       
    58  * explicitly configured to a different value after a seek event.
       
    59  *
       
    60  * The current position in the segment should be set with the gst_segment_set_last_stop().
       
    61  * The public last_stop field contains the last set stop position in the segment.
       
    62  *
       
    63  * For elements that perform seeks, the current segment should be updated with the
       
    64  * gst_segment_set_seek() and the values from the seek event. This method will update
       
    65  * all the segment fields. The last_stop field will contain the new playback position.
       
    66  * If the cur_type was different from GST_SEEK_TYPE_NONE, playback continues from
       
    67  * the last_stop position, possibly with updated flags or rate.
       
    68  *
       
    69  * For elements that want to use #GstSegment to track the playback region, use
       
    70  * gst_segment_set_newsegment() to update the segment fields with the information from
       
    71  * the newsegment event. The gst_segment_clip() method can be used to check and clip
       
    72  * the media data to the segment boundaries.
       
    73  *
       
    74  * For elements that want to synchronize to the pipeline clock, gst_segment_to_running_time()
       
    75  * can be used to convert a timestamp to a value that can be used to synchronize
       
    76  * to the clock. This function takes into account all accumulated segments as well as
       
    77  * any rate or applied_rate conversions.
       
    78  *
       
    79  * For elements that need to perform operations on media data in stream_time, 
       
    80  * gst_segment_to_stream_time() can be used to convert a timestamp and the segment
       
    81  * info to stream time (which is always between 0 and the duration of the stream).
       
    82  *
       
    83  * Last reviewed on 2007-05-17 (0.10.13)
       
    84  */
       
    85 
       
    86 static GstSegment *
       
    87 gst_segment_copy (GstSegment * segment)
       
    88 {
       
    89   GstSegment *result = NULL;
       
    90 
       
    91   if (segment) {
       
    92     result = gst_segment_new ();
       
    93     memcpy (result, segment, sizeof (GstSegment));
       
    94   }
       
    95   return result;
       
    96 }
       
    97 #ifdef __SYMBIAN32__
       
    98 EXPORT_C
       
    99 #endif
       
   100 
       
   101 
       
   102 GType
       
   103 gst_segment_get_type (void)
       
   104 {
       
   105   static GType gst_segment_type = 0;
       
   106 
       
   107   if (G_UNLIKELY (gst_segment_type == 0)) {
       
   108     gst_segment_type = g_boxed_type_register_static ("GstSegment",
       
   109         (GBoxedCopyFunc) gst_segment_copy, (GBoxedFreeFunc) gst_segment_free);
       
   110   }
       
   111 
       
   112   return gst_segment_type;
       
   113 }
       
   114 
       
   115 /**
       
   116  * gst_segment_new:
       
   117  *
       
   118  * Allocate a new #GstSegment structure and initialize it using 
       
   119  * gst_segment_init().
       
   120  *
       
   121  * Returns: a new #GstSegment, free with gst_segment_free().
       
   122  */
       
   123 #ifdef __SYMBIAN32__
       
   124 EXPORT_C
       
   125 #endif
       
   126 
       
   127 GstSegment *
       
   128 gst_segment_new (void)
       
   129 {
       
   130   GstSegment *result;
       
   131 
       
   132   result = g_new0 (GstSegment, 1);
       
   133   gst_segment_init (result, GST_FORMAT_UNDEFINED);
       
   134 
       
   135   return result;
       
   136 }
       
   137 
       
   138 /**
       
   139  * gst_segment_free:
       
   140  * @segment: a #GstSegment
       
   141  *
       
   142  * Free the allocated segment @segment.
       
   143  */
       
   144 #ifdef __SYMBIAN32__
       
   145 EXPORT_C
       
   146 #endif
       
   147 
       
   148 void
       
   149 gst_segment_free (GstSegment * segment)
       
   150 {
       
   151   g_free (segment);
       
   152 }
       
   153 
       
   154 /**
       
   155  * gst_segment_init:
       
   156  * @segment: a #GstSegment structure.
       
   157  * @format: the format of the segment.
       
   158  *
       
   159  * The start/last_stop positions are set to 0 and the stop/duration
       
   160  * fields are set to -1 (unknown). The default rate of 1.0 and no
       
   161  * flags are set.
       
   162  *
       
   163  * Initialize @segment to its default values.
       
   164  */
       
   165 #ifdef __SYMBIAN32__
       
   166 EXPORT_C
       
   167 #endif
       
   168 
       
   169 void
       
   170 gst_segment_init (GstSegment * segment, GstFormat format)
       
   171 {
       
   172   g_return_if_fail (segment != NULL);
       
   173 
       
   174   segment->rate = 1.0;
       
   175   segment->abs_rate = 1.0;
       
   176   segment->applied_rate = 1.0;
       
   177   segment->format = format;
       
   178   segment->flags = 0;
       
   179   segment->start = 0;
       
   180   segment->stop = -1;
       
   181   segment->time = 0;
       
   182   segment->accum = 0;
       
   183   segment->last_stop = 0;
       
   184   segment->duration = -1;
       
   185 }
       
   186 
       
   187 /**
       
   188  * gst_segment_set_duration:
       
   189  * @segment: a #GstSegment structure.
       
   190  * @format: the format of the segment.
       
   191  * @duration: the duration of the segment info or -1 if unknown.
       
   192  *
       
   193  * Set the duration of the segment to @duration. This function is mainly
       
   194  * used by elements that perform seeking and know the total duration of the
       
   195  * segment. 
       
   196  * 
       
   197  * This field should be set to allow seeking requests relative to the
       
   198  * duration.
       
   199  */
       
   200 #ifdef __SYMBIAN32__
       
   201 EXPORT_C
       
   202 #endif
       
   203 
       
   204 void
       
   205 gst_segment_set_duration (GstSegment * segment, GstFormat format,
       
   206     gint64 duration)
       
   207 {
       
   208   g_return_if_fail (segment != NULL);
       
   209 
       
   210   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   211     segment->format = format;
       
   212   else
       
   213     g_return_if_fail (segment->format == format);
       
   214 
       
   215   segment->duration = duration;
       
   216 }
       
   217 
       
   218 /**
       
   219  * gst_segment_set_last_stop:
       
   220  * @segment: a #GstSegment structure.
       
   221  * @format: the format of the segment.
       
   222  * @position: the position 
       
   223  *
       
   224  * Set the last observed stop position in the segment to @position.
       
   225  *
       
   226  * This field should be set to allow seeking requests relative to the
       
   227  * current playing position.
       
   228  */
       
   229 #ifdef __SYMBIAN32__
       
   230 EXPORT_C
       
   231 #endif
       
   232 
       
   233 void
       
   234 gst_segment_set_last_stop (GstSegment * segment, GstFormat format,
       
   235     gint64 position)
       
   236 {
       
   237   g_return_if_fail (segment != NULL);
       
   238 
       
   239   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   240     segment->format = format;
       
   241   else
       
   242     g_return_if_fail (segment->format == format);
       
   243 
       
   244   segment->last_stop = MAX (segment->start, position);
       
   245 }
       
   246 
       
   247 /**
       
   248  * gst_segment_set_seek:
       
   249  * @segment: a #GstSegment structure.
       
   250  * @rate: the rate of the segment.
       
   251  * @format: the format of the segment.
       
   252  * @flags: the seek flags for the segment
       
   253  * @start_type: the seek method
       
   254  * @start: the seek start value
       
   255  * @stop_type: the seek method
       
   256  * @stop: the seek stop value
       
   257  * @update: boolean holding whether last_stop was updated.
       
   258  *
       
   259  * Update the segment structure with the field values of a seek event (see
       
   260  * gst_event_new_seek()).
       
   261  *
       
   262  * After calling this method, the segment field last_stop and time will
       
   263  * contain the requested new position in the segment. The new requested
       
   264  * position in the segment depends on @rate and @start_type and @stop_type. 
       
   265  *
       
   266  * For positive @rate, the new position in the segment is the new @segment
       
   267  * start field when it was updated with a @start_type different from
       
   268  * #GST_SEEK_TYPE_NONE. If no update was performed on @segment start position
       
   269  * (#GST_SEEK_TYPE_NONE), @start is ignored and @segment last_stop is
       
   270  * unmodified.
       
   271  *
       
   272  * For negative @rate, the new position in the segment is the new @segment
       
   273  * stop field when it was updated with a @stop_type different from
       
   274  * #GST_SEEK_TYPE_NONE. If no stop was previously configured in the segment, the
       
   275  * duration of the segment will be used to update the stop position.
       
   276  * If no update was performed on @segment stop position (#GST_SEEK_TYPE_NONE),
       
   277  * @stop is ignored and @segment last_stop is unmodified.
       
   278  *
       
   279  * The applied rate of the segment will be set to 1.0 by default.
       
   280  * If the caller can apply a rate change, it should update @segment
       
   281  * rate and applied_rate after calling this function.
       
   282  *
       
   283  * @update will be set to TRUE if a seek should be performed to the segment 
       
   284  * last_stop field. This field can be FALSE if, for example, only the @rate
       
   285  * has been changed but not the playback position.
       
   286  */
       
   287 #ifdef __SYMBIAN32__
       
   288 EXPORT_C
       
   289 #endif
       
   290 
       
   291 void
       
   292 gst_segment_set_seek (GstSegment * segment, gdouble rate,
       
   293     GstFormat format, GstSeekFlags flags,
       
   294     GstSeekType start_type, gint64 start,
       
   295     GstSeekType stop_type, gint64 stop, gboolean * update)
       
   296 {
       
   297   gboolean update_stop, update_start;
       
   298   gint64 last_stop;
       
   299 
       
   300   g_return_if_fail (rate != 0.0);
       
   301   g_return_if_fail (segment != NULL);
       
   302 
       
   303   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   304     segment->format = format;
       
   305 
       
   306   update_start = update_stop = TRUE;
       
   307 
       
   308   /* segment->start is never invalid */
       
   309   switch (start_type) {
       
   310     case GST_SEEK_TYPE_NONE:
       
   311       /* no update to segment, take previous start */
       
   312       start = segment->start;
       
   313       update_start = FALSE;
       
   314       break;
       
   315     case GST_SEEK_TYPE_SET:
       
   316       /* start holds desired position, map -1 to the start */
       
   317       if (start == -1)
       
   318         start = 0;
       
   319       /* start must be 0 or the formats must match */
       
   320       g_return_if_fail (start == 0 || segment->format == format);
       
   321       break;
       
   322     case GST_SEEK_TYPE_CUR:
       
   323       g_return_if_fail (start == 0 || segment->format == format);
       
   324       /* add start to currently configured segment */
       
   325       start = segment->start + start;
       
   326       break;
       
   327     case GST_SEEK_TYPE_END:
       
   328       if (segment->duration != -1) {
       
   329         g_return_if_fail (start == 0 || segment->format == format);
       
   330         /* add start to total length */
       
   331         start = segment->duration + start;
       
   332       } else {
       
   333         /* no update if duration unknown */
       
   334         start = segment->start;
       
   335         update_start = FALSE;
       
   336       }
       
   337       break;
       
   338   }
       
   339   /* bring in sane range */
       
   340   if (segment->duration != -1)
       
   341     start = CLAMP (start, 0, segment->duration);
       
   342   else
       
   343     start = MAX (start, 0);
       
   344 
       
   345   /* stop can be -1 if we have not configured a stop. */
       
   346   switch (stop_type) {
       
   347     case GST_SEEK_TYPE_NONE:
       
   348       stop = segment->stop;
       
   349       update_stop = FALSE;
       
   350       break;
       
   351     case GST_SEEK_TYPE_SET:
       
   352       /* stop holds required value, if it's not -1, it must be of the same
       
   353        * format as the segment. */
       
   354       g_return_if_fail (stop == -1 || segment->format == format);
       
   355       break;
       
   356     case GST_SEEK_TYPE_CUR:
       
   357       if (segment->stop != -1) {
       
   358         /* only add compatible formats or 0 */
       
   359         g_return_if_fail (stop == 0 || segment->format == format);
       
   360         stop = segment->stop + stop;
       
   361       } else
       
   362         stop = -1;
       
   363       break;
       
   364     case GST_SEEK_TYPE_END:
       
   365       if (segment->duration != -1) {
       
   366         /* only add compatible formats or 0 */
       
   367         g_return_if_fail (stop == 0 || segment->format == format);
       
   368         stop = segment->duration + stop;
       
   369       } else {
       
   370         stop = segment->stop;
       
   371         update_stop = FALSE;
       
   372       }
       
   373       break;
       
   374   }
       
   375 
       
   376   /* if we have a valid stop time, make sure it is clipped */
       
   377   if (stop != -1) {
       
   378     if (segment->duration != -1)
       
   379       stop = CLAMP (stop, 0, segment->duration);
       
   380     else
       
   381       stop = MAX (stop, 0);
       
   382   }
       
   383 
       
   384   /* we can't have stop before start */
       
   385   if (stop != -1)
       
   386     g_return_if_fail (start <= stop);
       
   387 
       
   388   segment->rate = rate;
       
   389   segment->abs_rate = ABS (rate);
       
   390   segment->applied_rate = 1.0;
       
   391   segment->flags = flags;
       
   392   segment->start = start;
       
   393   segment->stop = stop;
       
   394   segment->time = start;
       
   395 
       
   396   last_stop = segment->last_stop;
       
   397   if (update_start && rate > 0.0) {
       
   398     last_stop = start;
       
   399   }
       
   400   if (update_stop && rate < 0.0) {
       
   401     if (stop != -1)
       
   402       last_stop = stop;
       
   403     else {
       
   404       if (segment->duration != -1)
       
   405         last_stop = segment->duration;
       
   406       else
       
   407         last_stop = 0;
       
   408     }
       
   409   }
       
   410   /* set update arg to reflect update of last_stop */
       
   411   if (update)
       
   412     *update = last_stop != segment->last_stop;
       
   413 
       
   414   /* update new position */
       
   415   segment->last_stop = last_stop;
       
   416 }
       
   417 
       
   418 /**
       
   419  * gst_segment_set_newsegment:
       
   420  * @segment: a #GstSegment structure.
       
   421  * @update: flag indicating a new segment is started or updated
       
   422  * @rate: the rate of the segment.
       
   423  * @format: the format of the segment.
       
   424  * @start: the new start value
       
   425  * @stop: the new stop value
       
   426  * @time: the new stream time
       
   427  *
       
   428  * Update the segment structure with the field values of a new segment event and
       
   429  * with a default applied_rate of 1.0.
       
   430  *
       
   431  * Since: 0.10.6
       
   432  */
       
   433 #ifdef __SYMBIAN32__
       
   434 EXPORT_C
       
   435 #endif
       
   436 
       
   437 void
       
   438 gst_segment_set_newsegment (GstSegment * segment, gboolean update, gdouble rate,
       
   439     GstFormat format, gint64 start, gint64 stop, gint64 time)
       
   440 {
       
   441   gst_segment_set_newsegment_full (segment, update, rate, 1.0, format, start,
       
   442       stop, time);
       
   443 }
       
   444 
       
   445 /**
       
   446  * gst_segment_set_newsegment_full:
       
   447  * @segment: a #GstSegment structure.
       
   448  * @update: flag indicating a new segment is started or updated
       
   449  * @rate: the rate of the segment.
       
   450  * @applied_rate: the applied rate of the segment.
       
   451  * @format: the format of the segment.
       
   452  * @start: the new start value
       
   453  * @stop: the new stop value
       
   454  * @time: the new stream time
       
   455  *
       
   456  * Update the segment structure with the field values of a new segment event.
       
   457  */
       
   458 #ifdef __SYMBIAN32__
       
   459 EXPORT_C
       
   460 #endif
       
   461 
       
   462 void
       
   463 gst_segment_set_newsegment_full (GstSegment * segment, gboolean update,
       
   464     gdouble rate, gdouble applied_rate, GstFormat format, gint64 start,
       
   465     gint64 stop, gint64 time)
       
   466 {
       
   467   gint64 duration;
       
   468 
       
   469   g_return_if_fail (rate != 0.0);
       
   470   g_return_if_fail (applied_rate != 0.0);
       
   471   g_return_if_fail (segment != NULL);
       
   472 
       
   473   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   474     segment->format = format;
       
   475 
       
   476   /* any other format with 0 also gives time 0, the other values are
       
   477    * invalid in the format though. */
       
   478   if (format != segment->format && start == 0) {
       
   479     format = segment->format;
       
   480     if (stop != 0)
       
   481       stop = -1;
       
   482     if (time != 0)
       
   483       time = -1;
       
   484   }
       
   485 
       
   486   g_return_if_fail (segment->format == format);
       
   487 
       
   488   if (update) {
       
   489     if (segment->rate > 0.0) {
       
   490       /* an update to the current segment is done, elapsed time is
       
   491        * difference between the old start and new start. */
       
   492       if (start > segment->start)
       
   493         duration = start - segment->start;
       
   494       else
       
   495         duration = 0;
       
   496     } else {
       
   497       /* for negative rates, the elapsed duration is the diff between the stop
       
   498        * positions */
       
   499       if (stop != -1 && stop < segment->stop)
       
   500         duration = segment->stop - stop;
       
   501       else
       
   502         duration = 0;
       
   503     }
       
   504   } else {
       
   505     /* the new segment has to be aligned with the old segment.
       
   506      * We first update the accumulated time of the previous
       
   507      * segment. the accumulated time is used when syncing to the
       
   508      * clock. 
       
   509      */
       
   510     if (segment->stop != -1) {
       
   511       duration = segment->stop - segment->start;
       
   512     } else if (segment->last_stop != -1) {
       
   513       /* else use last seen timestamp as segment stop */
       
   514       duration = segment->last_stop - segment->start;
       
   515     } else {
       
   516       /* else we don't know and throw a warning.. really, this should
       
   517        * be fixed in the element. */
       
   518       g_warning ("closing segment of unknown duration, assuming duration of 0");
       
   519       duration = 0;
       
   520     }
       
   521   }
       
   522   /* use previous rate to calculate duration */
       
   523   if (segment->abs_rate != 1.0)
       
   524     duration /= segment->abs_rate;
       
   525 
       
   526   /* accumulate duration */
       
   527   segment->accum += duration;
       
   528 
       
   529   /* then update the current segment */
       
   530   segment->rate = rate;
       
   531   segment->abs_rate = ABS (rate);
       
   532   segment->applied_rate = applied_rate;
       
   533   segment->start = start;
       
   534   segment->last_stop = start;
       
   535   segment->stop = stop;
       
   536   segment->time = time;
       
   537 }
       
   538 
       
   539 /**
       
   540  * gst_segment_to_stream_time:
       
   541  * @segment: a #GstSegment structure.
       
   542  * @format: the format of the segment.
       
   543  * @position: the position in the segment
       
   544  *
       
   545  * Translate @position to stream time using the currently configured 
       
   546  * segment. The @position value must be between @segment start and
       
   547  * stop value. 
       
   548  *
       
   549  * This function is typically used by elements that need to operate on
       
   550  * the stream time of the buffers it receives, such as effect plugins.
       
   551  * In those use cases, @position is typically the buffer timestamp or 
       
   552  * clock time that one wants to convert to the stream time.
       
   553  * The stream time is always between 0 and the total duration of the 
       
   554  * media stream. 
       
   555  *
       
   556  * Returns: the position in stream_time or -1 when an invalid position
       
   557  * was given.
       
   558  */
       
   559 #ifdef __SYMBIAN32__
       
   560 EXPORT_C
       
   561 #endif
       
   562 
       
   563 gint64
       
   564 gst_segment_to_stream_time (GstSegment * segment, GstFormat format,
       
   565     gint64 position)
       
   566 {
       
   567   gint64 result, start, stop, time;
       
   568   gdouble abs_applied_rate;
       
   569 
       
   570   g_return_val_if_fail (segment != NULL, -1);
       
   571 
       
   572   /* format does not matter for -1 */
       
   573   if (G_UNLIKELY (position == -1))
       
   574     return -1;
       
   575 
       
   576   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   577     segment->format = format;
       
   578 
       
   579   /* if we have the position for the same format as the segment, we can compare
       
   580    * the start and stop values, otherwise we assume 0 and -1 */
       
   581   if (segment->format == format) {
       
   582     start = segment->start;
       
   583     stop = segment->stop;
       
   584     time = segment->time;
       
   585   } else {
       
   586     start = 0;
       
   587     stop = -1;
       
   588     time = 0;
       
   589   }
       
   590 
       
   591   /* outside of the segment boundary stop */
       
   592   if (G_UNLIKELY (stop != -1 && position > stop))
       
   593     return -1;
       
   594 
       
   595   /* before the segment boundary */
       
   596   if (G_UNLIKELY (position < start))
       
   597     return -1;
       
   598 
       
   599   /* time must be known */
       
   600   if (G_UNLIKELY (time == -1))
       
   601     return -1;
       
   602 
       
   603   /* bring to uncorrected position in segment */
       
   604   result = position - start;
       
   605 
       
   606   abs_applied_rate = ABS (segment->applied_rate);
       
   607 
       
   608   /* correct for applied rate if needed */
       
   609   if (abs_applied_rate != 1.0)
       
   610     result *= abs_applied_rate;
       
   611 
       
   612   /* add or subtract from segment time based on applied rate */
       
   613   if (segment->applied_rate > 0.0) {
       
   614     /* correct for segment time */
       
   615     result += time;
       
   616   } else {
       
   617     /* correct for segment time, clamp at 0. Streams with a negative
       
   618      * applied_rate have timestamps between start and stop, as usual, but have
       
   619      * the time member starting high and going backwards.  */
       
   620     if (time > result)
       
   621       result = time - result;
       
   622     else
       
   623       result = 0;
       
   624   }
       
   625 
       
   626   return result;
       
   627 }
       
   628 
       
   629 /**
       
   630  * gst_segment_to_running_time:
       
   631  * @segment: a #GstSegment structure.
       
   632  * @format: the format of the segment.
       
   633  * @position: the position in the segment
       
   634  *
       
   635  * Translate @position to the total running time using the currently configured 
       
   636  * and previously accumulated segments. Position is a value between @segment
       
   637  * start and stop time.
       
   638  *
       
   639  * This function is typically used by elements that need to synchronize to the
       
   640  * global clock in a pipeline. The runnning time is a constantly increasing value
       
   641  * starting from 0. When gst_segment_init() is called, this value will reset to
       
   642  * 0.
       
   643  *
       
   644  * This function returns -1 if the position is outside of @segment start and stop.
       
   645  *
       
   646  * Returns: the position as the total running time or -1 when an invalid position
       
   647  * was given.
       
   648  */
       
   649 #ifdef __SYMBIAN32__
       
   650 EXPORT_C
       
   651 #endif
       
   652 
       
   653 gint64
       
   654 gst_segment_to_running_time (GstSegment * segment, GstFormat format,
       
   655     gint64 position)
       
   656 {
       
   657   gint64 result;
       
   658   gint64 start, stop, accum;
       
   659 
       
   660   g_return_val_if_fail (segment != NULL, -1);
       
   661 
       
   662   if (G_UNLIKELY (position == -1))
       
   663     return -1;
       
   664 
       
   665   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   666     segment->format = format;
       
   667 
       
   668   /* if we have the position for the same format as the segment, we can compare
       
   669    * the start and stop values, otherwise we assume 0 and -1 */
       
   670   if (segment->format == format) {
       
   671     start = segment->start;
       
   672     stop = segment->stop;
       
   673     accum = segment->accum;
       
   674   } else {
       
   675     start = 0;
       
   676     stop = -1;
       
   677     accum = 0;
       
   678   }
       
   679 
       
   680   /* before the segment boundary */
       
   681   if (G_UNLIKELY (position < start))
       
   682     return -1;
       
   683 
       
   684   if (segment->rate > 0.0) {
       
   685     /* outside of the segment boundary stop */
       
   686     if (G_UNLIKELY (stop != -1 && position > stop))
       
   687       return -1;
       
   688 
       
   689     /* bring to uncorrected position in segment */
       
   690     result = position - start;
       
   691   } else {
       
   692     /* cannot continue if no stop position set or outside of
       
   693      * the segment. */
       
   694     if (G_UNLIKELY (stop == -1 || position > stop))
       
   695       return -1;
       
   696 
       
   697     /* bring to uncorrected position in segment */
       
   698     result = stop - position;
       
   699   }
       
   700 
       
   701   /* scale based on the rate, avoid division by and conversion to 
       
   702    * float when not needed */
       
   703   if (segment->abs_rate != 1.0)
       
   704     result /= segment->abs_rate;
       
   705 
       
   706   /* correct for accumulated segments */
       
   707   result += accum;
       
   708 
       
   709   return result;
       
   710 }
       
   711 
       
   712 /**
       
   713  * gst_segment_clip:
       
   714  * @segment: a #GstSegment structure.
       
   715  * @format: the format of the segment.
       
   716  * @start: the start position in the segment
       
   717  * @stop: the stop position in the segment
       
   718  * @clip_start: the clipped start position in the segment
       
   719  * @clip_stop: the clipped stop position in the segment
       
   720  *
       
   721  * Clip the given @start and @stop values to the segment boundaries given
       
   722  * in @segment. @start and @stop are compared and clipped to @segment 
       
   723  * start and stop values.
       
   724  *
       
   725  * If the function returns FALSE, @start and @stop are known to fall
       
   726  * outside of @segment and @clip_start and @clip_stop are not updated.
       
   727  *
       
   728  * When the function returns TRUE, @clip_start and @clip_stop will be
       
   729  * updated. If @clip_start or @clip_stop are different from @start or @stop
       
   730  * respectively, the region fell partially in the segment.
       
   731  *
       
   732  * Note that when @stop is -1, @clip_stop will be set to the end of the
       
   733  * segment. Depending on the use case, this may or may not be what you want.
       
   734  *
       
   735  * Returns: TRUE if the given @start and @stop times fall partially or 
       
   736  *     completely in @segment, FALSE if the values are completely outside 
       
   737  *     of the segment.
       
   738  */
       
   739 #ifdef __SYMBIAN32__
       
   740 EXPORT_C
       
   741 #endif
       
   742 
       
   743 gboolean
       
   744 gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start,
       
   745     gint64 stop, gint64 * clip_start, gint64 * clip_stop)
       
   746 {
       
   747   g_return_val_if_fail (segment != NULL, FALSE);
       
   748 
       
   749   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   750     segment->format = format;
       
   751   else
       
   752     g_return_val_if_fail (segment->format == format, FALSE);
       
   753 
       
   754   /* if we have a stop position and a valid start and start is bigger, 
       
   755    * we're outside of the segment */
       
   756   if (G_UNLIKELY (segment->stop != -1 && start != -1 && start >= segment->stop))
       
   757     return FALSE;
       
   758 
       
   759   /* if a stop position is given and is before the segment start,
       
   760    * we're outside of the segment */
       
   761   if (G_UNLIKELY (stop != -1 && stop != start && stop <= segment->start))
       
   762     return FALSE;
       
   763 
       
   764   if (clip_start) {
       
   765     if (start == -1)
       
   766       *clip_start = -1;
       
   767     else
       
   768       *clip_start = MAX (start, segment->start);
       
   769   }
       
   770 
       
   771   if (clip_stop) {
       
   772     if (stop == -1)
       
   773       *clip_stop = segment->stop;
       
   774     else if (segment->stop == -1)
       
   775       *clip_stop = MAX (-1, stop);
       
   776     else
       
   777       *clip_stop = MIN (stop, segment->stop);
       
   778 
       
   779     if (segment->duration != -1)
       
   780       *clip_stop = MIN (*clip_stop, segment->duration);
       
   781   }
       
   782 
       
   783   return TRUE;
       
   784 }