[FFmpeg-devel] [PATCH 3/3] avcodec/cbs_h2645: Write slice data directly

Andreas Rheinhardt andreas.rheinhardt at gmail.com
Sat Nov 16 07:24:31 EET 2019


Up until now, writing the data of a slice uses an intermediate buffer
into which the unit (both header as well as the rest) is assembled
before being copied into a freshly allocated buffer. But given that one
has a very good upper bound on the size needed before one starts copying
the slice data, one can allocate the buffer in advance, copy the already
written header into it and directly assemble the rest of the unit in
this buffer.

It proved easier to potentially allocate one byte more and decrement
the size afterwards if it needs to be decremented than to calculate the
exact amount in advance. It is even easier than the current way of
determining whether the last byte needs to be written or not.

Given that the write buffer is now only used for NAL units different
than slices and slice headers, its size has been reduced to 10 KB.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
---
 libavcodec/cbs_h2645.c | 72 +++++++++++++++++++++---------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index 6025035e22..31634a36fc 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -1094,24 +1094,33 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx,
 }
 
 static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx,
+                                      CodedBitstreamUnit *unit,
                                       PutBitContext *pbc, const uint8_t *data,
                                       size_t data_size, int data_bit_start)
 {
     size_t rest  = data_size - (data_bit_start + 7) / 8;
+    int size = (put_bits_count(pbc) - data_bit_start + 7) / 8;
     const uint8_t *pos = data + data_bit_start / 8;
+    int err;
 
     av_assert0(data_bit_start >= 0 &&
                data_size > data_bit_start / 8);
 
-    if (data_size * 8 + 8 > put_bits_left(pbc))
-        return AVERROR(ENOSPC);
+    if (data_size > INT_MAX / 8 - size)
+        return AVERROR(ENOMEM);
+
+    // size might be one too big if in- and output are misaligned.
+    size += data_size;
+
+    err = ff_cbs_alloc_unit_data(ctx, unit, size);
+    if (err < 0)
+        return err;
 
-    if (!rest)
-        goto rbsp_stop_one_bit;
+    // Rebase pbc onto the new buffer.
+    memcpy(unit->data, pbc->buf, put_bits_ptr(pbc) - pbc->buf);
+    rebase_put_bits(pbc, unit->data, size);
 
-    // First copy the remaining bits of the first byte
-    // The above check ensures that we do not accidentally
-    // copy beyond the rbsp_stop_one_bit.
+    // First copy the remaining bits of the first byte.
     if (data_bit_start % 8)
         put_bits(pbc, 8 - data_bit_start % 8,
                  *pos++ & MAX_UINT_BITS(8 - data_bit_start % 8));
@@ -1122,33 +1131,25 @@ static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx,
         // This happens normally for CABAC.
         flush_put_bits(pbc);
         memcpy(put_bits_ptr(pbc), pos, rest);
-        skip_put_bytes(pbc, rest);
     } else {
         // If not, we have to copy manually.
-        // rbsp_stop_one_bit forces us to special-case
-        // the last byte.
-        uint8_t temp;
-        int i;
 
-        for (; rest > 4; rest -= 4, pos += 4)
+        for (; rest >= 4; rest -= 4, pos += 4)
             put_bits32(pbc, AV_RB32(pos));
 
-        for (; rest > 1; rest--, pos++)
+        for (; rest > 0; rest--, pos++)
             put_bits(pbc, 8, *pos);
 
-    rbsp_stop_one_bit:
-        temp = rest ? *pos : *pos & MAX_UINT_BITS(8 - data_bit_start % 8);
+        flush_put_bits(pbc);
 
-        av_assert0(temp);
-        i = ff_ctz(*pos);
-        temp = temp >> i;
-        i = rest ? (8 - i) : (8 - i - data_bit_start % 8);
-        put_bits(pbc, i, temp);
-        if (put_bits_count(pbc) % 8)
-            put_bits(pbc, 8 - put_bits_count(pbc) % 8, 0);
+        // Correct size if it is too big because of misalignment.
+        if (!unit->data[size - 1])
+            unit->data_size = size - 1;
     }
 
-    return 0;
+    unit->data_bit_padding = 0;
+
+    return 1;
 }
 
 static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx,
@@ -1207,11 +1208,9 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx,
                 return err;
 
             if (slice->data) {
-                err = cbs_h2645_write_slice_data(ctx, pbc, slice->data,
-                                                 slice->data_size,
-                                                 slice->data_bit_start);
-                if (err < 0)
-                    return err;
+                return cbs_h2645_write_slice_data(ctx, unit, pbc, slice->data,
+                                                  slice->data_size,
+                                                  slice->data_bit_start);
             } else {
                 // No slice data - that was just the header.
                 // (Bitstream may be unaligned!)
@@ -1341,11 +1340,9 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx,
                 return err;
 
             if (slice->data) {
-                err = cbs_h2645_write_slice_data(ctx, pbc, slice->data,
-                                                 slice->data_size,
-                                                 slice->data_bit_start);
-                if (err < 0)
-                    return err;
+                return cbs_h2645_write_slice_data(ctx, unit, pbc, slice->data,
+                                                  slice->data_size,
+                                                  slice->data_bit_start);
             } else {
                 // No slice data - that was just the header.
             }
@@ -1389,8 +1386,8 @@ static int cbs_h2645_write_nal_unit(CodedBitstreamContext *ctx,
     int err;
 
     if (!priv->write_buffer) {
-        // Initial write buffer size is 1MB.
-        priv->write_buffer_size = 1024 * 1024;
+        // Initial write buffer size is 10KB.
+        priv->write_buffer_size = 10 * 1024;
 
     reallocate_and_try_again:
         err = av_reallocp(&priv->write_buffer, priv->write_buffer_size);
@@ -1409,6 +1406,9 @@ static int cbs_h2645_write_nal_unit(CodedBitstreamContext *ctx,
     else
         err = cbs_h265_write_nal_unit(ctx, unit, &pbc);
 
+    if (err == 1)
+        return 0;
+
     if (err == AVERROR(ENOSPC)) {
         // Overflow.
         if (priv->write_buffer_size == INT_MAX / 8)
-- 
2.20.1



More information about the ffmpeg-devel mailing list