[FFmpeg-devel] [PATCH 02/20] avcodec/h264_sei: Don't use GetBit-API for byte-aligned reads

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Sun Jul 3 01:21:42 EEST 2022


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 <andreas.rheinhardt at outlook.com>
---
 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;
-- 
2.34.1



More information about the ffmpeg-devel mailing list