diff mbox

[FFmpeg-devel,1/3] avformat/matroskadec: use refcounted buffers in EbmlBin

Message ID 20180404234334.9052-1-jamrial@gmail.com
State Accepted
Commit a61886650b598c98b7f8b44b3c186e33873913cd
Headers show

Commit Message

James Almer April 4, 2018, 11:43 p.m. UTC
Data in EbmlBin objects is never changed after being read from the
input file (save for two specific cases with encoded CodePrivate), so
using AVBufferRef we can prevent unnecessary copy of data by instead
creating new references to said constant data.

Signed-off-by: James Almer <jamrial@gmail.com>
---
The CodecPrivate parts are untested, as there's no FATE coverage of them.

 libavformat/matroskadec.c | 44 +++++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 13 deletions(-)

Comments

James Almer April 7, 2018, 12:18 a.m. UTC | #1
On 4/4/2018 8:43 PM, James Almer wrote:
> Data in EbmlBin objects is never changed after being read from the
> input file (save for two specific cases with encoded CodePrivate), so
> using AVBufferRef we can prevent unnecessary copy of data by instead
> creating new references to said constant data.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> The CodecPrivate parts are untested, as there's no FATE coverage of them.
> 
>  libavformat/matroskadec.c | 44 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 31 insertions(+), 13 deletions(-)

Pushed.
diff mbox

Patch

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 6156c2f9b4..029929a1cb 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -104,6 +104,7 @@  typedef struct EbmlList {
 
 typedef struct EbmlBin {
     int      size;
+    AVBufferRef *buf;
     uint8_t *data;
     int64_t  pos;
 } EbmlBin;
@@ -962,14 +963,19 @@  static int ebml_read_ascii(AVIOContext *pb, int size, char **str)
  */
 static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin)
 {
-    av_fast_padded_malloc(&bin->data, &bin->size, length);
-    if (!bin->data)
-        return AVERROR(ENOMEM);
+    int ret;
 
+    ret = av_buffer_realloc(&bin->buf, length + AV_INPUT_BUFFER_PADDING_SIZE);
+    if (ret < 0)
+        return ret;
+    memset(bin->buf->data + length, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
+    bin->data = bin->buf->data;
     bin->size = length;
     bin->pos  = avio_tell(pb);
     if (avio_read(pb, bin->data, length) != length) {
-        av_freep(&bin->data);
+        av_buffer_unref(&bin->buf);
+        bin->data = NULL;
         bin->size = 0;
         return AVERROR(EIO);
     }
@@ -1252,7 +1258,7 @@  static void ebml_free(EbmlSyntax *syntax, void *data)
             av_freep(data_off);
             break;
         case EBML_BIN:
-            av_freep(&((EbmlBin *) data_off)->data);
+            av_buffer_unref(&((EbmlBin *) data_off)->buf);
             break;
         case EBML_LEVEL1:
         case EBML_NEST:
@@ -2036,12 +2042,13 @@  static int get_qt_codec(MatroskaTrack *track, uint32_t *fourcc, enum AVCodecID *
      * by expanding/shifting the data by 4 bytes and storing the data
      * size at the start. */
     if (ff_codec_get_id(codec_tags, AV_RL32(track->codec_priv.data))) {
-        uint8_t *p = av_realloc(track->codec_priv.data,
-                                track->codec_priv.size + 4);
-        if (!p)
-            return AVERROR(ENOMEM);
-        memmove(p + 4, p, track->codec_priv.size);
-        track->codec_priv.data = p;
+        int ret = av_buffer_realloc(&track->codec_priv.buf,
+                                    track->codec_priv.size + 4 + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (ret < 0)
+            return ret;
+
+        track->codec_priv.data = track->codec_priv.buf->data;
+        memmove(track->codec_priv.data + 4, track->codec_priv.data, track->codec_priv.size);
         track->codec_priv.size += 4;
         AV_WB32(track->codec_priv.data, track->codec_priv.size);
     }
@@ -2162,8 +2169,19 @@  static int matroska_parse_tracks(AVFormatContext *s)
                            "Failed to decode codec private data\n");
                 }
 
-                if (codec_priv != track->codec_priv.data)
-                    av_free(codec_priv);
+                if (codec_priv != track->codec_priv.data) {
+                    av_buffer_unref(&track->codec_priv.buf);
+                    if (track->codec_priv.data) {
+                        track->codec_priv.buf = av_buffer_create(track->codec_priv.data,
+                                                                 track->codec_priv.size + AV_INPUT_BUFFER_PADDING_SIZE,
+                                                                 NULL, NULL, 0);
+                        if (!track->codec_priv.buf) {
+                            av_freep(&track->codec_priv.data);
+                            track->codec_priv.size = 0;
+                            return AVERROR(ENOMEM);
+                        }
+                    }
+                }
             }
         }