gstreamer_core/gst/gstsegment.c
changeset 16 8e837d1bf446
parent 0 0e761a78d257
child 30 7e817e7e631c
equal deleted inserted replaced
15:4b0c6ed43234 16:8e837d1bf446
    17  * License along with this library; if not, write to the
    17  * License along with this library; if not, write to the
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    19  * Boston, MA 02111-1307, USA.
    19  * Boston, MA 02111-1307, USA.
    20  */
    20  */
    21 
    21 
    22 
       
    23 #include "gst_private.h"
    22 #include "gst_private.h"
       
    23 
       
    24 #include <math.h>
    24 
    25 
    25 #include "gstutils.h"
    26 #include "gstutils.h"
    26 #include "gstsegment.h"
    27 #include "gstsegment.h"
    27 
    28 
    28 /**
    29 /**
    81  * info to stream time (which is always between 0 and the duration of the stream).
    82  * info to stream time (which is always between 0 and the duration of the stream).
    82  *
    83  *
    83  * Last reviewed on 2007-05-17 (0.10.13)
    84  * Last reviewed on 2007-05-17 (0.10.13)
    84  */
    85  */
    85 
    86 
    86 static GstSegment *
    87 /**
       
    88  * gst_segment_copy:
       
    89  * @segment: a #GstSegment
       
    90  *
       
    91  * Create a copy of given @segment.
       
    92  *
       
    93  * Returns: a new #GstSegment, free with gst_segment_free().
       
    94  *
       
    95  * Since: 0.10.20
       
    96  */
       
    97 #ifdef __SYMBIAN32__
       
    98 EXPORT_C
       
    99 #endif
       
   100 
       
   101 GstSegment *
    87 gst_segment_copy (GstSegment * segment)
   102 gst_segment_copy (GstSegment * segment)
    88 {
   103 {
    89   GstSegment *result = NULL;
   104   GstSegment *result = NULL;
    90 
   105 
    91   if (segment) {
   106   if (segment) {
    92     result = gst_segment_new ();
   107     result = (GstSegment *) g_slice_copy (sizeof (GstSegment), segment);
    93     memcpy (result, segment, sizeof (GstSegment));
       
    94   }
   108   }
    95   return result;
   109   return result;
    96 }
   110 }
    97 #ifdef __SYMBIAN32__
   111 #ifdef __SYMBIAN32__
    98 EXPORT_C
   112 EXPORT_C
   127 GstSegment *
   141 GstSegment *
   128 gst_segment_new (void)
   142 gst_segment_new (void)
   129 {
   143 {
   130   GstSegment *result;
   144   GstSegment *result;
   131 
   145 
   132   result = g_new0 (GstSegment, 1);
   146   result = g_slice_new0 (GstSegment);
   133   gst_segment_init (result, GST_FORMAT_UNDEFINED);
   147   gst_segment_init (result, GST_FORMAT_UNDEFINED);
   134 
   148 
   135   return result;
   149   return result;
   136 }
   150 }
   137 
   151 
   146 #endif
   160 #endif
   147 
   161 
   148 void
   162 void
   149 gst_segment_free (GstSegment * segment)
   163 gst_segment_free (GstSegment * segment)
   150 {
   164 {
   151   g_free (segment);
   165   g_slice_free (GstSegment, segment);
   152 }
   166 }
   153 
   167 
   154 /**
   168 /**
   155  * gst_segment_init:
   169  * gst_segment_init:
   156  * @segment: a #GstSegment structure.
   170  * @segment: a #GstSegment structure.
   462 void
   476 void
   463 gst_segment_set_newsegment_full (GstSegment * segment, gboolean update,
   477 gst_segment_set_newsegment_full (GstSegment * segment, gboolean update,
   464     gdouble rate, gdouble applied_rate, GstFormat format, gint64 start,
   478     gdouble rate, gdouble applied_rate, GstFormat format, gint64 start,
   465     gint64 stop, gint64 time)
   479     gint64 stop, gint64 time)
   466 {
   480 {
   467   gint64 duration;
   481   gint64 duration, last_stop;
   468 
   482 
   469   g_return_if_fail (rate != 0.0);
   483   g_return_if_fail (rate != 0.0);
   470   g_return_if_fail (applied_rate != 0.0);
   484   g_return_if_fail (applied_rate != 0.0);
   471   g_return_if_fail (segment != NULL);
   485   g_return_if_fail (segment != NULL);
       
   486 
       
   487   GST_DEBUG ("configuring segment update %d, rate %lf, format %s, "
       
   488       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", position %"
       
   489       G_GINT64_FORMAT, update, rate, gst_format_get_name (format), start,
       
   490       stop, time);
       
   491   GST_DEBUG ("old segment was: %" GST_SEGMENT_FORMAT, segment);
   472 
   492 
   473   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
   493   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
   474     segment->format = format;
   494     segment->format = format;
   475 
   495 
   476   /* any other format with 0 also gives time 0, the other values are
   496   /* any other format with 0 also gives time 0, the other values are
   484   }
   504   }
   485 
   505 
   486   g_return_if_fail (segment->format == format);
   506   g_return_if_fail (segment->format == format);
   487 
   507 
   488   if (update) {
   508   if (update) {
   489     if (segment->rate > 0.0) {
   509     if (G_LIKELY (segment->rate > 0.0)) {
   490       /* an update to the current segment is done, elapsed time is
   510       /* an update to the current segment is done, elapsed time is
   491        * difference between the old start and new start. */
   511        * difference between the old start and new start. */
   492       if (start > segment->start)
   512       if (start > segment->start)
   493         duration = start - segment->start;
   513         duration = start - segment->start;
   494       else
   514       else
   499       if (stop != -1 && stop < segment->stop)
   519       if (stop != -1 && stop < segment->stop)
   500         duration = segment->stop - stop;
   520         duration = segment->stop - stop;
   501       else
   521       else
   502         duration = 0;
   522         duration = 0;
   503     }
   523     }
       
   524     /* update last_stop to be a valid value in the updated segment */
       
   525     if (start > segment->last_stop)
       
   526       last_stop = start;
       
   527     else if (stop != -1 && stop < segment->last_stop)
       
   528       last_stop = stop;
       
   529     else
       
   530       last_stop = segment->last_stop;
   504   } else {
   531   } else {
   505     /* the new segment has to be aligned with the old segment.
   532     /* the new segment has to be aligned with the old segment.
   506      * We first update the accumulated time of the previous
   533      * We first update the accumulated time of the previous
   507      * segment. the accumulated time is used when syncing to the
   534      * segment. the accumulated time is used when syncing to the
   508      * clock. 
   535      * clock. */
   509      */
       
   510     if (segment->stop != -1) {
   536     if (segment->stop != -1) {
   511       duration = segment->stop - segment->start;
   537       duration = segment->stop - segment->start;
   512     } else if (segment->last_stop != -1) {
   538     } else if (segment->last_stop != -1) {
   513       /* else use last seen timestamp as segment stop */
   539       /* else use last seen timestamp as segment stop */
   514       duration = segment->last_stop - segment->start;
   540       duration = segment->last_stop - segment->start;
   516       /* else we don't know and throw a warning.. really, this should
   542       /* else we don't know and throw a warning.. really, this should
   517        * be fixed in the element. */
   543        * be fixed in the element. */
   518       g_warning ("closing segment of unknown duration, assuming duration of 0");
   544       g_warning ("closing segment of unknown duration, assuming duration of 0");
   519       duration = 0;
   545       duration = 0;
   520     }
   546     }
       
   547     /* position the last_stop to the next expected position in the new segment,
       
   548      * which is the start or the stop of the segment */
       
   549     if (rate > 0.0)
       
   550       last_stop = start;
       
   551     else
       
   552       last_stop = stop;
   521   }
   553   }
   522   /* use previous rate to calculate duration */
   554   /* use previous rate to calculate duration */
   523   if (segment->abs_rate != 1.0)
   555   if (G_LIKELY (segment->abs_rate != 1.0))
   524     duration /= segment->abs_rate;
   556     duration /= segment->abs_rate;
   525 
   557 
   526   /* accumulate duration */
   558   /* accumulate duration */
   527   segment->accum += duration;
   559   segment->accum += duration;
   528 
   560 
   529   /* then update the current segment */
   561   /* then update the current segment */
   530   segment->rate = rate;
   562   segment->rate = rate;
   531   segment->abs_rate = ABS (rate);
   563   segment->abs_rate = ABS (rate);
   532   segment->applied_rate = applied_rate;
   564   segment->applied_rate = applied_rate;
   533   segment->start = start;
   565   segment->start = start;
   534   segment->last_stop = start;
   566   segment->last_stop = last_stop;
   535   segment->stop = stop;
   567   segment->stop = stop;
   536   segment->time = time;
   568   segment->time = time;
   537 }
   569 }
   538 
   570 
   539 /**
   571 /**
   576   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
   608   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
   577     segment->format = format;
   609     segment->format = format;
   578 
   610 
   579   /* if we have the position for the same format as the segment, we can compare
   611   /* 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 */
   612    * the start and stop values, otherwise we assume 0 and -1 */
   581   if (segment->format == format) {
   613   if (G_LIKELY (segment->format == format)) {
   582     start = segment->start;
   614     start = segment->start;
   583     stop = segment->stop;
   615     stop = segment->stop;
   584     time = segment->time;
   616     time = segment->time;
   585   } else {
   617   } else {
   586     start = 0;
   618     start = 0;
   604   result = position - start;
   636   result = position - start;
   605 
   637 
   606   abs_applied_rate = ABS (segment->applied_rate);
   638   abs_applied_rate = ABS (segment->applied_rate);
   607 
   639 
   608   /* correct for applied rate if needed */
   640   /* correct for applied rate if needed */
   609   if (abs_applied_rate != 1.0)
   641   if (G_UNLIKELY (abs_applied_rate != 1.0))
   610     result *= abs_applied_rate;
   642     result *= abs_applied_rate;
   611 
   643 
   612   /* add or subtract from segment time based on applied rate */
   644   /* add or subtract from segment time based on applied rate */
   613   if (segment->applied_rate > 0.0) {
   645   if (G_LIKELY (segment->applied_rate > 0.0)) {
   614     /* correct for segment time */
   646     /* correct for segment time */
   615     result += time;
   647     result += time;
   616   } else {
   648   } else {
   617     /* correct for segment time, clamp at 0. Streams with a negative
   649     /* correct for segment time, clamp at 0. Streams with a negative
   618      * applied_rate have timestamps between start and stop, as usual, but have
   650      * applied_rate have timestamps between start and stop, as usual, but have
   619      * the time member starting high and going backwards.  */
   651      * the time member starting high and going backwards.  */
   620     if (time > result)
   652     if (G_LIKELY (time > result))
   621       result = time - result;
   653       result = time - result;
   622     else
   654     else
   623       result = 0;
   655       result = 0;
   624   }
   656   }
   625 
   657 
   665   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
   697   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
   666     segment->format = format;
   698     segment->format = format;
   667 
   699 
   668   /* if we have the position for the same format as the segment, we can compare
   700   /* 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 */
   701    * the start and stop values, otherwise we assume 0 and -1 */
   670   if (segment->format == format) {
   702   if (G_LIKELY (segment->format == format)) {
   671     start = segment->start;
   703     start = segment->start;
   672     stop = segment->stop;
   704     stop = segment->stop;
   673     accum = segment->accum;
   705     accum = segment->accum;
   674   } else {
   706   } else {
   675     start = 0;
   707     start = 0;
   679 
   711 
   680   /* before the segment boundary */
   712   /* before the segment boundary */
   681   if (G_UNLIKELY (position < start))
   713   if (G_UNLIKELY (position < start))
   682     return -1;
   714     return -1;
   683 
   715 
   684   if (segment->rate > 0.0) {
   716   if (G_LIKELY (segment->rate > 0.0)) {
   685     /* outside of the segment boundary stop */
   717     /* outside of the segment boundary stop */
   686     if (G_UNLIKELY (stop != -1 && position > stop))
   718     if (G_UNLIKELY (stop != -1 && position > stop))
   687       return -1;
   719       return -1;
   688 
   720 
   689     /* bring to uncorrected position in segment */
   721     /* bring to uncorrected position in segment */
   698     result = stop - position;
   730     result = stop - position;
   699   }
   731   }
   700 
   732 
   701   /* scale based on the rate, avoid division by and conversion to 
   733   /* scale based on the rate, avoid division by and conversion to 
   702    * float when not needed */
   734    * float when not needed */
   703   if (segment->abs_rate != 1.0)
   735   if (G_UNLIKELY (segment->abs_rate != 1.0))
   704     result /= segment->abs_rate;
   736     result /= segment->abs_rate;
   705 
   737 
   706   /* correct for accumulated segments */
   738   /* correct for accumulated segments */
   707   result += accum;
   739   result += accum;
   708 
   740 
   780       *clip_stop = MIN (*clip_stop, segment->duration);
   812       *clip_stop = MIN (*clip_stop, segment->duration);
   781   }
   813   }
   782 
   814 
   783   return TRUE;
   815   return TRUE;
   784 }
   816 }
       
   817 
       
   818 /**
       
   819  * gst_segment_to_position:
       
   820  * @segment: a #GstSegment structure.
       
   821  * @format: the format of the segment.
       
   822  * @running_time: the running_time in the segment
       
   823  *
       
   824  * Convert @running_time into a position in the segment so that
       
   825  * gst_segment_to_running_time() with that position returns @running_time.
       
   826  *
       
   827  * Returns: the position in the segment for @running_time. This function returns
       
   828  * -1 when @running_time is -1 or when it is not inside @segment.
       
   829  *
       
   830  * Since: 0.10.24
       
   831  */
       
   832 #ifdef __SYMBIAN32__
       
   833 EXPORT_C
       
   834 #endif
       
   835 
       
   836 gint64
       
   837 gst_segment_to_position (GstSegment * segment, GstFormat format,
       
   838     gint64 running_time)
       
   839 {
       
   840   gint64 result;
       
   841   gint64 start, stop, accum;
       
   842 
       
   843   g_return_val_if_fail (segment != NULL, -1);
       
   844 
       
   845   if (G_UNLIKELY (running_time == -1))
       
   846     return -1;
       
   847 
       
   848   if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
       
   849     segment->format = format;
       
   850 
       
   851   /* if we have the position for the same format as the segment, we can compare
       
   852    * the start and stop values, otherwise we assume 0 and -1 */
       
   853   if (G_LIKELY (segment->format == format)) {
       
   854     start = segment->start;
       
   855     stop = segment->stop;
       
   856     accum = segment->accum;
       
   857   } else {
       
   858     start = 0;
       
   859     stop = -1;
       
   860     accum = 0;
       
   861   }
       
   862 
       
   863   /* this running_time was for a previous segment */
       
   864   if (running_time < accum)
       
   865     return -1;
       
   866 
       
   867   /* start by subtracting the accumulated time */
       
   868   result = running_time - accum;
       
   869 
       
   870   /* move into the segment at the right rate */
       
   871   if (G_UNLIKELY (segment->abs_rate != 1.0))
       
   872     result = ceil (result * segment->abs_rate);
       
   873 
       
   874   if (G_LIKELY (segment->rate > 0.0)) {
       
   875     /* bring to corrected position in segment */
       
   876     result += start;
       
   877 
       
   878     /* outside of the segment boundary stop */
       
   879     if (G_UNLIKELY (stop != -1 && result > stop))
       
   880       return -1;
       
   881   } else {
       
   882     /* cannot continue if no stop position set or outside of
       
   883      * the segment. */
       
   884     if (G_UNLIKELY (stop == -1 || result + start > stop))
       
   885       return -1;
       
   886 
       
   887     /* bring to corrected position in segment */
       
   888     result = stop - result;
       
   889   }
       
   890   return result;
       
   891 }
       
   892 
       
   893 
       
   894 /**
       
   895  * gst_segment_set_running_time:
       
   896  * @segment: a #GstSegment structure.
       
   897  * @format: the format of the segment.
       
   898  * @running_time: the running_time in the segment
       
   899  *
       
   900  * Adjust the start/stop and accum values of @segment such that the next valid
       
   901  * buffer will be one with @running_time.
       
   902  *
       
   903  * Returns: %TRUE if the segment could be updated successfully. If %FALSE is
       
   904  * returned, @running_time is -1 or not in @segment.
       
   905  *
       
   906  * Since: 0.10.24
       
   907  */
       
   908 #ifdef __SYMBIAN32__
       
   909 EXPORT_C
       
   910 #endif
       
   911 
       
   912 gboolean
       
   913 gst_segment_set_running_time (GstSegment * segment, GstFormat format,
       
   914     gint64 running_time)
       
   915 {
       
   916   gint64 position;
       
   917   gint64 start, stop, last_stop;
       
   918 
       
   919   /* start by bringing the running_time into the segment position */
       
   920   position = gst_segment_to_position (segment, format, running_time);
       
   921 
       
   922   /* we must have a valid position now */
       
   923   if (G_UNLIKELY (position == -1))
       
   924     return FALSE;
       
   925 
       
   926   start = segment->start;
       
   927   stop = segment->stop;
       
   928   last_stop = segment->last_stop;
       
   929 
       
   930   if (G_LIKELY (segment->rate > 0.0)) {
       
   931     /* update the start/last_stop and time values */
       
   932     start = position;
       
   933     if (last_stop < start)
       
   934       last_stop = start;
       
   935   } else {
       
   936     /* reverse, update stop */
       
   937     stop = position;
       
   938     /* if we were past the position, go back */
       
   939     if (last_stop > stop)
       
   940       last_stop = stop;
       
   941   }
       
   942   /* and accumulated time is exactly the running time */
       
   943   segment->time = gst_segment_to_stream_time (segment, format, start);
       
   944   segment->start = start;
       
   945   segment->stop = stop;
       
   946   segment->last_stop = last_stop;
       
   947   segment->accum = running_time;
       
   948 
       
   949   return TRUE;
       
   950 }