summaryrefslogtreecommitdiff
path: root/libavdevice
diff options
context:
space:
mode:
authorMarton Balint <cus@passwd.hu>2020-09-05 23:29:24 +0200
committerMarton Balint <cus@passwd.hu>2020-12-03 18:32:57 +0100
commitff373bb4a87a5b17dfa82aba5c7e74b125298fa8 (patch)
tree4198d61592a79d804d3fc0fce7b3ccc760351ee3 /libavdevice
parenteca12f4d5a9231b0e6b71f55525518f104877ee6 (diff)
avdevice/decklink_dec: add support for 50/60 fps timecode
Signed-off-by: Marton Balint <cus@passwd.hu>
Diffstat (limited to 'libavdevice')
-rw-r--r--libavdevice/decklink_dec.cpp64
1 files changed, 52 insertions, 12 deletions
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 2e41b587e8..090437a6b5 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -789,6 +789,52 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame,
return pts;
}
+int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational frame_rate, BMDTimecodeFormat tc_format, IDeckLinkVideoInputFrame *videoFrame)
+{
+ IDeckLinkTimecode *timecode;
+ int ret = AVERROR(ENOENT);
+#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
+ int hfr = (tc_format == bmdTimecodeRP188HighFrameRate);
+#else
+ int hfr = 0;
+#endif
+ if (videoFrame->GetTimecode(tc_format, &timecode) == S_OK) {
+ uint8_t hh, mm, ss, ff;
+ if (timecode->GetComponents(&hh, &mm, &ss, &ff) == S_OK) {
+ int flags = (timecode->GetFlags() & bmdTimecodeIsDropFrame) ? AV_TIMECODE_FLAG_DROPFRAME : 0;
+ if (!hfr && av_cmp_q(frame_rate, av_make_q(30, 1)) == 1)
+ ff = ff << 1 | !!(timecode->GetFlags() & bmdTimecodeFieldMark);
+ ret = av_timecode_init_from_components(tc, frame_rate, flags, hh, mm, ss, ff, avctx);
+ }
+ timecode->Release();
+ }
+ return ret;
+}
+
+int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimecode *tc, IDeckLinkVideoInputFrame *videoFrame)
+{
+ AVRational frame_rate = ctx->video_st->r_frame_rate;
+ int ret;
+ /* 50/60 fps content has alternating VITC1 and VITC2 timecode (see SMPTE ST
+ * 12-2, section 7), so the native ordering of RP188Any (HFR, VITC1, LTC,
+ * VITC2) would not work because LTC might not contain the field flag.
+ * Therefore we query the types manually. */
+ if (ctx->tc_format == bmdTimecodeRP188Any && av_cmp_q(frame_rate, av_make_q(30, 1)) == 1) {
+#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
+ ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188HighFrameRate, videoFrame);
+ if (ret == AVERROR(ENOENT))
+#endif
+ ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188VITC1, videoFrame);
+ if (ret == AVERROR(ENOENT))
+ ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188VITC2, videoFrame);
+ if (ret == AVERROR(ENOENT))
+ ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188LTC, videoFrame);
+ } else {
+ ret = get_bmd_timecode(avctx, tc, frame_rate, ctx->tc_format, videoFrame);
+ }
+ return ret;
+}
+
HRESULT decklink_input_callback::VideoInputFrameArrived(
IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame)
{
@@ -870,22 +916,16 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
// Handle Timecode (if requested)
if (ctx->tc_format) {
- IDeckLinkTimecode *timecode;
- if (videoFrame->GetTimecode(ctx->tc_format, &timecode) == S_OK) {
- const char *tc = NULL;
- DECKLINK_STR decklink_tc;
- if (timecode->GetString(&decklink_tc) == S_OK) {
- tc = DECKLINK_STRDUP(decklink_tc);
- DECKLINK_FREE(decklink_tc);
- }
- timecode->Release();
+ AVTimecode tcr;
+ if (get_frame_timecode(avctx, ctx, &tcr, videoFrame) >= 0) {
+ char tcstr[AV_TIMECODE_STR_SIZE];
+ const char *tc = av_timecode_make_string(&tcr, tcstr, 0);
if (tc) {
AVDictionary* metadata_dict = NULL;
int metadata_len;
uint8_t* packed_metadata;
- AVTimecode tcr;
- if (av_timecode_init_from_string(&tcr, ctx->video_st->r_frame_rate, tc, ctx) >= 0) {
+ if (av_cmp_q(ctx->video_st->r_frame_rate, av_make_q(60, 1)) < 1) {
uint32_t tc_data = av_timecode_get_smpte_from_framenum(&tcr, 0);
int size = sizeof(uint32_t) * 4;
uint32_t *sd = (uint32_t *)av_packet_new_side_data(&pkt, AV_PKT_DATA_S12M_TIMECODE, size);
@@ -896,7 +936,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
}
}
- if (av_dict_set(&metadata_dict, "timecode", tc, AV_DICT_DONT_STRDUP_VAL) >= 0) {
+ if (av_dict_set(&metadata_dict, "timecode", tc, 0) >= 0) {
packed_metadata = av_packet_pack_dictionary(metadata_dict, &metadata_len);
av_dict_free(&metadata_dict);
if (packed_metadata) {