|
|
|
@ -1287,42 +1287,49 @@ static int h264_export_frame_props(H264Context *h) |
|
|
|
|
h->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (h->sei.picture_timing.fulltc_received) { |
|
|
|
|
if (h->sei.picture_timing.timecode_cnt > 0) { |
|
|
|
|
uint32_t tc = 0; |
|
|
|
|
uint32_t frames; |
|
|
|
|
uint32_t *tc_sd; |
|
|
|
|
|
|
|
|
|
AVFrameSideData *tcside = av_frame_new_side_data(cur->f, |
|
|
|
|
AV_FRAME_DATA_S12M_TIMECODE, |
|
|
|
|
sizeof(uint32_t)); |
|
|
|
|
sizeof(uint32_t)*4); |
|
|
|
|
if (!tcside) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
/* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
|
|
|
|
|
See SMPTE ST 12-1:2014 Sec 12.1 for more info. */ |
|
|
|
|
if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) { |
|
|
|
|
frames = h->sei.picture_timing.tc_frames / 2; |
|
|
|
|
if (h->sei.picture_timing.tc_frames % 2 == 1) { |
|
|
|
|
if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0) |
|
|
|
|
tc |= (1 << 7); |
|
|
|
|
else |
|
|
|
|
tc |= (1 << 23); |
|
|
|
|
tc_sd = (uint32_t*)tcside->data; |
|
|
|
|
tc_sd[0] = h->sei.picture_timing.timecode_cnt; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < tc_sd[0]; i++) { |
|
|
|
|
uint32_t frames; |
|
|
|
|
|
|
|
|
|
/* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
|
|
|
|
|
See SMPTE ST 12-1:2014 Sec 12.1 for more info. */ |
|
|
|
|
if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) { |
|
|
|
|
frames = h->sei.picture_timing.timecode[i].frame / 2; |
|
|
|
|
if (h->sei.picture_timing.timecode[i].frame % 2 == 1) { |
|
|
|
|
if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0) |
|
|
|
|
tc |= (1 << 7); |
|
|
|
|
else |
|
|
|
|
tc |= (1 << 23); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
frames = h->sei.picture_timing.timecode[i].frame; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
frames = h->sei.picture_timing.tc_frames; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tc |= h->sei.picture_timing.tc_dropframe << 30; |
|
|
|
|
tc |= (frames / 10) << 28; |
|
|
|
|
tc |= (frames % 10) << 24; |
|
|
|
|
tc |= (h->sei.picture_timing.tc_seconds / 10) << 20; |
|
|
|
|
tc |= (h->sei.picture_timing.tc_seconds % 10) << 16; |
|
|
|
|
tc |= (h->sei.picture_timing.tc_minutes / 10) << 12; |
|
|
|
|
tc |= (h->sei.picture_timing.tc_minutes % 10) << 8; |
|
|
|
|
tc |= (h->sei.picture_timing.tc_hours / 10) << 4; |
|
|
|
|
tc |= (h->sei.picture_timing.tc_hours % 10); |
|
|
|
|
tc |= h->sei.picture_timing.timecode[i].dropframe << 30; |
|
|
|
|
tc |= (frames / 10) << 28; |
|
|
|
|
tc |= (frames % 10) << 24; |
|
|
|
|
tc |= (h->sei.picture_timing.timecode[i].seconds / 10) << 20; |
|
|
|
|
tc |= (h->sei.picture_timing.timecode[i].seconds % 10) << 16; |
|
|
|
|
tc |= (h->sei.picture_timing.timecode[i].minutes / 10) << 12; |
|
|
|
|
tc |= (h->sei.picture_timing.timecode[i].minutes % 10) << 8; |
|
|
|
|
tc |= (h->sei.picture_timing.timecode[i].hours / 10) << 4; |
|
|
|
|
tc |= (h->sei.picture_timing.timecode[i].hours % 10); |
|
|
|
|
|
|
|
|
|
memcpy(tcside->data, &tc, sizeof(uint32_t)); |
|
|
|
|
h->sei.picture_timing.fulltc_received = 0; |
|
|
|
|
tc_sd[i + 1] = tc; |
|
|
|
|
} |
|
|
|
|
h->sei.picture_timing.timecode_cnt = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (h->sei.alternative_transfer.present && |
|
|
|
|