diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index 5f9a9c46ef..ec1cbc6a66 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -481,6 +481,15 @@ static inline int parse_nal_units(AVCodecParserContext *s, } } + if (p->sei.picture_timing.present) { + ret = ff_h264_sei_process_picture_timing(&p->sei.picture_timing, + sps, avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error processing the picture timing SEI\n"); + p->sei.picture_timing.present = 0; + } + } + if (sps->pic_struct_present_flag && p->sei.picture_timing.present) { switch (p->sei.picture_timing.pic_struct) { case H264_SEI_PIC_STRUCT_TOP_FIELD: diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 32d13985f3..870dd90717 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -54,30 +54,22 @@ void ff_h264_sei_uninit(H264SEIContext *h) av_buffer_unref(&h->a53_caption.buf_ref); } -static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, - const H264ParamSets *ps, void *logctx) +int ff_h264_sei_process_picture_timing(H264SEIPictureTiming *h, const SPS *sps, + void *logctx) { - int i; - const SPS *sps = ps->sps; + GetBitContext gb; - for (i = 0; ilog2_max_frame_num) && ps->sps_list[i]) - sps = (const SPS *)ps->sps_list[i]->data; - - if (!sps) { - av_log(logctx, AV_LOG_ERROR, "SPS unavailable in decode_picture_timing\n"); - return AVERROR_PS_NOT_FOUND; - } + init_get_bits(&gb, h->payload, h->payload_size_bits); if (sps->nal_hrd_parameters_present_flag || sps->vcl_hrd_parameters_present_flag) { - h->cpb_removal_delay = get_bits_long(gb, sps->cpb_removal_delay_length); - h->dpb_output_delay = get_bits_long(gb, sps->dpb_output_delay_length); + h->cpb_removal_delay = get_bits_long(&gb, sps->cpb_removal_delay_length); + h->dpb_output_delay = get_bits_long(&gb, sps->dpb_output_delay_length); } if (sps->pic_struct_present_flag) { unsigned int i, num_clock_ts; - h->pic_struct = get_bits(gb, 4); + h->pic_struct = get_bits(&gb, 4); h->ct_type = 0; if (h->pic_struct > H264_SEI_PIC_STRUCT_FRAME_TRIPLING) @@ -86,38 +78,38 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, num_clock_ts = sei_num_clock_ts_table[h->pic_struct]; h->timecode_cnt = 0; 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 counting_type, cnt_dropped_flag; - h->ct_type |= 1 << get_bits(gb, 2); - skip_bits(gb, 1); /* nuit_field_based_flag */ - counting_type = get_bits(gb, 5); /* counting_type */ - full_timestamp_flag = get_bits(gb, 1); - skip_bits(gb, 1); /* discontinuity_flag */ - cnt_dropped_flag = get_bits(gb, 1); /* cnt_dropped_flag */ + h->ct_type |= 1 << get_bits(&gb, 2); + skip_bits(&gb, 1); /* nuit_field_based_flag */ + counting_type = get_bits(&gb, 5); /* counting_type */ + full_timestamp_flag = get_bits(&gb, 1); + skip_bits(&gb, 1); /* discontinuity_flag */ + cnt_dropped_flag = get_bits(&gb, 1); /* cnt_dropped_flag */ if (cnt_dropped_flag && counting_type > 1 && counting_type < 7) tc->dropframe = 1; - tc->frame = get_bits(gb, 8); /* n_frames */ + tc->frame = get_bits(&gb, 8); /* n_frames */ if (full_timestamp_flag) { tc->full = 1; - tc->seconds = get_bits(gb, 6); /* seconds_value 0..59 */ - tc->minutes = get_bits(gb, 6); /* minutes_value 0..59 */ - tc->hours = get_bits(gb, 5); /* hours_value 0..23 */ + tc->seconds = get_bits(&gb, 6); /* seconds_value 0..59 */ + tc->minutes = get_bits(&gb, 6); /* minutes_value 0..59 */ + tc->hours = get_bits(&gb, 5); /* hours_value 0..23 */ } else { tc->seconds = tc->minutes = tc->hours = tc->full = 0; - if (get_bits(gb, 1)) { /* seconds_flag */ - tc->seconds = get_bits(gb, 6); - if (get_bits(gb, 1)) { /* minutes_flag */ - tc->minutes = get_bits(gb, 6); - if (get_bits(gb, 1)) /* hours_flag */ - tc->hours = get_bits(gb, 5); + if (get_bits(&gb, 1)) { /* seconds_flag */ + tc->seconds = get_bits(&gb, 6); + if (get_bits(&gb, 1)) { /* minutes_flag */ + tc->minutes = get_bits(&gb, 6); + if (get_bits(&gb, 1)) /* hours_flag */ + tc->hours = get_bits(&gb, 5); } } } if (sps->time_offset_length > 0) - skip_bits(gb, + skip_bits(&gb, sps->time_offset_length); /* time_offset */ } } @@ -126,6 +118,28 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, h->ct_type, h->pic_struct); } + return 0; +} + +static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, + void *logctx) +{ + int index = get_bits_count(gb); + int size_bits = get_bits_left(gb); + int size = (size_bits + 7) / 8; + + if (index & 7) { + av_log(logctx, AV_LOG_ERROR, "Unaligned SEI payload\n"); + return AVERROR_INVALIDDATA; + } + if (size > sizeof(h->payload)) { + av_log(logctx, AV_LOG_ERROR, "Picture timing SEI payload too large\n"); + return AVERROR_INVALIDDATA; + } + memcpy(h->payload, gb->buffer + index / 8, size); + + h->payload_size_bits = size_bits; + h->present = 1; return 0; } @@ -436,7 +450,7 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, switch (type) { case H264_SEI_TYPE_PIC_TIMING: // Picture timing SEI - ret = decode_picture_timing(&h->picture_timing, &gb_payload, ps, logctx); + ret = decode_picture_timing(&h->picture_timing, &gb_payload, logctx); break; case H264_SEI_TYPE_USER_DATA_REGISTERED: ret = decode_registered_user_data(h, &gb_payload, logctx, size); diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index a75c3aa175..f07a5055c3 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -20,6 +20,7 @@ #define AVCODEC_H264_SEI_H #include "get_bits.h" +#include "h264_ps.h" /** * SEI message types @@ -79,6 +80,10 @@ typedef struct H264SEITimeCode { } H264SEITimeCode; typedef struct H264SEIPictureTiming { + // maximum size of pic_timing according to the spec should be 274 bits + uint8_t payload[40]; + int payload_size_bits; + int present; H264_SEI_PicStructType pic_struct; @@ -202,4 +207,10 @@ void ff_h264_sei_uninit(H264SEIContext *h); */ const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h); +/** + * Parse the contents of a picture timing message given an active SPS. + */ +int ff_h264_sei_process_picture_timing(H264SEIPictureTiming *h, const SPS *sps, + void *logctx); + #endif /* AVCODEC_H264_SEI_H */ diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index af30f6267b..c6072738d7 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1134,6 +1134,16 @@ static int h264_export_frame_props(H264Context *h) /* Signal interlacing information externally. */ /* Prioritize picture timing SEI information over used * decoding process if it exists. */ + if (h->sei.picture_timing.present) { + int ret = ff_h264_sei_process_picture_timing(&h->sei.picture_timing, sps, + h->avctx); + if (ret < 0) { + av_log(h->avctx, AV_LOG_ERROR, "Error processing a picture timing SEI\n"); + if (h->avctx->err_recognition & AV_EF_EXPLODE) + return ret; + h->sei.picture_timing.present = 0; + } + } if (sps->pic_struct_present_flag && h->sei.picture_timing.present) { H264SEIPictureTiming *pt = &h->sei.picture_timing;