11/*
2- * Copyright (C) 2017 Open Broadcast Systems Ltd
2+ * Copyright (C) 2017-2021 Open Broadcast Systems Ltd
33 *
44 * Authors: Rafaël Carré
5+ * Kieran Kunhya
56 *
67 * Permission is hereby granted, free of charge, to any person obtaining
78 * a copy of this software and associated documentation files (the
@@ -96,6 +97,9 @@ struct upipe_sync {
9697 /** ntsc */
9798 uint8_t frame_idx ;
9899
100+ /* framesync */
101+ int frame_sync ;
102+
99103 /** public upipe structure */
100104 struct upipe upipe ;
101105};
@@ -469,7 +473,7 @@ static bool sync_channel(struct upipe *upipe)
469473 } else {
470474 float f = (float )((int64_t )pts - (int64_t )video_pts ) * 1000 / UCLOCK_FREQ ;
471475 upipe_notice_va (upipe_sync_sub_to_upipe (upipe_sync_sub ),
472- "DROP %.2f, duration in CLOCK %" PRIu64 "" , f , duration );
476+ "DROP %.2f, duration in CLOCK %" PRIu64 " samples %zu " , f , duration , samples );
473477 ulist_delete (uchain_uref );
474478 uref_free (uref );
475479 upipe_sync_sub -> samples -= samples ;
@@ -713,7 +717,8 @@ static void output_sound(struct upipe *upipe, const struct urational *fps,
713717
714718 src_samples -= uref_samples ;
715719 samples -= uref_samples ;
716- upipe_sync_sub -> samples -= uref_samples ;
720+ if (upipe_sync_sub -> samples >= uref_samples )
721+ upipe_sync_sub -> samples -= uref_samples ;
717722 //upipe_notice_va(upipe_sub, "pop, samples %" PRIu64, upipe_sync_sub->samples);
718723
719724 if (src_samples == 0 ) {
@@ -747,44 +752,52 @@ static void cb(struct upump *upump)
747752 struct upipe_sync * upipe_sync = upipe_sync_from_upipe (upipe );
748753
749754 uint64_t now = uclock_now (upipe_sync -> uclock );
750- if (now - upipe_sync -> ticks_per_frame > upipe_sync -> pts )
751- upipe_dbg_va (upipe , "cb after %" PRId64 "ms" ,
752- (int64_t )((int64_t )now - (int64_t )upipe_sync -> pts ) / 27000 );
755+
756+ if (upipe_sync -> frame_sync ) {
757+ if (now - upipe_sync -> ticks_per_frame > upipe_sync -> pts )
758+ upipe_dbg_va (upipe , "cb after %" PRId64 "ms" ,
759+ (int64_t )((int64_t )now - (int64_t )upipe_sync -> pts ) / 27000 );
760+ }
753761
754762 now = upipe_sync -> pts ; // the upump was scheduled for now
755763 struct uchain * uchain = NULL ;
756- for (;;) {
757- uchain = ulist_peek (& upipe_sync -> urefs );
758- upipe_throw (upipe , UPROBE_SYNC_PICTURE , UPIPE_SYNC_SIGNATURE , !!uchain );
759- if (!uchain )
760- break ;
761-
762- struct uref * uref = uref_from_uchain (uchain );
763- uint64_t pts = 0 ;
764- uref_clock_get_pts_sys (uref , & pts );
765- pts += upipe_sync -> latency ;
764+ if (upipe_sync -> frame_sync ) {
765+ for (;;) {
766+ uchain = ulist_peek (& upipe_sync -> urefs );
767+ upipe_throw (upipe , UPROBE_SYNC_PICTURE , UPIPE_SYNC_SIGNATURE , !!uchain );
768+ if (!uchain )
769+ break ;
770+
771+ struct uref * uref = uref_from_uchain (uchain );
772+ uint64_t pts = 0 ;
773+ uref_clock_get_pts_sys (uref , & pts );
774+ pts += upipe_sync -> latency ;
775+
776+ /* frame duration */
777+ const uint64_t ticks = upipe_sync -> ticks_per_frame ;
778+
779+ if (pts < now - ticks / 2 ) {
780+ /* frame pts too much in the past */
781+ upipe_warn_va (upipe , "too late" );
782+ } else if (pts > now + ticks / 2 ) {
783+ upipe_warn_va (upipe , "video too early: %.2f > %.2f" ,
784+ pts_to_time (pts ), pts_to_time (now + ticks / 2 )
785+ );
786+ uchain = NULL ; /* do not drop */
787+ break ;
788+ } else {
789+ break ; // ok
790+ }
766791
767- /* frame duration */
768- const uint64_t ticks = upipe_sync -> ticks_per_frame ;
769-
770- if (pts < now - ticks / 2 ) {
771- /* frame pts too much in the past */
772- upipe_warn_va (upipe , "too late" );
773- } else if (pts > now + ticks / 2 ) {
774- upipe_warn_va (upipe , "video too early: %.2f > %.2f" ,
775- pts_to_time (pts ), pts_to_time (now + ticks / 2 )
776- );
777- uchain = NULL ; /* do not drop */
778- break ;
779- } else {
780- break ; // ok
792+ ulist_pop (& upipe_sync -> urefs );
793+ uref_free (uref );
794+ upipe_sync -> buffered_frames -- ;
795+ int64_t u = pts - now ;
796+ upipe_err_va (upipe , "Drop pic (pts-now == %" PRId64 "ms)" , u / 27000 );
781797 }
782-
783- ulist_pop (& upipe_sync -> urefs );
784- uref_free (uref );
785- upipe_sync -> buffered_frames -- ;
786- int64_t u = pts - now ;
787- upipe_err_va (upipe , "Drop pic (pts-now == %" PRId64 "ms)" , u / 27000 );
798+ }
799+ else {
800+ upipe_dbg_va (upipe , "queued %zu" , ulist_depth (& upipe_sync -> urefs ));
788801 }
789802
790803 /* sync audio */
@@ -795,56 +808,65 @@ static void cb(struct upump *upump)
795808 /* output audio */
796809 output_sound (upipe_sync_to_upipe (upipe_sync ), & upipe_sync -> fps , NULL );
797810
798- /* output pic */
799- if (uchain ) {
800- ulist_pop (& upipe_sync -> urefs );
801- /* buffer picture */
802- uref_free (upipe_sync -> uref );
803- upipe_sync -> buffered_frames -- ;
804- upipe_sync -> uref = uref_from_uchain (uchain );
805- } else {
806- upipe_dbg_va (upipe , "no picture, repeating last one" );
807- }
808-
809811 struct uref * uref = NULL ;
810- if (upipe_sync -> uref ) {
811- uref = uref_dup (upipe_sync -> uref );
812- uref_clock_set_pts_sys (uref , upipe_sync -> pts - upipe_sync -> latency );
813- }
812+ if (upipe_sync -> frame_sync ) {
813+ /* output pic */
814+ if (uchain ) {
815+ ulist_pop (& upipe_sync -> urefs );
816+ /* buffer picture */
817+ uref_free (upipe_sync -> uref );
818+ upipe_sync -> buffered_frames -- ;
819+ upipe_sync -> uref = uref_from_uchain (uchain );
820+ } else {
821+ upipe_dbg_va (upipe , "no picture, repeating last one" );
822+ }
814823
815- if (0 ) {
816- now = uclock_now (upipe_sync -> uclock );
817- upipe_notice_va (upipe ,
818- "output %.2f now %.2f latency %" PRIu64 ,
819- pts_to_time (upipe_sync -> pts - upipe_sync -> latency ),
820- pts_to_time (now ),
821- upipe_sync -> latency / 27000
822- );
824+ if (upipe_sync -> uref ) {
825+ uref = uref_dup (upipe_sync -> uref );
826+ uref_clock_set_pts_sys (uref , upipe_sync -> pts - upipe_sync -> latency );
827+ }
828+
829+ if (0 ) {
830+ now = uclock_now (upipe_sync -> uclock );
831+ upipe_notice_va (upipe ,
832+ "output %.2f now %.2f latency %" PRIu64 ,
833+ pts_to_time (upipe_sync -> pts - upipe_sync -> latency ),
834+ pts_to_time (now ),
835+ upipe_sync -> latency / 27000
836+ );
837+ }
838+ }
839+ else {
840+ uchain = ulist_pop (& upipe_sync -> urefs );
841+ uref = uref_from_uchain (uchain );
823842 }
824843
825844 if (uref )
826845 upipe_sync_output (upipe , uref , NULL );
827846
828- /* increment pts */
829- upipe_sync -> pts += upipe_sync -> ticks_per_frame ;
830-
831- /* schedule next pic */
832- now = uclock_now (upipe_sync -> uclock );
833- if (now != UINT64_MAX && now > upipe_sync -> pts ) {
834- uint64_t diff = now - upipe_sync -> pts ;
835- diff += upipe_sync -> ticks_per_frame - 1 ;
836- diff /= upipe_sync -> ticks_per_frame ;
837- upipe_err_va (upipe , "skipping %" PRIu64 " beats" , diff );
838- upipe_sync -> pts += diff * upipe_sync -> ticks_per_frame ;
839- }
847+ /* In non framesync mode scheduling is based on when video frame arrives */
848+ if (upipe_sync -> frame_sync ) {
849+ /* increment pts */
850+ upipe_sync -> pts += upipe_sync -> ticks_per_frame ;
840851
841- uint64_t wait ;
842- if (now == UINT64_MAX )
843- wait = upipe_sync -> ticks_per_frame ;
844- else
845- wait = upipe_sync -> pts - now ;
852+ /* schedule next pic */
853+ now = uclock_now (upipe_sync -> uclock );
854+ if (now != UINT64_MAX && now > upipe_sync -> pts ) {
855+ uint64_t diff = now - upipe_sync -> pts ;
856+ diff += upipe_sync -> ticks_per_frame - 1 ;
857+ diff /= upipe_sync -> ticks_per_frame ;
858+ upipe_err_va (upipe , "skipping %" PRIu64 " beats" , diff );
859+ upipe_sync -> pts += diff * upipe_sync -> ticks_per_frame ;
860+ }
861+
862+ uint64_t wait ;
863+ if (now == UINT64_MAX )
864+ wait = upipe_sync -> ticks_per_frame ;
865+ else
866+ wait = upipe_sync -> pts - now ;
846867
847- upipe_sync_wait_upump (upipe , wait , cb );
868+ upipe_sync_wait_upump (upipe , wait , cb );
869+ }
848870}
849871
850872/** @internal @This receives data.
@@ -883,7 +905,7 @@ static void upipe_sync_sub_input(struct upipe *upipe, struct uref *uref,
883905 size_t samples = 0 ;
884906 uref_sound_size (uref , & samples , NULL );
885907 upipe_sync_sub -> samples += samples ;
886- // upipe_notice_va(upipe, "push, samples %" PRIu64, upipe_sync_sub->samples);
908+ upipe_notice_va (upipe , "push in samples %zu, queued samples %" PRIu64 , samples , upipe_sync_sub -> samples );
887909
888910 ulist_add (& upipe_sync_sub -> urefs , uref_to_uchain (uref ));
889911
@@ -928,46 +950,63 @@ static void upipe_sync_input(struct upipe *upipe, struct uref *uref,
928950 return ;
929951 }
930952 pts += upipe_sync -> latency ;
931-
932953 uint64_t now = uclock_now (upipe_sync -> uclock );
933954
934- /* reject late pics */
935- if (now != UINT64_MAX && now > pts ) {
936- uint64_t cr = 0 ;
937- uref_clock_get_cr_sys (uref , & cr );
938- upipe_err_va (upipe , "%s() picture too late by %" PRIu64 "ms, drop pic, recept %" PRIu64 "" ,
939- __func__ , (now - pts ) / 27000 , (now - cr ) / 27000 );
940- uref_free (uref );
941- return ;
942- }
955+ uint64_t wait ;
956+ if (upipe_sync -> frame_sync ) {
957+ /* reject late pics */
958+ if (now != UINT64_MAX && now > pts ) {
959+ uint64_t cr = 0 ;
960+ uref_clock_get_cr_sys (uref , & cr );
961+ upipe_err_va (upipe , "%s() picture too late by %" PRIu64 "ms, drop pic, recept %" PRIu64 "" ,
962+ __func__ , (now - pts ) / 27000 , (now - cr ) / 27000 );
963+ uref_free (uref );
964+ return ;
965+ }
943966
944- //upipe_dbg_va(upipe, "push PTS in %" PRIu64 " ms", (pts - now) / 27000);
967+ //upipe_dbg_va(upipe, "push PTS in %" PRIu64 " ms", (pts - now) / 27000);
945968
946- /* buffer pic */
947- ulist_add (& upipe_sync -> urefs , uref_to_uchain (uref ));
948- upipe_sync -> buffered_frames ++ ;
969+ /* buffer pic */
970+ ulist_add (& upipe_sync -> urefs , uref_to_uchain (uref ));
971+ upipe_sync -> buffered_frames ++ ;
949972
950- /* limit buffered frames */
951- if (unlikely (upipe_sync -> buffered_frames >= MAX_VIDEO_FRAMES )) {
952- ulist_uref_flush (& upipe_sync -> urefs );
953- upipe_sync -> buffered_frames = 0 ;
954- }
973+ /* limit buffered frames */
974+ if (unlikely (upipe_sync -> buffered_frames >= MAX_VIDEO_FRAMES )) {
975+ ulist_uref_flush (& upipe_sync -> urefs );
976+ upipe_sync -> buffered_frames = 0 ;
977+ }
955978
956- /* timer already active */
957- if (upipe_sync -> upump )
958- return ;
979+ /* timer already active */
980+ if (upipe_sync -> upump )
981+ return ;
959982
960- /* need upump mgr */
961- if (!ubase_check (upipe_sync_check_upump_mgr (upipe_sync_to_upipe (upipe_sync ))))
962- return ;
983+ /* need upump mgr */
984+ if (!ubase_check (upipe_sync_check_upump_mgr (upipe_sync_to_upipe (upipe_sync ))))
985+ return ;
963986
964- /* start timer */
965- uint64_t wait ;
966- if (now == UINT64_MAX )
967- wait = upipe_sync -> ticks_per_frame ;
968- else
987+ /* start timer */
988+ if (now == UINT64_MAX )
989+ wait = upipe_sync -> ticks_per_frame ;
990+ else
991+ wait = pts - now ;
992+ }
993+ else {
969994 wait = pts - now ;
970995
996+ /* too old frames */
997+ if (now > pts + upipe_sync -> ticks_per_frame ) {
998+ uref_free (uref );
999+ return ;
1000+ }
1001+
1002+ /* buffer pic */
1003+ ulist_add (& upipe_sync -> urefs , uref_to_uchain (uref ));
1004+
1005+ /* need upump mgr */
1006+ if (!ubase_check (upipe_sync_check_upump_mgr (upipe_sync_to_upipe (upipe_sync ))))
1007+ return ;
1008+ }
1009+
9711010 upipe_sync -> pts = pts ;
9721011 upipe_sync_wait_upump (upipe_sync_to_upipe (upipe_sync ), wait , cb );
9731012}
@@ -997,6 +1036,7 @@ static struct upipe *upipe_sync_alloc(struct upipe_mgr *mgr,
9971036 upipe_sync -> buffered_frames = 0 ;
9981037 upipe_sync -> uref = NULL ;
9991038 ulist_init (& upipe_sync -> urefs );
1039+ upipe_sync -> frame_sync = 1 ; /* Old frame sync behaviour by default */
10001040
10011041 upipe_sync_init_urefcount (upipe );
10021042 upipe_sync_init_uclock (upipe );
@@ -1059,6 +1099,28 @@ static int upipe_sync_set_flow_def(struct upipe *upipe, struct uref *flow_def)
10591099 return UBASE_ERR_NONE ;
10601100}
10611101
1102+ /** @internal @This sets the content of an sync option.
1103+ *
1104+ * @param upipe description structure of the pipe
1105+ * @param option name of the option
1106+ * @param content content of the option
1107+ * @return an error code
1108+ */
1109+ static int upipe_sync_set_option (struct upipe * upipe ,
1110+ const char * option , const char * content )
1111+ {
1112+ struct upipe_sync * upipe_sync = upipe_sync_from_upipe (upipe );
1113+ if (!option || !content )
1114+ return UBASE_ERR_INVALID ;
1115+
1116+ if (!strcmp (option , "frame-sync" ))
1117+ upipe_sync -> frame_sync = atoi (content );
1118+ else
1119+ return UBASE_ERR_INVALID ;
1120+
1121+ return UBASE_ERR_NONE ;
1122+ }
1123+
10621124/** @internal @This processes control commands.
10631125 *
10641126 * @param upipe description structure of the pipe
@@ -1081,7 +1143,11 @@ static int upipe_sync_control(struct upipe *upipe, int command, va_list args)
10811143 return UBASE_ERR_NONE ;
10821144 case UPIPE_ATTACH_UPUMP_MGR :
10831145 return upipe_sync_attach_upump_mgr (upipe );
1084-
1146+ case UPIPE_SET_OPTION : {
1147+ const char * option = va_arg (args , const char * );
1148+ const char * content = va_arg (args , const char * );
1149+ return upipe_sync_set_option (upipe , option , content );
1150+ }
10851151 default :
10861152 return UBASE_ERR_UNHANDLED ;
10871153 }
0 commit comments