Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/upipe/udict.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ enum udict_type {
/** p.afd */
UDICT_TYPE_PIC_AFD,
/** p.cea_708 */
UDICT_TYPE_PIC_CEA_708
UDICT_TYPE_PIC_CEA_708,
/** p.s12m */
UDICT_TYPE_PIC_S12M
};

/** @This defines standard commands which udict modules may implement. */
Expand Down
1 change: 1 addition & 0 deletions include/upipe/uref_pic.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ UREF_ATTR_VOID_SH(pic, bf, UDICT_TYPE_PIC_BF, bottom field present)
UREF_ATTR_VOID_SH(pic, tff, UDICT_TYPE_PIC_TFF, top field first)
UREF_ATTR_SMALL_UNSIGNED_SH(pic, afd, UDICT_TYPE_PIC_AFD, active format description)
UREF_ATTR_OPAQUE_SH(pic, cea_708, UDICT_TYPE_PIC_CEA_708, cea-708 captions)
UREF_ATTR_OPAQUE_SH(pic, s12m, UDICT_TYPE_PIC_S12M, SMPTE 12M timecode)
UREF_ATTR_UNSIGNED(pic, original_height, "p.original_height", original picture height before chunking)

/** @This returns a new uref pointing to a new ubuf pointing to a picture.
Expand Down
5 changes: 5 additions & 0 deletions lib/upipe-av/upipe_avcodec_decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,11 @@ static void upipe_avcdec_output_pic(struct upipe *upipe, struct upump **upump_p)
if (side_data)
uref_pic_set_cea_708(uref, side_data->data, side_data->size);

side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE);
if (side_data) {
uref_pic_set_s12m(uref, side_data->data, side_data->size);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using the AV_FRAME_DATA_S12M_TIMECODE macro to check for availability :

#ifdef AV_FRAME_DATA_S12M_TIMECODE
     side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE);
     if (side_data) {
         uref_pic_set_s12m(uref, side_data->data, side_data->size);
     }
#endif

/* various time-related attributes */
upipe_avcdec_set_time_attributes(upipe, uref);

Expand Down
94 changes: 91 additions & 3 deletions lib/upipe-blackmagic/upipe_blackmagic_sink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,73 @@ extern "C" {
static const unsigned max_samples = (uint64_t)48000 * 1001 / 24000;
static const size_t audio_buf_size = max_samples * DECKLINK_CHANNELS * sizeof(int32_t);

inline static unsigned bcd2uint(uint8_t bcd)
{
unsigned low = bcd & 0xf;
unsigned high = bcd >> 4;
if (low > 9 || high > 9)
return 0;
return low + 10*high;
}

class upipe_bmd_sink_timecode : public IDeckLinkTimecode
{
public:
upipe_bmd_sink_timecode(uint32_t _BCD) : BCD(_BCD) { }

virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD (void) {
return BCD;
}

virtual HRESULT STDMETHODCALLTYPE GetComponents(uint8_t *hours, uint8_t *minutes, uint8_t *seconds, uint8_t *frames) {
*hours = bcd2uint( BCD & 0x3f);
*minutes = bcd2uint((BCD >> 8) & 0x7f);
*seconds = bcd2uint((BCD >> 16) & 0x7f);
*frames = bcd2uint((BCD >> 24) & 0x3f);
return S_OK;
}

virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags() {
return !!(BCD & (1 << 30)) ? bmdTimecodeIsDropFrame : bmdTimecodeFlagDefault;
}

virtual HRESULT STDMETHODCALLTYPE GetTimecodeUserBits(BMDTimecodeUserBits *userBits) {
*userBits = GetBCD();
return S_OK;
}

virtual HRESULT GetString (const char **timecode) {
uint8_t h, m, s, f, drop = (this->GetFlags() == bmdTimecodeIsDropFrame);
GetComponents(&h, &m, &s, &f);

if (!(*timecode = (const char*)calloc(16, sizeof(char)))) {
return S_FALSE;
}

snprintf((char*)*timecode, 16, "%02u:%02u:%02u%c%02u", h, m, s, drop ? ';' : ':', f);
return S_OK;
}

virtual ULONG STDMETHODCALLTYPE AddRef(void) {
return uatomic_fetch_add(&refcount, 1) + 1;
}

virtual ULONG STDMETHODCALLTYPE Release(void) {
uint32_t new_ref = uatomic_fetch_sub(&refcount, 1) - 1;
if (new_ref == 0)
delete this;
return new_ref;
}

virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) {
return E_NOINTERFACE;
}

private:
uint32_t BCD;
uatomic_uint32_t refcount;
};

class upipe_bmd_sink_frame : public IDeckLinkVideoFrame
{
public:
Expand Down Expand Up @@ -117,8 +184,14 @@ class upipe_bmd_sink_frame : public IDeckLinkVideoFrame
}

virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format,
IDeckLinkTimecode **timecode) {
*timecode = NULL;
IDeckLinkTimecode **_timecode) {
timecode->AddRef();
*_timecode = timecode;
return S_FALSE;
}

virtual HRESULT STDMETHODCALLTYPE SetTimecode(upipe_bmd_sink_timecode &_timecode) {
timecode = &_timecode;
return S_FALSE;
}

Expand Down Expand Up @@ -159,6 +232,7 @@ class upipe_bmd_sink_frame : public IDeckLinkVideoFrame

uatomic_uint32_t refcount;
IDeckLinkVideoFrameAncillary *frame_anc;
upipe_bmd_sink_timecode *timecode;

public:
uint64_t pts;
Expand Down Expand Up @@ -307,6 +381,9 @@ struct upipe_bmd_sink {
/** pass through teletext */
uatomic_uint32_t ttx;

/** pass through timecode */
uatomic_uint32_t timecode;

/** last frame output */
upipe_bmd_sink_frame *video_frame;
};
Expand Down Expand Up @@ -787,8 +864,17 @@ static upipe_bmd_sink_frame *get_video_frame(struct upipe *upipe,
uref_free(subpic);
}

video_frame->SetAncillaryData(ancillary);
if (uatomic_load(&upipe_bmd_sink->timecode)) {
const uint32_t *tc_data;
size_t tc_data_size;
// bmdVideoOutputRP188
if (ubase_check(uref_pic_get_s12m(uref, (const uint8_t**)&tc_data, &tc_data_size))) {
upipe_bmd_sink_timecode timecode(tc_data[1]);
video_frame->SetTimecode(timecode);
}
}

video_frame->SetAncillaryData(ancillary);
video_frame->AddRef(); // we're gonna buffer this frame
upipe_bmd_sink->video_frame = video_frame;

Expand Down Expand Up @@ -1609,6 +1695,8 @@ static int upipe_bmd_sink_set_option(struct upipe *upipe,
uatomic_store(&upipe_bmd_sink->cc, strcmp(v, "0"));
} else if (!strcmp(k, "teletext")) {
uatomic_store(&upipe_bmd_sink->ttx, strcmp(v, "0"));
} else if (!strcmp(k, "timecode")) {
uatomic_store(&upipe_bmd_sink->timecode, strcmp(v, "0"));
} else
return UBASE_ERR_INVALID;

Expand Down
6 changes: 6 additions & 0 deletions lib/upipe-blackmagic/upipe_blackmagic_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,12 @@ HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(
else if (upipe_bmd_src->tff)
uref_pic_set_tff(uref);

IDeckLinkTimecode *timecode;
if (VideoFrame->GetTimecode(bmdTimecodeRP188Any, &timecode) == S_OK) {
uint32_t bcd = timecode->GetBCD();
uref_pic_set_s12m(uref, (uint8_t*)&bcd, sizeof(bcd));
}

if (!uqueue_push(&upipe_bmd_src->uqueue, uref))
uref_free(uref);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/upipe/udict_inline.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ static const struct inline_shorthand inline_shorthands[] = {
{ "p.bf", UDICT_TYPE_VOID },
{ "p.tff", UDICT_TYPE_VOID },
{ "p.afd", UDICT_TYPE_SMALL_UNSIGNED },
{ "p.cea_708", UDICT_TYPE_OPAQUE }
{ "p.cea_708", UDICT_TYPE_OPAQUE },
{ "p.s12m", UDICT_TYPE_OPAQUE }
};

/** @This stores the size of the value of basic attribute types. */
Expand Down