diff mbox

[FFmpeg-devel,1/7] avformat/aviobuf: Avoid allocating buffer when using dynamic buffer

Message ID 20191127122211.6352-1-andreas.rheinhardt@gmail.com
State Accepted
Commit 163bb9ac0af495a5cb95441bdb5c02170440d28c
Headers show

Commit Message

Andreas Rheinhardt Nov. 27, 2019, 12:22 p.m. UTC
Up until now, using a dynamic buffer entailed at least three
allocations: One for the AVIOContext, one for the AVIOContext's opaque
(which, among other things, contains the small write buffer), and one
for the big buffer that is independently allocated that is returned when
calling avio_close_dyn_buf().

It is possible to avoid the third allocation if one doesn't use a
packetized dynamic buffer, if all the data written so far fit into the
write buffer and if one does not require the actual (big) buffer to have
an indefinite lifetime. This is done by making avio_get_dyn_buf() return
a pointer to the data in the write buffer if nothing has been written to
the main buffer yet. The dynamic buffer will then be freed using
ffio_free_dynamic_buffer (which needed to be modified not to call
avio_close_dyn_buf() internally).

So a typical use-case like:

size = avio_close_dyn_buf(dyn_pb, &buf);
do something with buf
av_free(buf);

can be converted to:

size = avio_get_dyn_buf(dyn_pb, &buf);
do something with buf
ffio_free_dynamic_buffer(&dyn_pb);

In more complex scenarios this can simplify freeing as well, because it
is now clear that freeing always has to be performed via
ffio_free_dynamic_buffer().

Of course, in case this saves an allocation it also saves a memcpy.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
---
 libavformat/aviobuf.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

Comments

James Almer Nov. 28, 2019, 6:23 p.m. UTC | #1
On 11/27/2019 9:22 AM, Andreas Rheinhardt wrote:
> Up until now, using a dynamic buffer entailed at least three
> allocations: One for the AVIOContext, one for the AVIOContext's opaque
> (which, among other things, contains the small write buffer), and one
> for the big buffer that is independently allocated that is returned when
> calling avio_close_dyn_buf().
> 
> It is possible to avoid the third allocation if one doesn't use a
> packetized dynamic buffer, if all the data written so far fit into the
> write buffer and if one does not require the actual (big) buffer to have
> an indefinite lifetime. This is done by making avio_get_dyn_buf() return
> a pointer to the data in the write buffer if nothing has been written to
> the main buffer yet. The dynamic buffer will then be freed using
> ffio_free_dynamic_buffer (which needed to be modified not to call
> avio_close_dyn_buf() internally).
> 
> So a typical use-case like:
> 
> size = avio_close_dyn_buf(dyn_pb, &buf);
> do something with buf
> av_free(buf);
> 
> can be converted to:
> 
> size = avio_get_dyn_buf(dyn_pb, &buf);
> do something with buf
> ffio_free_dynamic_buffer(&dyn_pb);
> 
> In more complex scenarios this can simplify freeing as well, because it
> is now clear that freeing always has to be performed via
> ffio_free_dynamic_buffer().
> 
> Of course, in case this saves an allocation it also saves a memcpy.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
> ---
>  libavformat/aviobuf.c | 20 ++++++++++++++------
>  1 file changed, 14 insertions(+), 6 deletions(-)

Patchset applied.
diff mbox

Patch

diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 2dfce8af8b..70e1d2ca10 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -1443,14 +1443,19 @@  int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
 {
     DynBuffer *d;
 
-    if (!s) {
+    if (!s || s->error) {
         *pbuffer = NULL;
         return 0;
     }
+    d = s->opaque;
+
+    if (!d->size) {
+        *pbuffer = d->io_buffer;
+        return FFMAX(s->buf_ptr, s->buf_ptr_max) - s->buffer;
+    }
 
     avio_flush(s);
 
-    d = s->opaque;
     *pbuffer = d->buffer;
 
     return d->size;
@@ -1488,12 +1493,15 @@  int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
 
 void ffio_free_dyn_buf(AVIOContext **s)
 {
-    uint8_t *tmp;
+    DynBuffer *d;
+
     if (!*s)
         return;
-    avio_close_dyn_buf(*s, &tmp);
-    av_free(tmp);
-    *s = NULL;
+
+    d = (*s)->opaque;
+    av_free(d->buffer);
+    av_free(d);
+    avio_context_free(s);
 }
 
 static int null_buf_write(void *opaque, uint8_t *buf, int buf_size)