@@ -78,6 +78,73 @@ extern "C" {
7878static const unsigned max_samples = (uint64_t )48000 * 1001 / 24000 ;
7979static const size_t audio_buf_size = max_samples * DECKLINK_CHANNELS * sizeof (int32_t );
8080
81+ inline static unsigned bcd2uint (uint8_t bcd)
82+ {
83+ unsigned low = bcd & 0xf ;
84+ unsigned high = bcd >> 4 ;
85+ if (low > 9 || high > 9 )
86+ return 0 ;
87+ return low + 10 *high;
88+ }
89+
90+ class upipe_bmd_sink_timecode : public IDeckLinkTimecode
91+ {
92+ public:
93+ upipe_bmd_sink_timecode (uint32_t _BCD) : BCD(_BCD) { }
94+
95+ virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD (void ) {
96+ return BCD;
97+ }
98+
99+ virtual HRESULT STDMETHODCALLTYPE GetComponents (uint8_t *hours, uint8_t *minutes, uint8_t *seconds, uint8_t *frames) {
100+ *hours = bcd2uint ( BCD & 0x3f );
101+ *minutes = bcd2uint ((BCD >> 8 ) & 0x7f );
102+ *seconds = bcd2uint ((BCD >> 16 ) & 0x7f );
103+ *frames = bcd2uint ((BCD >> 24 ) & 0x3f );
104+ return S_OK;
105+ }
106+
107+ virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags () {
108+ return !!(BCD & (1 << 30 )) ? bmdTimecodeIsDropFrame : bmdTimecodeFlagDefault;
109+ }
110+
111+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeUserBits (BMDTimecodeUserBits *userBits) {
112+ *userBits = GetBCD ();
113+ return S_OK;
114+ }
115+
116+ virtual HRESULT GetString (const char **timecode) {
117+ uint8_t h, m, s, f, drop = (this ->GetFlags () == bmdTimecodeIsDropFrame);
118+ GetComponents (&h, &m, &s, &f);
119+
120+ if (!(*timecode = (const char *)calloc (16 , sizeof (char )))) {
121+ return S_FALSE;
122+ }
123+
124+ snprintf ((char *)*timecode, 16 , " %02u:%02u:%02u%c%02u" , h, m, s, drop ? ' ;' : ' :' , f);
125+ return S_OK;
126+ }
127+
128+ virtual ULONG STDMETHODCALLTYPE AddRef (void ) {
129+ return uatomic_fetch_add (&refcount, 1 ) + 1 ;
130+ }
131+
132+ virtual ULONG STDMETHODCALLTYPE Release (void ) {
133+ uint32_t new_ref = uatomic_fetch_sub (&refcount, 1 ) - 1 ;
134+ if (new_ref == 0 )
135+ delete this ;
136+ return new_ref;
137+ }
138+
139+ virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID iid, LPVOID *ppv) {
140+ return E_NOINTERFACE;
141+ }
142+
143+ private:
144+ uint32_t BCD;
145+ uatomic_uint32_t refcount;
146+ };
147+
81148class upipe_bmd_sink_frame : public IDeckLinkVideoFrame
82149{
83150public:
@@ -118,8 +185,14 @@ class upipe_bmd_sink_frame : public IDeckLinkVideoFrame
118185 }
119186
120187 virtual HRESULT STDMETHODCALLTYPE GetTimecode (BMDTimecodeFormat format,
121- IDeckLinkTimecode **timecode) {
122- *timecode = NULL ;
188+ IDeckLinkTimecode **_timecode) {
189+ timecode->AddRef ();
190+ *_timecode = timecode;
191+ return S_FALSE;
192+ }
193+
194+ virtual HRESULT STDMETHODCALLTYPE SetTimecode (upipe_bmd_sink_timecode &_timecode) {
195+ timecode = &_timecode;
123196 return S_FALSE;
124197 }
125198
@@ -160,6 +233,7 @@ class upipe_bmd_sink_frame : public IDeckLinkVideoFrame
160233
161234 uatomic_uint32_t refcount;
162235 IDeckLinkVideoFrameAncillary *frame_anc;
236+ upipe_bmd_sink_timecode *timecode;
163237
164238public:
165239 uint64_t pts;
@@ -325,6 +399,9 @@ struct upipe_bmd_sink {
325399 /* * pass through teletext */
326400 uatomic_uint32_t ttx;
327401
402+ /* * pass through timecode */
403+ uatomic_uint32_t timecode;
404+
328405 /* * last frame output */
329406 upipe_bmd_sink_frame *video_frame;
330407
@@ -987,8 +1064,17 @@ static upipe_bmd_sink_frame *get_video_frame(struct upipe *upipe,
9871064 pthread_mutex_unlock (&upipe_bmd_sink->lock );
9881065#endif
9891066
990- video_frame->SetAncillaryData (ancillary);
1067+ if (uatomic_load (&upipe_bmd_sink->timecode )) {
1068+ const uint32_t *tc_data;
1069+ size_t tc_data_size;
1070+ // bmdVideoOutputRP188
1071+ if (ubase_check (uref_pic_get_s12m (uref, (const uint8_t **)&tc_data, &tc_data_size))) {
1072+ upipe_bmd_sink_timecode timecode (tc_data[1 ]);
1073+ video_frame->SetTimecode (timecode);
1074+ }
1075+ }
9911076
1077+ video_frame->SetAncillaryData (ancillary);
9921078 video_frame->AddRef (); // we're gonna buffer this frame
9931079 upipe_bmd_sink->video_frame = video_frame;
9941080
@@ -1883,6 +1969,8 @@ static int upipe_bmd_sink_set_option(struct upipe *upipe,
18831969 uatomic_store (&upipe_bmd_sink->cc , strcmp (v, " 0" ));
18841970 } else if (!strcmp (k, " teletext" )) {
18851971 uatomic_store (&upipe_bmd_sink->ttx , strcmp (v, " 0" ));
1972+ } else if (!strcmp (k, " timecode" )) {
1973+ uatomic_store (&upipe_bmd_sink->timecode , strcmp (v, " 0" ));
18861974 } else
18871975 return UBASE_ERR_INVALID;
18881976
0 commit comments