[FFmpeg-devel] [PATCH 11/17] avformat/avc, hevc: Avoid intermediate buffers when parsing annex B

Andreas Rheinhardt andreas.rheinhardt at gmail.com
Thu Jul 9 22:20:16 EEST 2020


When creating H.264 or HEVC extradata from annex B extradata or when
transforming annex B into HEVC while also filtering parameter sets away,
the whole input has first been transformed into mp4-style H.264/HEVC
in order to simplify parsing at the next step. By using ff_avc_parse_nalu,
one can avoid these intermediate steps (which involved (re)allocations).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
---
 libavformat/avc.c  | 28 ++++++++-----------------
 libavformat/hevc.c | 52 +++++++++++++---------------------------------
 2 files changed, 23 insertions(+), 57 deletions(-)

diff --git a/libavformat/avc.c b/libavformat/avc.c
index d089051034..98462940ad 100644
--- a/libavformat/avc.c
+++ b/libavformat/avc.c
@@ -147,7 +147,7 @@ int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
 int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
 {
     AVIOContext *sps_pb = NULL, *pps_pb = NULL, *sps_ext_pb = NULL;
-    uint8_t *buf, *end, *start;
+    const uint8_t *nal, *nal_end, *end;
     uint8_t *sps, *pps, *sps_ext;
     uint32_t sps_size = 0, pps_size = 0, sps_ext_size = 0;
     int ret, nb_sps = 0, nb_pps = 0, nb_sps_ext = 0;
@@ -162,12 +162,6 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
         return 0;
     }
 
-    ret = ff_avc_parse_nal_units_buf(data, &buf, &len);
-    if (ret < 0)
-        return ret;
-    start = buf;
-    end = buf + len;
-
     ret = avio_open_dyn_buf(&sps_pb);
     if (ret < 0)
         goto fail;
@@ -179,12 +173,11 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
         goto fail;
 
     /* look for sps and pps */
-    while (end - buf > 4) {
-        uint32_t size;
-        uint8_t nal_type;
-        size = FFMIN(AV_RB32(buf), end - buf - 4);
-        buf += 4;
-        nal_type = buf[0] & 0x1f;
+    nal_end = NULL;
+    end     = data + len;
+    while (nal = ff_avc_parse_nalu(&data, &nal_end, end)) {
+        uint32_t size = nal_end - nal;
+        uint8_t nal_type = nal[0] & 0x1f;
 
         if (nal_type == 7) { /* SPS */
             nb_sps++;
@@ -193,7 +186,7 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
                 goto fail;
             }
             avio_wb16(sps_pb, size);
-            avio_write(sps_pb, buf, size);
+            avio_write(sps_pb, nal, size);
         } else if (nal_type == 8) { /* PPS */
             nb_pps++;
             if (size > UINT16_MAX || nb_pps >= H264_MAX_PPS_COUNT) {
@@ -201,7 +194,7 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
                 goto fail;
             }
             avio_wb16(pps_pb, size);
-            avio_write(pps_pb, buf, size);
+            avio_write(pps_pb, nal, size);
         } else if (nal_type == 13) { /* SPS_EXT */
             nb_sps_ext++;
             if (size > UINT16_MAX || nb_sps_ext >= 256) {
@@ -209,10 +202,8 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
                 goto fail;
             }
             avio_wb16(sps_ext_pb, size);
-            avio_write(sps_ext_pb, buf, size);
+            avio_write(sps_ext_pb, nal, size);
         }
-
-        buf += size;
     }
     sps_size = avio_get_dyn_buf(sps_pb, &sps);
     pps_size = avio_get_dyn_buf(pps_pb, &pps);
@@ -252,7 +243,6 @@ fail:
     ffio_free_dyn_buf(&sps_pb);
     ffio_free_dyn_buf(&pps_pb);
     ffio_free_dyn_buf(&sps_ext_pb);
-    av_free(start);
 
     return ret;
 }
diff --git a/libavformat/hevc.c b/libavformat/hevc.c
index 94eb3a9cb1..095988b7df 100644
--- a/libavformat/hevc.c
+++ b/libavformat/hevc.c
@@ -35,7 +35,7 @@ typedef struct HVCCNALUnitArray {
     uint8_t  NAL_unit_type;
     uint16_t numNalus;
     uint16_t *nalUnitLength;
-    uint8_t  **nalUnit;
+    const uint8_t **nalUnit;
 } HVCCNALUnitArray;
 
 typedef struct HEVCDecoderConfigurationRecord {
@@ -657,7 +657,7 @@ static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type)
     skip_bits(gb, 9);
 }
 
-static int hvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
+static int hvcc_array_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size,
                                    uint8_t nal_type, int ps_array_completeness,
                                    HEVCDecoderConfigurationRecord *hvcc)
 {
@@ -710,7 +710,7 @@ static int hvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
     return 0;
 }
 
-static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
+static int hvcc_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size,
                              int ps_array_completeness,
                              HEVCDecoderConfigurationRecord *hvcc)
 {
@@ -1000,26 +1000,16 @@ int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in,
                        int size, int filter_ps, int *ps_count)
 {
     int num_ps = 0, ret = 0;
-    uint8_t *buf, *end, *start = NULL;
+    const uint8_t *nal, *nal_end = NULL, *end = buf_in + size;
 
     if (!filter_ps) {
         ret = ff_avc_parse_nal_units(pb, buf_in, size);
         goto end;
     }
 
-    ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size);
-    if (ret < 0)
-        goto end;
-
-    ret = 0;
-    buf = start;
-    end = start + size;
-
-    while (end - buf > 4) {
-        uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4);
-        uint8_t type = (buf[4] >> 1) & 0x3f;
-
-        buf += 4;
+    while (nal = ff_avc_parse_nalu(&buf_in, &nal_end, end)) {
+        uint32_t len = nal_end - nal;
+        uint8_t type = (nal[0] >> 1) & 0x3f;
 
         switch (type) {
         case HEVC_NAL_VPS:
@@ -1030,15 +1020,12 @@ int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in,
         default:
             ret += 4 + len;
             avio_wb32(pb, len);
-            avio_write(pb, buf, len);
+            avio_write(pb, nal, len);
             break;
         }
-
-        buf += len;
     }
 
 end:
-    av_free(start);
     if (ps_count)
         *ps_count = num_ps;
     return ret;
@@ -1069,7 +1056,7 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
                        int size, int ps_array_completeness)
 {
     HEVCDecoderConfigurationRecord hvcc;
-    uint8_t *buf, *end, *start;
+    const uint8_t *nal, *nal_end = NULL, *end;
     int ret;
 
     if (size < 6) {
@@ -1084,20 +1071,12 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
         return AVERROR_INVALIDDATA;
     }
 
-    ret = ff_avc_parse_nal_units_buf(data, &start, &size);
-    if (ret < 0)
-        return ret;
-
     hvcc_init(&hvcc);
 
-    buf = start;
-    end = start + size;
-
-    while (end - buf > 4) {
-        uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4);
-        uint8_t type = (buf[4] >> 1) & 0x3f;
-
-        buf += 4;
+    end = data + size;
+    while (nal = ff_avc_parse_nalu(&data, &nal_end, end)) {
+        uint32_t len = nal_end - nal;
+        uint8_t type = (nal[0] >> 1) & 0x3f;
 
         switch (type) {
         case HEVC_NAL_VPS:
@@ -1105,21 +1084,18 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
         case HEVC_NAL_PPS:
         case HEVC_NAL_SEI_PREFIX:
         case HEVC_NAL_SEI_SUFFIX:
-            ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc);
+            ret = hvcc_add_nal_unit(nal, len, ps_array_completeness, &hvcc);
             if (ret < 0)
                 goto end;
             break;
         default:
             break;
         }
-
-        buf += len;
     }
 
     ret = hvcc_write(pb, &hvcc);
 
 end:
     hvcc_close(&hvcc);
-    av_free(start);
     return ret;
 }
-- 
2.20.1



More information about the ffmpeg-devel mailing list