From adf3b01158153bb82a6d7c947d4a0dab0e06d6d9 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Wed, 22 Jun 2022 12:46:05 +0200 Subject: [PATCH] avcodec/h264_sei: Don't use GetBit-API for byte-aligned reads SEI NALUs and several SEI messages are naturally byte-aligned, so reading them via the bytestream-API is more natural. Signed-off-by: Andreas Rheinhardt --- libavcodec/h264_sei.c | 145 ++++++++++++++++++++---------------------- libavcodec/h264_sei.h | 2 +- 2 files changed, 70 insertions(+), 77 deletions(-) diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 034ddb8f1c..d62a276779 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -33,6 +33,7 @@ #include "libavutil/macros.h" #include "libavutil/mem.h" #include "atsc_a53.h" +#include "bytestream.h" #include "get_bits.h" #include "golomb.h" #include "h264_ps.h" @@ -70,8 +71,10 @@ int ff_h264_sei_process_picture_timing(H264SEIPictureTiming *h, const SPS *sps, void *logctx) { GetBitContext gb; + av_unused int ret; - init_get_bits(&gb, h->payload, h->payload_size_bits); + ret = init_get_bits8(&gb, h->payload, h->payload_size_bytes); + av_assert1(ret >= 0); if (sps->nal_hrd_parameters_present_flag || sps->vcl_hrd_parameters_present_flag) { @@ -133,44 +136,36 @@ int ff_h264_sei_process_picture_timing(H264SEIPictureTiming *h, const SPS *sps, return 0; } -static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, +static int decode_picture_timing(H264SEIPictureTiming *h, GetByteContext *gb, void *logctx) { - int index = get_bits_count(gb); - int size_bits = get_bits_left(gb); - int size = (size_bits + 7) / 8; + int size = bytestream2_get_bytes_left(gb); - 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); + bytestream2_get_bufferu(gb, h->payload, size); - h->payload_size_bits = size_bits; + h->payload_size_bytes = size; h->present = 1; return 0; } -static int decode_registered_user_data_afd(H264SEIAFD *h, GetBitContext *gb, int size) +static int decode_registered_user_data_afd(H264SEIAFD *h, GetByteContext *gb) { int flag; - if (size-- < 1) + if (bytestream2_get_bytes_left(gb) <= 0) return AVERROR_INVALIDDATA; - skip_bits(gb, 1); // 0 - flag = get_bits(gb, 1); // active_format_flag - skip_bits(gb, 6); // reserved + + flag = !!(bytestream2_get_byteu(gb) & 0x40); // active_format_flag if (flag) { - if (size-- < 1) + if (bytestream2_get_bytes_left(gb) <= 0) return AVERROR_INVALIDDATA; - skip_bits(gb, 4); // reserved - h->active_format_description = get_bits(gb, 4); + h->active_format_description = bytestream2_get_byteu(gb) & 0xF; h->present = 1; } @@ -178,31 +173,26 @@ static int decode_registered_user_data_afd(H264SEIAFD *h, GetBitContext *gb, int } static int decode_registered_user_data_closed_caption(H264SEIA53Caption *h, - GetBitContext *gb, void *logctx, - int size) + GetByteContext *gb) { - if (size < 3) - return AVERROR(EINVAL); - - return ff_parse_a53_cc(&h->buf_ref, gb->buffer + get_bits_count(gb) / 8, size); + return ff_parse_a53_cc(&h->buf_ref, gb->buffer, + bytestream2_get_bytes_left(gb)); } -static int decode_registered_user_data(H264SEIContext *h, GetBitContext *gb, - void *logctx, int size) +static int decode_registered_user_data(H264SEIContext *h, GetByteContext *gb, + void *logctx) { int country_code, provider_code; - if (size < 3) + if (bytestream2_get_bytes_left(gb) < 3) return AVERROR_INVALIDDATA; - size -= 3; - country_code = get_bits(gb, 8); // itu_t_t35_country_code + country_code = bytestream2_get_byteu(gb); // itu_t_t35_country_code if (country_code == 0xFF) { - if (size < 1) + if (bytestream2_get_bytes_left(gb) < 3) return AVERROR_INVALIDDATA; - skip_bits(gb, 8); // itu_t_t35_country_code_extension_byte - size--; + bytestream2_skipu(gb, 1); // itu_t_t35_country_code_extension_byte } if (country_code != 0xB5) { // usa_country_code @@ -213,23 +203,21 @@ static int decode_registered_user_data(H264SEIContext *h, GetBitContext *gb, } /* itu_t_t35_payload_byte follows */ - provider_code = get_bits(gb, 16); + provider_code = bytestream2_get_be16u(gb); switch (provider_code) { case 0x31: { // atsc_provider_code uint32_t user_identifier; - if (size < 4) + if (bytestream2_get_bytes_left(gb) < 4) return AVERROR_INVALIDDATA; - size -= 4; - user_identifier = get_bits_long(gb, 32); + user_identifier = bytestream2_get_be32u(gb); switch (user_identifier) { case MKBETAG('D', 'T', 'G', '1'): // afd_data - return decode_registered_user_data_afd(&h->afd, gb, size); + return decode_registered_user_data_afd(&h->afd, gb); case MKBETAG('G', 'A', '9', '4'): // closed captions - return decode_registered_user_data_closed_caption(&h->a53_caption, gb, - logctx, size); + return decode_registered_user_data_closed_caption(&h->a53_caption, gb); default: av_log(logctx, AV_LOG_VERBOSE, "Unsupported User Data Registered ITU-T T35 SEI message (atsc user_identifier = 0x%04x)\n", @@ -248,11 +236,11 @@ static int decode_registered_user_data(H264SEIContext *h, GetBitContext *gb, return 0; } -static int decode_unregistered_user_data(H264SEIUnregistered *h, GetBitContext *gb, - void *logctx, int size) +static int decode_unregistered_user_data(H264SEIUnregistered *h, GetByteContext *gb, + void *logctx) { uint8_t *user_data; - int e, build, i; + int e, build, size = bytestream2_get_bytes_left(gb); AVBufferRef *buf_ref, **tmp; if (size < 16 || size >= INT_MAX - 1) @@ -268,10 +256,8 @@ static int decode_unregistered_user_data(H264SEIUnregistered *h, GetBitContext * return AVERROR(ENOMEM); user_data = buf_ref->data; - for (i = 0; i < size; i++) - user_data[i] = get_bits(gb, 8); - - user_data[i] = 0; + bytestream2_get_bufferu(gb, user_data, size); + user_data[size] = 0; buf_ref->size = size; h->buf_ref[h->nb_buf_ref++] = buf_ref; @@ -384,36 +370,36 @@ static int decode_display_orientation(H264SEIDisplayOrientation *h, return 0; } -static int decode_green_metadata(H264SEIGreenMetaData *h, GetBitContext *gb) +static int decode_green_metadata(H264SEIGreenMetaData *h, GetByteContext *gb) { - h->green_metadata_type = get_bits(gb, 8); + h->green_metadata_type = bytestream2_get_byte(gb); if (h->green_metadata_type == 0) { - h->period_type = get_bits(gb, 8); + h->period_type = bytestream2_get_byte(gb); if (h->period_type == 2) - h->num_seconds = get_bits(gb, 16); + h->num_seconds = bytestream2_get_be16(gb); else if (h->period_type == 3) - h->num_pictures = get_bits(gb, 16); + h->num_pictures = bytestream2_get_be16(gb); - h->percent_non_zero_macroblocks = get_bits(gb, 8); - h->percent_intra_coded_macroblocks = get_bits(gb, 8); - h->percent_six_tap_filtering = get_bits(gb, 8); - h->percent_alpha_point_deblocking_instance = get_bits(gb, 8); + h->percent_non_zero_macroblocks = bytestream2_get_byte(gb); + h->percent_intra_coded_macroblocks = bytestream2_get_byte(gb); + h->percent_six_tap_filtering = bytestream2_get_byte(gb); + h->percent_alpha_point_deblocking_instance = bytestream2_get_byte(gb); } else if (h->green_metadata_type == 1) { - h->xsd_metric_type = get_bits(gb, 8); - h->xsd_metric_value = get_bits(gb, 16); + h->xsd_metric_type = bytestream2_get_byte(gb); + h->xsd_metric_value = bytestream2_get_be16(gb); } return 0; } static int decode_alternative_transfer(H264SEIAlternativeTransfer *h, - GetBitContext *gb) + GetByteContext *gb) { h->present = 1; - h->preferred_transfer_characteristics = get_bits(gb, 8); + h->preferred_transfer_characteristics = bytestream2_get_byte(gb); return 0; } @@ -463,45 +449,52 @@ static int decode_film_grain_characteristics(H264SEIFilmGrainCharacteristics *h, int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, const H264ParamSets *ps, void *logctx) { + GetByteContext gbyte; int master_ret = 0; - while (get_bits_left(gb) > 16 && show_bits(gb, 16)) { + av_assert1((get_bits_count(gb) % 8) == 0); + bytestream2_init(&gbyte, gb->buffer + get_bits_count(gb) / 8, + get_bits_left(gb) / 8); + + while (bytestream2_get_bytes_left(&gbyte) > 2 && bytestream2_peek_ne16(&gbyte)) { + GetByteContext gbyte_payload; GetBitContext gb_payload; int type = 0; unsigned size = 0; int ret = 0; do { - if (get_bits_left(gb) < 8) + if (bytestream2_get_bytes_left(&gbyte) <= 0) return AVERROR_INVALIDDATA; - type += show_bits(gb, 8); - } while (get_bits(gb, 8) == 255); + type += bytestream2_peek_byteu(&gbyte); + } while (bytestream2_get_byteu(&gbyte) == 255); do { - if (get_bits_left(gb) < 8) + if (bytestream2_get_bytes_left(&gbyte) <= 0) return AVERROR_INVALIDDATA; - size += show_bits(gb, 8); - } while (get_bits(gb, 8) == 255); + size += bytestream2_peek_byteu(&gbyte); + } while (bytestream2_get_byteu(&gbyte) == 255); - if (size > get_bits_left(gb) / 8) { + if (size > bytestream2_get_bytes_left(&gbyte)) { av_log(logctx, AV_LOG_ERROR, "SEI type %d size %d truncated at %d\n", - type, 8*size, get_bits_left(gb)); + type, size, bytestream2_get_bytes_left(&gbyte)); return AVERROR_INVALIDDATA; } - ret = init_get_bits8(&gb_payload, gb->buffer + get_bits_count(gb) / 8, size); + bytestream2_init (&gbyte_payload, gbyte.buffer, size); + ret = init_get_bits8(&gb_payload, gbyte.buffer, size); if (ret < 0) return ret; switch (type) { case SEI_TYPE_PIC_TIMING: // Picture timing SEI - ret = decode_picture_timing(&h->picture_timing, &gb_payload, logctx); + ret = decode_picture_timing(&h->picture_timing, &gbyte_payload, logctx); break; case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35: - ret = decode_registered_user_data(h, &gb_payload, logctx, size); + ret = decode_registered_user_data(h, &gbyte_payload, logctx); break; case SEI_TYPE_USER_DATA_UNREGISTERED: - ret = decode_unregistered_user_data(&h->unregistered, &gb_payload, logctx, size); + ret = decode_unregistered_user_data(&h->unregistered, &gbyte_payload, logctx); break; case SEI_TYPE_RECOVERY_POINT: ret = decode_recovery_point(&h->recovery_point, &gb_payload, logctx); @@ -516,10 +509,10 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, ret = decode_display_orientation(&h->display_orientation, &gb_payload); break; case SEI_TYPE_GREEN_METADATA: - ret = decode_green_metadata(&h->green_metadata, &gb_payload); + ret = decode_green_metadata(&h->green_metadata, &gbyte_payload); break; case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: - ret = decode_alternative_transfer(&h->alternative_transfer, &gb_payload); + ret = decode_alternative_transfer(&h->alternative_transfer, &gbyte_payload); break; case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS: ret = decode_film_grain_characteristics(&h->film_grain_characteristics, &gb_payload); @@ -537,7 +530,7 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, type, -get_bits_left(&gb_payload)); } - skip_bits_long(gb, 8 * size); + bytestream2_skipu(&gbyte, size); } return master_ret; diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index f9166b45df..d7866f42ad 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -66,7 +66,7 @@ typedef struct 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 payload_size_bytes; int present; H264_SEI_PicStructType pic_struct;