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 |
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 |
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; |
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 } |