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 %" PRIu64 "" , ulist_depth (& upipe_sync -> urefs ));
788801 }
789802
790803 /* sync audio */
@@ -795,56 +808,78 @@ 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+ } else {
870+ uchain = ulist_peek (& upipe_sync -> urefs );
871+ if (uchain ) {
872+ uref = uref_from_uchain (uchain );
873+ if (uref ) {
874+ uint64_t pts = 0 ;
875+ uref_clock_get_pts_sys (uref , & pts );
876+ upipe_sync -> pts = pts + upipe_sync -> latency ;
877+
878+ uint64_t wait = pts - now ;
879+ upipe_sync_wait_upump (upipe , wait , cb );
880+ }
881+ }
882+ }
848883}
849884
850885/** @internal @This receives data.
@@ -883,7 +918,7 @@ static void upipe_sync_sub_input(struct upipe *upipe, struct uref *uref,
883918 size_t samples = 0 ;
884919 uref_sound_size (uref , & samples , NULL );
885920 upipe_sync_sub -> samples += samples ;
886- // upipe_notice_va(upipe, "push, samples %" PRIu64, upipe_sync_sub->samples);
921+ upipe_notice_va (upipe , "push in samples %zu, queued samples %" PRIu64 , samples , upipe_sync_sub -> samples );
887922
888923 ulist_add (& upipe_sync_sub -> urefs , uref_to_uchain (uref ));
889924
@@ -928,46 +963,63 @@ static void upipe_sync_input(struct upipe *upipe, struct uref *uref,
928963 return ;
929964 }
930965 pts += upipe_sync -> latency ;
931-
932966 uint64_t now = uclock_now (upipe_sync -> uclock );
933967
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- }
968+ uint64_t wait ;
969+ if (upipe_sync -> frame_sync ) {
970+ /* reject late pics */
971+ if (now != UINT64_MAX && now > pts ) {
972+ uint64_t cr = 0 ;
973+ uref_clock_get_cr_sys (uref , & cr );
974+ upipe_err_va (upipe , "%s() picture too late by %" PRIu64 "ms, drop pic, recept %" PRIu64 "" ,
975+ __func__ , (now - pts ) / 27000 , (now - cr ) / 27000 );
976+ uref_free (uref );
977+ return ;
978+ }
943979
944- //upipe_dbg_va(upipe, "push PTS in %" PRIu64 " ms", (pts - now) / 27000);
980+ //upipe_dbg_va(upipe, "push PTS in %" PRIu64 " ms", (pts - now) / 27000);
945981
946- /* buffer pic */
947- ulist_add (& upipe_sync -> urefs , uref_to_uchain (uref ));
948- upipe_sync -> buffered_frames ++ ;
982+ /* buffer pic */
983+ ulist_add (& upipe_sync -> urefs , uref_to_uchain (uref ));
984+ upipe_sync -> buffered_frames ++ ;
949985
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- }
986+ /* limit buffered frames */
987+ if (unlikely (upipe_sync -> buffered_frames >= MAX_VIDEO_FRAMES )) {
988+ ulist_uref_flush (& upipe_sync -> urefs );
989+ upipe_sync -> buffered_frames = 0 ;
990+ }
955991
956- /* timer already active */
957- if (upipe_sync -> upump )
958- return ;
992+ /* timer already active */
993+ if (upipe_sync -> upump )
994+ return ;
959995
960- /* need upump mgr */
961- if (!ubase_check (upipe_sync_check_upump_mgr (upipe_sync_to_upipe (upipe_sync ))))
962- return ;
996+ /* need upump mgr */
997+ if (!ubase_check (upipe_sync_check_upump_mgr (upipe_sync_to_upipe (upipe_sync ))))
998+ return ;
963999
964- /* start timer */
965- uint64_t wait ;
966- if (now == UINT64_MAX )
967- wait = upipe_sync -> ticks_per_frame ;
968- else
1000+ /* start timer */
1001+ if (now == UINT64_MAX )
1002+ wait = upipe_sync -> ticks_per_frame ;
1003+ else
1004+ wait = pts - now ;
1005+ }
1006+ else {
9691007 wait = pts - now ;
9701008
1009+ /* too old frames */
1010+ if (now > pts + upipe_sync -> ticks_per_frame ) {
1011+ uref_free (uref );
1012+ return ;
1013+ }
1014+
1015+ /* buffer pic */
1016+ ulist_add (& upipe_sync -> urefs , uref_to_uchain (uref ));
1017+
1018+ /* need upump mgr */
1019+ if (!ubase_check (upipe_sync_check_upump_mgr (upipe_sync_to_upipe (upipe_sync ))))
1020+ return ;
1021+ }
1022+
9711023 upipe_sync -> pts = pts ;
9721024 upipe_sync_wait_upump (upipe_sync_to_upipe (upipe_sync ), wait , cb );
9731025}
@@ -997,6 +1049,7 @@ static struct upipe *upipe_sync_alloc(struct upipe_mgr *mgr,
9971049 upipe_sync -> buffered_frames = 0 ;
9981050 upipe_sync -> uref = NULL ;
9991051 ulist_init (& upipe_sync -> urefs );
1052+ upipe_sync -> frame_sync = 1 ; /* Old frame sync behaviour by default */
10001053
10011054 upipe_sync_init_urefcount (upipe );
10021055 upipe_sync_init_uclock (upipe );
@@ -1059,6 +1112,28 @@ static int upipe_sync_set_flow_def(struct upipe *upipe, struct uref *flow_def)
10591112 return UBASE_ERR_NONE ;
10601113}
10611114
1115+ /** @internal @This sets the content of an sync option.
1116+ *
1117+ * @param upipe description structure of the pipe
1118+ * @param option name of the option
1119+ * @param content content of the option
1120+ * @return an error code
1121+ */
1122+ static int upipe_sync_set_option (struct upipe * upipe ,
1123+ const char * option , const char * content )
1124+ {
1125+ struct upipe_sync * upipe_sync = upipe_sync_from_upipe (upipe );
1126+ if (!option || !content )
1127+ return UBASE_ERR_INVALID ;
1128+
1129+ if (!strcmp (option , "frame-sync" ))
1130+ upipe_sync -> frame_sync = atoi (content );
1131+ else
1132+ return UBASE_ERR_INVALID ;
1133+
1134+ return UBASE_ERR_NONE ;
1135+ }
1136+
10621137/** @internal @This processes control commands.
10631138 *
10641139 * @param upipe description structure of the pipe
@@ -1081,7 +1156,11 @@ static int upipe_sync_control(struct upipe *upipe, int command, va_list args)
10811156 return UBASE_ERR_NONE ;
10821157 case UPIPE_ATTACH_UPUMP_MGR :
10831158 return upipe_sync_attach_upump_mgr (upipe );
1084-
1159+ case UPIPE_SET_OPTION : {
1160+ const char * option = va_arg (args , const char * );
1161+ const char * content = va_arg (args , const char * );
1162+ return upipe_sync_set_option (upipe , option , content );
1163+ }
10851164 default :
10861165 return UBASE_ERR_UNHANDLED ;
10871166 }
0 commit comments