[FFmpeg-devel] [PATCH v2] Use AVBufferPool in MOV
Arnaud MASSERANN
arnaud1602 at gmail.com
Mon Dec 2 14:56:10 EET 2024
Most demuxers allocate a new buffer for each packet.
For MOV, this can be problematic, because of some high-bitrate
codecs like ProRes/HAPQ/NotchLC.
Use pools of buffer instead.
For some test media, demuxing goes from 20ms/frame to 11ms/frame,
close to the perf of ReadFile (10ms/frame), making it possible
to read the media at 60Hz.
Signed-off-by: Arnaud Masserann <Arnaud1602 at gmail.com>
---
libavformat/demux.h | 11 +++++++++++
libavformat/isom.h | 2 ++
libavformat/mov.c | 20 ++++++++++++++++++--
libavformat/utils.c | 30 ++++++++++++++++++++++++++++++
4 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/libavformat/demux.h b/libavformat/demux.h
index e83d84a201..bd76a90349 100644
--- a/libavformat/demux.h
+++ b/libavformat/demux.h
@@ -338,4 +338,15 @@ int ff_find_stream_index(const AVFormatContext *s, int id);
int ff_buffer_packet(AVFormatContext *s, AVPacket *pkt);
+/**
+ * Like av_get_packet, but allocates the AVPacket's buffer from a pool.
+ *
+ * @param s associated IO context
+ * @param pool the pool of buffer; must be initialized with a sufficient size
+ * @param pkt packet
+ * @param size desired payload size
+ * @return >0 (read size) if OK, AVERROR_xxx otherwise
+ */
+int ff_get_pooled_packet(AVIOContext *s, AVBufferPool* pool, AVPacket *pkt, int size);
+
#endif /* AVFORMAT_DEMUX_H */
diff --git a/libavformat/isom.h b/libavformat/isom.h
index f18b15bbff..9ecfdc9354 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -276,6 +276,8 @@ typedef struct MOVStreamContext {
} cenc;
struct IAMFDemuxContext *iamf;
+
+ AVBufferPool* pools[32];
} MOVStreamContext;
typedef struct HEIFItem {
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 24feadb95b..84fad85f3d 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -9859,6 +9859,7 @@ static void mov_free_encryption_index(MOVEncryptionIndex **index) {
static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
{
MOVStreamContext *sc = st->priv_data;
+ int i;
if (!sc || --sc->refcount) {
st->priv_data = NULL;
@@ -9915,6 +9916,9 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
ff_iamf_read_deinit(sc->iamf);
#endif
av_freep(&sc->iamf);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(sc->pools); i++)
+ av_buffer_pool_uninit(&sc->pools[i]);
}
static int mov_read_close(AVFormatContext *s)
@@ -10937,6 +10941,16 @@ static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *s
return 0;
}
+static AVBufferPool *mov_pool_get(AVBufferPool* pools[32], int size)
+{
+ int index = av_log2(size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!pools[index]) {
+ int pool_size = 2 << index;
+ pools[index] = av_buffer_pool_init(pool_size, NULL);
+ }
+ return pools[index];
+}
+
static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MOVContext *mov = s->priv_data;
@@ -11043,8 +11057,10 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
return FFERROR_REDO;
}
#endif
- else
- ret = av_get_packet(sc->pb, pkt, sample->size);
+ else{
+ AVBufferPool* pool = mov_pool_get(sc->pools, sample->size);
+ ret = ff_get_pooled_packet(sc->pb, pool, pkt, sample->size);
+ }
if (ret < 0) {
if (should_retry(sc->pb, ret)) {
mov_current_sample_dec(sc);
diff --git a/libavformat/utils.c b/libavformat/utils.c
index e892e8bde7..3b92a10159 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -34,6 +34,7 @@
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
+#include "demux.h"
#if CONFIG_NETWORK
#include "network.h"
#endif
@@ -104,6 +105,35 @@ FF_ENABLE_DEPRECATION_WARNINGS
return append_packet_chunked(s, pkt, size);
}
+int ff_get_pooled_packet(AVIOContext *s, AVBufferPool* pool, AVPacket *pkt, int size)
+{
+#if FF_API_INIT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
+ av_init_packet(pkt);
+ pkt->data = NULL;
+ pkt->size = 0;
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+ av_packet_unref(pkt);
+#endif
+ pkt->pos = avio_tell(s);
+
+ if(!pool)
+ return AVERROR(ENOMEM);
+
+ pkt->buf = av_buffer_pool_get(pool);
+ if(!pkt->buf)
+ return AVERROR(ENOMEM);
+
+ if(pkt->buf->size < size){
+ av_packet_unref(pkt);
+ return AVERROR(ENOMEM);
+ }
+
+ return append_packet_chunked(s, pkt, size);
+}
+
+
int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
{
if (!pkt->size)
--
2.34.1
More information about the ffmpeg-devel
mailing list