Skip to content

Commit d74d5ce

Browse files
Josh de KockJDarnley
authored andcommitted
upipe-blackmagic: support timecode playback
1 parent 3a46811 commit d74d5ce

File tree

1 file changed

+91
-3
lines changed

1 file changed

+91
-3
lines changed

lib/upipe-blackmagic/upipe_blackmagic_sink.cpp

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,73 @@ extern "C" {
7878
static const unsigned max_samples = (uint64_t)48000 * 1001 / 24000;
7979
static 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+
81148
class upipe_bmd_sink_frame : public IDeckLinkVideoFrame
82149
{
83150
public:
@@ -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

164238
public:
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

Comments
 (0)