mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-24 13:56:33 +02:00
h264/pic_timing: support multiple timecodes
This commit is contained in:
parent
4241e44a3c
commit
76a8c3b522
@ -84,8 +84,10 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb,
|
|||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
|
|
||||||
num_clock_ts = sei_num_clock_ts_table[h->pic_struct];
|
num_clock_ts = sei_num_clock_ts_table[h->pic_struct];
|
||||||
|
h->timecode_cnt = 0;
|
||||||
for (i = 0; i < num_clock_ts; i++) {
|
for (i = 0; i < num_clock_ts; i++) {
|
||||||
if (get_bits(gb, 1)) { /* clock_timestamp_flag */
|
if (get_bits(gb, 1)) { /* clock_timestamp_flag */
|
||||||
|
H264SEITimeCode *tc = &h->timecode[h->timecode_cnt++];
|
||||||
unsigned int full_timestamp_flag;
|
unsigned int full_timestamp_flag;
|
||||||
unsigned int counting_type, cnt_dropped_flag;
|
unsigned int counting_type, cnt_dropped_flag;
|
||||||
h->ct_type |= 1 << get_bits(gb, 2);
|
h->ct_type |= 1 << get_bits(gb, 2);
|
||||||
@ -95,20 +97,21 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb,
|
|||||||
skip_bits(gb, 1); /* discontinuity_flag */
|
skip_bits(gb, 1); /* discontinuity_flag */
|
||||||
cnt_dropped_flag = get_bits(gb, 1); /* cnt_dropped_flag */
|
cnt_dropped_flag = get_bits(gb, 1); /* cnt_dropped_flag */
|
||||||
if (cnt_dropped_flag && counting_type > 1 && counting_type < 7)
|
if (cnt_dropped_flag && counting_type > 1 && counting_type < 7)
|
||||||
h->tc_dropframe = 1;
|
tc->dropframe = 1;
|
||||||
h->tc_frames = get_bits(gb, 8); /* n_frames */
|
tc->frame = get_bits(gb, 8); /* n_frames */
|
||||||
if (full_timestamp_flag) {
|
if (full_timestamp_flag) {
|
||||||
h->fulltc_received = 1;
|
tc->full = 1;
|
||||||
h->tc_seconds = get_bits(gb, 6); /* seconds_value 0..59 */
|
tc->seconds = get_bits(gb, 6); /* seconds_value 0..59 */
|
||||||
h->tc_minutes = get_bits(gb, 6); /* minutes_value 0..59 */
|
tc->minutes = get_bits(gb, 6); /* minutes_value 0..59 */
|
||||||
h->tc_hours = get_bits(gb, 5); /* hours_value 0..23 */
|
tc->hours = get_bits(gb, 5); /* hours_value 0..23 */
|
||||||
} else {
|
} else {
|
||||||
|
tc->seconds = tc->minutes = tc->hours = tc->full = 0;
|
||||||
if (get_bits(gb, 1)) { /* seconds_flag */
|
if (get_bits(gb, 1)) { /* seconds_flag */
|
||||||
h->tc_seconds = get_bits(gb, 6);
|
tc->seconds = get_bits(gb, 6);
|
||||||
if (get_bits(gb, 1)) { /* minutes_flag */
|
if (get_bits(gb, 1)) { /* minutes_flag */
|
||||||
h->tc_minutes = get_bits(gb, 6);
|
tc->minutes = get_bits(gb, 6);
|
||||||
if (get_bits(gb, 1)) /* hours_flag */
|
if (get_bits(gb, 1)) /* hours_flag */
|
||||||
h->tc_minutes = get_bits(gb, 5);
|
tc->hours = get_bits(gb, 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,17 @@ typedef enum {
|
|||||||
H264_SEI_FPA_TYPE_2D = 6,
|
H264_SEI_FPA_TYPE_2D = 6,
|
||||||
} H264_SEI_FpaType;
|
} H264_SEI_FpaType;
|
||||||
|
|
||||||
|
typedef struct H264SEITimeCode {
|
||||||
|
/* When not continuously receiving full timecodes, we have to reference
|
||||||
|
the previous timecode received */
|
||||||
|
int full;
|
||||||
|
int frame;
|
||||||
|
int seconds;
|
||||||
|
int minutes;
|
||||||
|
int hours;
|
||||||
|
int dropframe;
|
||||||
|
} H264SEITimeCode;
|
||||||
|
|
||||||
typedef struct H264SEIPictureTiming {
|
typedef struct H264SEIPictureTiming {
|
||||||
int present;
|
int present;
|
||||||
H264_SEI_PicStructType pic_struct;
|
H264_SEI_PicStructType pic_struct;
|
||||||
@ -88,14 +99,15 @@ typedef struct H264SEIPictureTiming {
|
|||||||
*/
|
*/
|
||||||
int cpb_removal_delay;
|
int cpb_removal_delay;
|
||||||
|
|
||||||
/* When not continuously receiving full timecodes, we have to reference
|
/**
|
||||||
the previous timecode received */
|
* Maximum three timecodes in a pic_timing SEI.
|
||||||
int fulltc_received;
|
*/
|
||||||
int tc_frames;
|
H264SEITimeCode timecode[3];
|
||||||
int tc_seconds;
|
|
||||||
int tc_minutes;
|
/**
|
||||||
int tc_hours;
|
* Number of timecode in use
|
||||||
int tc_dropframe;
|
*/
|
||||||
|
int timecode_cnt;
|
||||||
} H264SEIPictureTiming;
|
} H264SEIPictureTiming;
|
||||||
|
|
||||||
typedef struct H264SEIAFD {
|
typedef struct H264SEIAFD {
|
||||||
|
@ -1287,42 +1287,49 @@ static int h264_export_frame_props(H264Context *h)
|
|||||||
h->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
|
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 tc = 0;
|
||||||
uint32_t frames;
|
uint32_t *tc_sd;
|
||||||
|
|
||||||
AVFrameSideData *tcside = av_frame_new_side_data(cur->f,
|
AVFrameSideData *tcside = av_frame_new_side_data(cur->f,
|
||||||
AV_FRAME_DATA_S12M_TIMECODE,
|
AV_FRAME_DATA_S12M_TIMECODE,
|
||||||
sizeof(uint32_t));
|
sizeof(uint32_t)*4);
|
||||||
if (!tcside)
|
if (!tcside)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
/* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
|
tc_sd = (uint32_t*)tcside->data;
|
||||||
See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
|
tc_sd[0] = h->sei.picture_timing.timecode_cnt;
|
||||||
if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) {
|
|
||||||
frames = h->sei.picture_timing.tc_frames / 2;
|
for (int i = 0; i < tc_sd[0]; i++) {
|
||||||
if (h->sei.picture_timing.tc_frames % 2 == 1) {
|
uint32_t frames;
|
||||||
if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0)
|
|
||||||
tc |= (1 << 7);
|
/* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
|
||||||
else
|
See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
|
||||||
tc |= (1 << 23);
|
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.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);
|
||||||
|
|
||||||
|
tc_sd[i + 1] = tc;
|
||||||
}
|
}
|
||||||
|
h->sei.picture_timing.timecode_cnt = 0;
|
||||||
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);
|
|
||||||
|
|
||||||
memcpy(tcside->data, &tc, sizeof(uint32_t));
|
|
||||||
h->sei.picture_timing.fulltc_received = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->sei.alternative_transfer.present &&
|
if (h->sei.alternative_transfer.present &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user