PR #23842 opened by charlymp URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23842 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23842.patch
Raw and fixed rate video encoders allocate a fresh buffer for every packet, which for UHD+ means tens of megabytes malloced and freed per frame. glibc mitigates this for smaller buffers, as its adaptive mmap threshold lets allocations up to 32 MiB be recycled from the heap, but beyond that limit every packet costs an mmap/munmap pair plus page faults, and the behavior depends on the allocator and its tunables (MALLOC_MMAP_THRESHOLD_, musl, the Windows heap whose recycling stops around 1 MiB). Recycling large buffers through a general purpose heap also contributes to memory fragmentation in long running processes. This series introduces an internal cap letting encoders declare a constant packet size, so the default get_encode_buffer() can serve them from an AVBufferPool, mirroring the existing decoder frame pool. This makes the per packet allocation cost deterministic regardless of the allocator and keeps large packet buffers out of the heap, limiting fragmentation. A user supplied get_encode_buffer callback keeps priority, and frame threaded encoders work unchanged (one pool per worker). >From af1b4cbf232bd40a16e0497f15d41d9dc11bef28 Mon Sep 17 00:00:00 2001 From: Charly Morgand-Poyac <[email protected]> Date: Sat, 18 Jul 2026 17:36:08 +0200 Subject: [PATCH 1/3] avcodec/encode: add FF_CODEC_CAP_FIXED_PACKET_SIZE Encoders producing packets of constant size for given stream parameters can set this internal capability to make the default get_encode_buffer() serve packet buffers from an AVBufferPool instead of allocating a new buffer for every packet. This makes the allocation cost per packet deterministic and avoids repeated large allocations for raw video encoders, where every packet can weigh tens of megabytes. The pool is recreated when the requested size changes, and a user supplied get_encode_buffer callback keeps priority since it bypasses the default allocator entirely. Signed-off-by: Charly Morgand-Poyac <[email protected]> --- libavcodec/avcodec.c | 1 + libavcodec/codec_internal.h | 6 ++++++ libavcodec/encode.c | 26 ++++++++++++++++++++++---- libavcodec/internal.h | 7 +++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c index 5320dfc06c..16f95fa4a2 100644 --- a/libavcodec/avcodec.c +++ b/libavcodec/avcodec.c @@ -467,6 +467,7 @@ av_cold void ff_codec_close(AVCodecContext *avctx) av_frame_free(&avci->recon_frame); av_refstruct_unref(&avci->pool); + av_buffer_pool_uninit(&avci->packet_pool); av_refstruct_pool_uninit(&avci->progress_frame_pool); if (av_codec_is_decoder(avctx->codec)) ff_decode_internal_uninit(avctx); diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h index 5cb65a06e2..f1e1033cbf 100644 --- a/libavcodec/codec_internal.h +++ b/libavcodec/codec_internal.h @@ -88,6 +88,12 @@ * encoders do. */ #define FF_CODEC_CAP_EOF_FLUSH (1 << 10) +/** + * The encoder requests output packets of a constant size for given stream + * parameters. The default get_encode_buffer() serves them from a buffer pool + * instead of allocating a new buffer for every packet. + */ +#define FF_CODEC_CAP_FIXED_PACKET_SIZE (1 << 11) /** * FFCodec.codec_tags termination value diff --git a/libavcodec/encode.c b/libavcodec/encode.c index 56b2f4362b..61ff2c6b54 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -92,10 +92,28 @@ int avcodec_default_get_encode_buffer(AVCodecContext *avctx, AVPacket *avpkt, in return AVERROR(EINVAL); } - ret = av_buffer_realloc(&avpkt->buf, avpkt->size + AV_INPUT_BUFFER_PADDING_SIZE); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to allocate packet of size %d\n", avpkt->size); - return ret; + if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_FIXED_PACKET_SIZE) { + AVCodecInternal *avci = avctx->internal; + int size = avpkt->size + AV_INPUT_BUFFER_PADDING_SIZE; + + if (avci->packet_pool_size != size) { + av_buffer_pool_uninit(&avci->packet_pool); + avci->packet_pool = av_buffer_pool_init(size, NULL); + if (!avci->packet_pool) { + avci->packet_pool_size = 0; + return AVERROR(ENOMEM); + } + avci->packet_pool_size = size; + } + avpkt->buf = av_buffer_pool_get(avci->packet_pool); + if (!avpkt->buf) + return AVERROR(ENOMEM); + } else { + ret = av_buffer_realloc(&avpkt->buf, avpkt->size + AV_INPUT_BUFFER_PADDING_SIZE); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to allocate packet of size %d\n", avpkt->size); + return ret; + } } avpkt->data = avpkt->buf->data; diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 137fd52745..fc61b9514e 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -68,6 +68,13 @@ typedef struct AVCodecInternal { struct FramePool *pool; + /** + * Packet buffer pool for encoders with FF_CODEC_CAP_FIXED_PACKET_SIZE, + * used by the default get_encode_buffer() callback. + */ + AVBufferPool *packet_pool; + int packet_pool_size; + struct AVRefStructPool *progress_frame_pool; void *thread_ctx; -- 2.52.0 >From e939bcddb82ec4c739a47b1c37dde9c4d341c507 Mon Sep 17 00:00:00 2001 From: Charly Morgand-Poyac <[email protected]> Date: Sat, 18 Jul 2026 17:49:53 +0200 Subject: [PATCH 2/3] avcodec: set FF_CODEC_CAP_FIXED_PACKET_SIZE on constant packet size encoders These encoders request a packet size that only depends on the stream parameters, so the default get_encode_buffer() can serve every packet from the buffer pool instead of allocating a fresh buffer each time. Covers rawvideo, v210, r210, r10k, avrp, avui, yuv4, y41p, bitpacked, bmp, pam, pbm, pgm, pgmyuv, ppm, pfm, phm, xwd, fits, dvvideo, dnxhd and libsvtjpegxs, whose rate control produces a fixed codestream budget per frame. Signed-off-by: Charly Morgand-Poyac <[email protected]> --- libavcodec/avuienc.c | 1 + libavcodec/bitpacked_enc.c | 1 + libavcodec/bmpenc.c | 1 + libavcodec/dnxhdenc.c | 3 ++- libavcodec/dvenc.c | 1 + libavcodec/fitsenc.c | 1 + libavcodec/libsvtjpegxsenc.c | 3 ++- libavcodec/pamenc.c | 1 + libavcodec/pnmenc.c | 6 ++++++ libavcodec/r210enc.c | 3 +++ libavcodec/rawenc.c | 1 + libavcodec/v210enc.c | 1 + libavcodec/xwdenc.c | 1 + libavcodec/y41penc.c | 1 + libavcodec/yuv4enc.c | 1 + 15 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libavcodec/avuienc.c b/libavcodec/avuienc.c index 0dea87f104..04a55e046d 100644 --- a/libavcodec/avuienc.c +++ b/libavcodec/avuienc.c @@ -103,4 +103,5 @@ const FFCodec ff_avui_encoder = { .color_ranges = AVCOL_RANGE_MPEG, .init = avui_encode_init, FF_CODEC_ENCODE_CB(avui_encode_frame), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/bitpacked_enc.c b/libavcodec/bitpacked_enc.c index cde3cf83ee..2b52f84f8f 100644 --- a/libavcodec/bitpacked_enc.c +++ b/libavcodec/bitpacked_enc.c @@ -115,4 +115,5 @@ const FFCodec ff_bitpacked_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/bmpenc.c b/libavcodec/bmpenc.c index 15d6778f24..77931e370f 100644 --- a/libavcodec/bmpenc.c +++ b/libavcodec/bmpenc.c @@ -169,4 +169,5 @@ const FFCodec ff_bmp_encoder = { AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_MONOBLACK), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index 844731f6c4..ff2a487a89 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -1358,7 +1358,8 @@ const FFCodec ff_dnxhd_encoder = { .p.priv_class = &dnxhd_class, .defaults = dnxhd_defaults, .p.profiles = NULL_IF_CONFIG_SMALL(ff_dnxhd_profiles), - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_FIXED_PACKET_SIZE, }; void ff_dnxhdenc_init(DNXHDEncContext *ctx) diff --git a/libavcodec/dvenc.c b/libavcodec/dvenc.c index f25c3ddfee..fe88310086 100644 --- a/libavcodec/dvenc.c +++ b/libavcodec/dvenc.c @@ -1257,4 +1257,5 @@ const FFCodec ff_dvvideo_encoder = { CODEC_PIXFMTS(AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &dvvideo_encode_class, + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/fitsenc.c b/libavcodec/fitsenc.c index 2a31514068..79fda5839c 100644 --- a/libavcodec/fitsenc.c +++ b/libavcodec/fitsenc.c @@ -119,4 +119,5 @@ const FFCodec ff_fits_encoder = { FF_CODEC_ENCODE_CB(fits_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_GBRAP16BE, AV_PIX_FMT_GBRP16BE, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/libsvtjpegxsenc.c b/libavcodec/libsvtjpegxsenc.c index d8dbc93075..ef014f8dfc 100644 --- a/libavcodec/libsvtjpegxsenc.c +++ b/libavcodec/libsvtjpegxsenc.c @@ -296,7 +296,8 @@ const FFCodec ff_libsvtjpegxs_encoder = { FF_CODEC_ENCODE_CB(svt_jpegxs_enc_encode), .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | - FF_CODEC_CAP_AUTO_THREADS, + FF_CODEC_CAP_AUTO_THREADS | + FF_CODEC_CAP_FIXED_PACKET_SIZE, CODEC_PIXFMTS_ARRAY(pix_fmts), .p.wrapper_name = "libsvtjpegxs", .p.priv_class = &svtjpegxs_enc_class, diff --git a/libavcodec/pamenc.c b/libavcodec/pamenc.c index e0c6eda235..8a137def10 100644 --- a/libavcodec/pamenc.c +++ b/libavcodec/pamenc.c @@ -140,4 +140,5 @@ const FFCodec ff_pam_encoder = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, AV_PIX_FMT_MONOBLACK), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/pnmenc.c b/libavcodec/pnmenc.c index 8f67fe0a3b..7d945ed941 100644 --- a/libavcodec/pnmenc.c +++ b/libavcodec/pnmenc.c @@ -233,6 +233,7 @@ const FFCodec ff_pgm_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif @@ -245,6 +246,7 @@ const FFCodec ff_pgmyuv_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif @@ -257,6 +259,7 @@ const FFCodec ff_ppm_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif @@ -269,6 +272,7 @@ const FFCodec ff_pbm_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_MONOWHITE), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif @@ -282,6 +286,7 @@ const FFCodec ff_pfm_encoder = { FF_CODEC_ENCODE_CB(pnm_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32LE, AV_PIX_FMT_GRAYF32LE, AV_PIX_FMT_GBRPF32BE, AV_PIX_FMT_GRAYF32BE), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif @@ -305,5 +310,6 @@ const FFCodec ff_phm_encoder = { .init = phm_enc_init, FF_CODEC_ENCODE_CB(pnm_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GRAYF32), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif diff --git a/libavcodec/r210enc.c b/libavcodec/r210enc.c index b1ade5cde6..d54044a7f9 100644 --- a/libavcodec/r210enc.c +++ b/libavcodec/r210enc.c @@ -100,6 +100,7 @@ const FFCodec ff_r210_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), CODEC_PIXFMTS_ARRAY(pix_fmt), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif #if CONFIG_R10K_ENCODER @@ -112,6 +113,7 @@ const FFCodec ff_r10k_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), CODEC_PIXFMTS_ARRAY(pix_fmt), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif #if CONFIG_AVRP_ENCODER @@ -124,5 +126,6 @@ const FFCodec ff_avrp_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), CODEC_PIXFMTS_ARRAY(pix_fmt), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; #endif diff --git a/libavcodec/rawenc.c b/libavcodec/rawenc.c index 8c577006d9..1626da7c89 100644 --- a/libavcodec/rawenc.c +++ b/libavcodec/rawenc.c @@ -90,4 +90,5 @@ const FFCodec ff_rawvideo_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = raw_encode_init, FF_CODEC_ENCODE_CB(raw_encode), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/v210enc.c b/libavcodec/v210enc.c index 2194e2128c..b5a6fccd8d 100644 --- a/libavcodec/v210enc.c +++ b/libavcodec/v210enc.c @@ -118,4 +118,5 @@ const FFCodec ff_v210_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/xwdenc.c b/libavcodec/xwdenc.c index 1d8b7d9002..4873e1e697 100644 --- a/libavcodec/xwdenc.c +++ b/libavcodec/xwdenc.c @@ -227,4 +227,5 @@ const FFCodec ff_xwd_encoder = { AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8, AV_PIX_FMT_MONOWHITE), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/y41penc.c b/libavcodec/y41penc.c index b0044b35ef..de77032162 100644 --- a/libavcodec/y41penc.c +++ b/libavcodec/y41penc.c @@ -86,4 +86,5 @@ const FFCodec ff_y41p_encoder = { .init = y41p_encode_init, FF_CODEC_ENCODE_CB(y41p_encode_frame), CODEC_PIXFMTS(AV_PIX_FMT_YUV411P), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; diff --git a/libavcodec/yuv4enc.c b/libavcodec/yuv4enc.c index 093038142f..af2b0f08a4 100644 --- a/libavcodec/yuv4enc.c +++ b/libavcodec/yuv4enc.c @@ -78,4 +78,5 @@ const FFCodec ff_yuv4_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), FF_CODEC_ENCODE_CB(yuv4_encode_frame), + .caps_internal = FF_CODEC_CAP_FIXED_PACKET_SIZE, }; -- 2.52.0 >From 4cb6efbf8b0087a904b63a5f6b7d8ecfe9d54956 Mon Sep 17 00:00:00 2001 From: Charly Morgand-Poyac <[email protected]> Date: Sat, 18 Jul 2026 17:36:18 +0200 Subject: [PATCH 3/3] tests/api: add api-encode-pool test Covers the packet buffer pool used by the default get_encode_buffer() for encoders with FF_CODEC_CAP_FIXED_PACKET_SIZE: constant packet size, buffer reuse once a packet is unreferenced, no aliasing between packets still in use, and pool recreation when the requested size changes. The test uses the rawvideo encoder and only builds when it is enabled. Signed-off-by: Charly Morgand-Poyac <[email protected]> --- tests/api/Makefile | 1 + tests/api/api-encode-pool-test.c | 153 +++++++++++++++++++++++++++++++ tests/fate/api.mak | 5 + 3 files changed, 159 insertions(+) create mode 100644 tests/api/api-encode-pool-test.c diff --git a/tests/api/Makefile b/tests/api/Makefile index 987db1b785..ebc1b11aec 100644 --- a/tests/api/Makefile +++ b/tests/api/Makefile @@ -1,3 +1,4 @@ +APITESTPROGS-$(CONFIG_RAWVIDEO_ENCODER) += api-encode-pool APITESTPROGS-$(call ENCDEC, FLAC, FLAC) += api-flac APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264 APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264-slice diff --git a/tests/api/api-encode-pool-test.c b/tests/api/api-encode-pool-test.c new file mode 100644 index 0000000000..5c617d488b --- /dev/null +++ b/tests/api/api-encode-pool-test.c @@ -0,0 +1,153 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * Test the packet buffer pool used by the default get_encode_buffer() for + * encoders with FF_CODEC_CAP_FIXED_PACKET_SIZE: buffers must be reused once + * the packet is unreferenced and must not alias packets still in use. + */ + +#include <stdio.h> +#include <string.h> + +#include "libavcodec/avcodec.h" +#include "libavutil/frame.h" +#include "libavutil/mem.h" + +static int encode_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, int fill) +{ + int ret; + + ret = av_frame_make_writable(frame); + if (ret < 0) + return ret; + + memset(frame->data[0], fill, frame->linesize[0] * frame->height); + frame->pts = fill; + + ret = avcodec_send_frame(ctx, frame); + if (ret < 0) + return ret; + + return avcodec_receive_packet(ctx, pkt); +} + +int main(void) +{ + const AVCodec *codec = avcodec_find_encoder_by_name("rawvideo"); + AVCodecContext *ctx = NULL; + AVFrame *frame = NULL; + AVPacket *pkt = NULL, *pkt2 = NULL; + uint8_t *snapshot = NULL; + const uint8_t *prev_data = NULL; + int first_size = -1; + int ret = 1; + + if (!codec) { + fprintf(stderr, "rawvideo encoder not found\n"); + return 1; + } + + ctx = avcodec_alloc_context3(codec); + frame = av_frame_alloc(); + pkt = av_packet_alloc(); + pkt2 = av_packet_alloc(); + if (!ctx || !frame || !pkt || !pkt2) + goto end; + + ctx->width = 128; + ctx->height = 64; + ctx->pix_fmt = AV_PIX_FMT_GRAY8; + ctx->time_base = (AVRational){ 1, 25 }; + ctx->thread_count = 1; + + if (avcodec_open2(ctx, codec, NULL) < 0) + goto end; + + frame->format = ctx->pix_fmt; + frame->width = ctx->width; + frame->height = ctx->height; + if (av_frame_get_buffer(frame, 0) < 0) + goto end; + + for (int i = 0; i < 64; i++) { + if (encode_frame(ctx, frame, pkt, i) < 0) + goto end; + if (first_size < 0) + first_size = pkt->size; + if (pkt->size != first_size) { + fprintf(stderr, "packet size changed: %d != %d\n", pkt->size, first_size); + goto end; + } + if (i && pkt->buf->data != prev_data) { + fprintf(stderr, "packet buffer not reused after unref\n"); + goto end; + } + prev_data = pkt->buf->data; + av_packet_unref(pkt); + } + + if (encode_frame(ctx, frame, pkt, 1) < 0) + goto end; + snapshot = av_memdup(pkt->data, pkt->size); + if (!snapshot) + goto end; + if (encode_frame(ctx, frame, pkt2, 2) < 0) + goto end; + if (pkt->buf->data == pkt2->buf->data) { + fprintf(stderr, "referenced packets share the same buffer\n"); + goto end; + } + if (memcmp(pkt->data, snapshot, pkt->size)) { + fprintf(stderr, "referenced packet was overwritten\n"); + goto end; + } + av_packet_unref(pkt); + av_packet_unref(pkt2); + + /* direct calls, to exercise pool recreation on size change */ + for (int i = 0; i < 4; i++) { + static const int sizes[] = { 1024, 1024, 4096, 1024 }; + + pkt->size = sizes[i]; + if (avcodec_default_get_encode_buffer(ctx, pkt, 0) < 0) + goto end; + if (pkt->buf->size != sizes[i] + AV_INPUT_BUFFER_PADDING_SIZE) { + fprintf(stderr, "unexpected pool buffer size %zu for request %d\n", + pkt->buf->size, sizes[i]); + goto end; + } + if (i && sizes[i] == sizes[i - 1] && pkt->buf->data != prev_data) { + fprintf(stderr, "pool buffer not reused for same-size request\n"); + goto end; + } + prev_data = pkt->buf->data; + av_packet_unref(pkt); + } + + ret = 0; +end: + av_free(snapshot); + av_packet_free(&pkt); + av_packet_free(&pkt2); + av_frame_free(&frame); + avcodec_free_context(&ctx); + return ret; +} diff --git a/tests/fate/api.mak b/tests/fate/api.mak index ba9789d9f7..202dd1bede 100644 --- a/tests/fate/api.mak +++ b/tests/fate/api.mak @@ -1,3 +1,8 @@ +FATE_API_LIBAVCODEC-$(CONFIG_RAWVIDEO_ENCODER) += fate-api-encode-pool +fate-api-encode-pool: $(APITESTSDIR)/api-encode-pool-test$(EXESUF) +fate-api-encode-pool: CMD = run $(APITESTSDIR)/api-encode-pool-test$(EXESUF) +fate-api-encode-pool: CMP = null + FATE_API_LIBAVCODEC-$(call ENCDEC, FLAC, FLAC) += fate-api-flac fate-api-flac: $(APITESTSDIR)/api-flac-test$(EXESUF) fate-api-flac: CMD = run $(APITESTSDIR)/api-flac-test$(EXESUF) -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
