diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 6fd238d444..6925a8ac31 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -822,6 +822,16 @@ static void decode_postinit(H264Context *h, int setup_finished) h->sei_hflip, h->sei_vflip); } + if (h->sei_reguserdata_afd_present) { + AVFrameSideData *sd = av_frame_new_side_data(cur->f, AV_FRAME_DATA_AFD, + sizeof(uint8_t)); + if (!sd) + return; + + *sd->data = h->active_format_description; + h->sei_reguserdata_afd_present = 0; + } + // FIXME do something with unavailable reference frames /* Sort B-frames into display order */ diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 6712c7e492..49bd4641a9 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -129,6 +129,7 @@ enum { typedef enum { SEI_TYPE_BUFFERING_PERIOD = 0, ///< buffering period (H.264, D.1.1) SEI_TYPE_PIC_TIMING = 1, ///< picture timing + SEI_TYPE_USER_DATA_REGISTERED = 4, ///< registered user data as specified by Rec. ITU-T T.35 SEI_TYPE_USER_DATA_UNREGISTERED = 5, ///< unregistered user data SEI_TYPE_RECOVERY_POINT = 6, ///< recovery point (frame # to decoder sync) SEI_TYPE_FRAME_PACKING = 45, ///< frame packing arrangement @@ -674,6 +675,12 @@ typedef struct H264Context { int sei_anticlockwise_rotation; int sei_hflip, sei_vflip; + /** + * User data registered by Rec. ITU-T T.35 SEI + */ + int sei_reguserdata_afd_present; + uint8_t active_format_description; + /** * Bit set of clock types for fields/frames in picture timing SEI message. * For each found ct_type, appropriate bit is set (e.g., bit 1 for diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 0e99f05cc2..fe85ef1aff 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -42,6 +42,7 @@ void ff_h264_reset_sei(H264Context *h) h->sei_buffering_period_present = 0; h->sei_frame_packing_present = 0; h->sei_display_orientation_present = 0; + h->sei_reguserdata_afd_present = 0; } static int decode_picture_timing(H264Context *h) @@ -102,6 +103,51 @@ static int decode_picture_timing(H264Context *h) return 0; } +static int decode_registered_user_data(H264Context *h, int size) +{ + uint32_t country_code; + uint32_t user_identifier; + int flag; + + if (size < 7) + return AVERROR_INVALIDDATA; + size -= 7; + + country_code = get_bits(&h->gb, 8); // itu_t_t35_country_code + if (country_code == 0xFF) { + skip_bits(&h->gb, 8); // itu_t_t35_country_code_extension_byte + size--; + } + + /* itu_t_t35_payload_byte follows */ + skip_bits(&h->gb, 8); // terminal provider code + skip_bits(&h->gb, 8); // terminal provider oriented code + user_identifier = get_bits_long(&h->gb, 32); + + switch (user_identifier) { + case MKBETAG('D', 'T', 'G', '1'): // afd_data + if (size-- < 1) + return AVERROR_INVALIDDATA; + skip_bits(&h->gb, 1); // 0 + flag = get_bits(&h->gb, 1); // active_format_flag + skip_bits(&h->gb, 6); // reserved + + if (flag) { + if (size-- < 1) + return AVERROR_INVALIDDATA; + skip_bits(&h->gb, 4); // reserved + h->active_format_description = get_bits(&h->gb, 4); + h->sei_reguserdata_afd_present = 1; + } + break; + default: + skip_bits(&h->gb, size * 8); + break; + } + + return 0; +} + static int decode_unregistered_user_data(H264Context *h, int size) { uint8_t user_data[16 + 256]; @@ -247,6 +293,9 @@ int ff_h264_decode_sei(H264Context *h) case SEI_TYPE_PIC_TIMING: // Picture timing SEI ret = decode_picture_timing(h); break; + case SEI_TYPE_USER_DATA_REGISTERED: + ret = decode_registered_user_data(h, size); + break; case SEI_TYPE_USER_DATA_UNREGISTERED: ret = decode_unregistered_user_data(h, size); break; diff --git a/libavcodec/version.h b/libavcodec/version.h index f043b3f993..b0643cc922 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -30,7 +30,7 @@ #define LIBAVCODEC_VERSION_MAJOR 56 #define LIBAVCODEC_VERSION_MINOR 29 -#define LIBAVCODEC_VERSION_MICRO 0 +#define LIBAVCODEC_VERSION_MICRO 1 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \