Skip to content

Commit b2f45ae

Browse files
author
Josh de Kock
committed
h264/pic_timing: support multiple timecodes
1 parent 8073270 commit b2f45ae

File tree

4 files changed

+74
-42
lines changed

4 files changed

+74
-42
lines changed

libavcodec/h264_sei.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb,
8484
return AVERROR_INVALIDDATA;
8585

8686
num_clock_ts = sei_num_clock_ts_table[h->pic_struct];
87+
h->timecode_cnt = 0;
8788
for (i = 0; i < num_clock_ts; i++) {
8889
if (get_bits(gb, 1)) { /* clock_timestamp_flag */
90+
H264SEITimeCode *tc = &h->timecode[h->timecode_cnt++];
8991
unsigned int full_timestamp_flag;
9092
unsigned int counting_type, cnt_dropped_flag;
9193
h->ct_type |= 1 << get_bits(gb, 2);
@@ -95,20 +97,21 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb,
9597
skip_bits(gb, 1); /* discontinuity_flag */
9698
cnt_dropped_flag = get_bits(gb, 1); /* cnt_dropped_flag */
9799
if (cnt_dropped_flag && counting_type > 1 && counting_type < 7)
98-
h->tc_dropframe = 1;
99-
h->tc_frames = get_bits(gb, 8); /* n_frames */
100+
tc->dropframe = 1;
101+
tc->frame = get_bits(gb, 8); /* n_frames */
100102
if (full_timestamp_flag) {
101-
h->fulltc_received = 1;
102-
h->tc_seconds = get_bits(gb, 6); /* seconds_value 0..59 */
103-
h->tc_minutes = get_bits(gb, 6); /* minutes_value 0..59 */
104-
h->tc_hours = get_bits(gb, 5); /* hours_value 0..23 */
103+
tc->full = 1;
104+
tc->seconds = get_bits(gb, 6); /* seconds_value 0..59 */
105+
tc->minutes = get_bits(gb, 6); /* minutes_value 0..59 */
106+
tc->hours = get_bits(gb, 5); /* hours_value 0..23 */
105107
} else {
108+
tc->seconds = tc->minutes = tc->hours = tc->full = 0;
106109
if (get_bits(gb, 1)) { /* seconds_flag */
107-
h->tc_seconds = get_bits(gb, 6);
110+
tc->seconds = get_bits(gb, 6);
108111
if (get_bits(gb, 1)) { /* minutes_flag */
109-
h->tc_minutes = get_bits(gb, 6);
112+
tc->minutes = get_bits(gb, 6);
110113
if (get_bits(gb, 1)) /* hours_flag */
111-
h->tc_minutes = get_bits(gb, 5);
114+
tc->hours = get_bits(gb, 5);
112115
}
113116
}
114117
}

libavcodec/h264_sei.h

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ typedef enum {
6767
H264_SEI_FPA_TYPE_2D = 6,
6868
} H264_SEI_FpaType;
6969

70+
typedef struct H264SEITimeCode {
71+
/* When not continuously receiving full timecodes, we have to reference
72+
the previous timecode received */
73+
int full;
74+
int frame;
75+
int seconds;
76+
int minutes;
77+
int hours;
78+
int dropframe;
79+
} H264SEITimeCode;
80+
7081
typedef struct H264SEIPictureTiming {
7182
int present;
7283
H264_SEI_PicStructType pic_struct;
@@ -88,14 +99,15 @@ typedef struct H264SEIPictureTiming {
8899
*/
89100
int cpb_removal_delay;
90101

91-
/* When not continuously receiving full timecodes, we have to reference
92-
the previous timecode received */
93-
int fulltc_received;
94-
int tc_frames;
95-
int tc_seconds;
96-
int tc_minutes;
97-
int tc_hours;
98-
int tc_dropframe;
102+
/**
103+
* Maximum three timecodes in a pic_timing SEI.
104+
*/
105+
H264SEITimeCode timecode[3];
106+
107+
/**
108+
* Number of timecode in use
109+
*/
110+
int timecode_cnt;
99111
} H264SEIPictureTiming;
100112

101113
typedef struct H264SEIAFD {

libavcodec/h264_slice.c

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,41 +1287,48 @@ static int h264_export_frame_props(H264Context *h)
12871287
h->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
12881288
}
12891289

1290-
if (h->sei.picture_timing.fulltc_received) {
1290+
if (h->sei.picture_timing.timecode_cnt > 0) {
12911291
int64_t tc = 0;
1292-
uint32_t frames;
1292+
uint32_t *tc_sd;
12931293

12941294
AVFrameSideData *tcside = av_frame_new_side_data(cur->f,
12951295
AV_FRAME_DATA_S12M_TIMECODE,
1296-
sizeof(uint32_t));
1296+
sizeof(uint32_t)*4);
12971297
if (!tcside)
12981298
return AVERROR(ENOMEM);
12991299

1300-
/* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
1301-
See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
1302-
if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) {
1303-
frames = h->sei.picture_timing.tc_frames / 2;
1304-
if (h->sei.picture_timing.tc_frames % 2 == 1) {
1305-
if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0)
1306-
tc |= (1 << 7);
1307-
else
1308-
tc |= (1 << 23);
1300+
tc_sd = (uint32_t*)tcside->data;
1301+
tc_sd[0] = h->sei.picture_timing.timecode_cnt;
1302+
1303+
for (int i = 0; i < tc_sd[0]; i++) {
1304+
uint32_t frames;
1305+
1306+
/* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
1307+
See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
1308+
if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) {
1309+
frames = h->sei.picture_timing.timecode[i].frame / 2;
1310+
if (h->sei.picture_timing.timecode[i].frame % 2 == 1) {
1311+
if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0)
1312+
tc |= (1 << 7);
1313+
else
1314+
tc |= (1 << 23);
1315+
}
1316+
} else {
1317+
frames = h->sei.picture_timing.timecode[i].frame;
13091318
}
1310-
} else {
1311-
frames = h->sei.picture_timing.tc_frames;
1312-
}
13131319

1314-
tc |= h->sei.picture_timing.tc_dropframe << 30;
1315-
tc |= (frames / 10) << 28;
1316-
tc |= (frames % 10) << 24;
1317-
tc |= (h->sei.picture_timing.tc_seconds / 10) << 20;
1318-
tc |= (h->sei.picture_timing.tc_seconds % 10) << 16;
1319-
tc |= (h->sei.picture_timing.tc_minutes / 10) << 12;
1320-
tc |= (h->sei.picture_timing.tc_minutes % 10) << 8;
1321-
tc |= (h->sei.picture_timing.tc_hours / 10) << 4;
1322-
tc |= (h->sei.picture_timing.tc_hours % 10);
1320+
tc |= h->sei.picture_timing.timecode[i].dropframe << 30;
1321+
tc |= (frames / 10) << 28;
1322+
tc |= (frames % 10) << 24;
1323+
tc |= (h->sei.picture_timing.timecode[i].seconds / 10) << 20;
1324+
tc |= (h->sei.picture_timing.timecode[i].seconds % 10) << 16;
1325+
tc |= (h->sei.picture_timing.timecode[i].minutes / 10) << 12;
1326+
tc |= (h->sei.picture_timing.timecode[i].minutes % 10) << 8;
1327+
tc |= (h->sei.picture_timing.timecode[i].hours / 10) << 4;
1328+
tc |= (h->sei.picture_timing.timecode[i].hours % 10);
13231329

1324-
memcpy(tcside->data, &tc, sizeof(uint32_t));
1330+
tc_sd[i + 1] = tc;
1331+
}
13251332
}
13261333

13271334
if (h->sei.alternative_transfer.present &&

libavfilter/vf_showinfo.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "libavutil/spherical.h"
3333
#include "libavutil/stereo3d.h"
3434
#include "libavutil/timestamp.h"
35+
#include "libavutil/timecode.h"
3536

3637
#include "avfilter.h"
3738
#include "internal.h"
@@ -174,6 +175,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
174175
case AV_FRAME_DATA_STEREO3D:
175176
dump_stereo3d(ctx, sd);
176177
break;
178+
case AV_FRAME_DATA_S12M_TIMECODE: {
179+
uint32_t *tc = (uint32_t*)sd->data;
180+
for (int j = 1; j < tc[0]; j++) {
181+
char tcbuf[AV_TIMECODE_STR_SIZE];
182+
av_timecode_make_smpte_tc_string(tcbuf, tc[j], 0);
183+
av_log(ctx, AV_LOG_INFO, "timecode - %s%s", tcbuf, j != tc[0] - 1 ? ", " : "");
184+
}
185+
break;
186+
}
177187
case AV_FRAME_DATA_DISPLAYMATRIX:
178188
av_log(ctx, AV_LOG_INFO, "displaymatrix: rotation of %.2f degrees",
179189
av_display_rotation_get((int32_t *)sd->data));

0 commit comments

Comments
 (0)