* [FFmpeg-devel] [PATCH] libsvtav1: Enable 2-pass encoding (PR #21239)
@ 2025-12-19 11:11 Werner Robitza via ffmpeg-devel
0 siblings, 0 replies; only message in thread
From: Werner Robitza via ffmpeg-devel @ 2025-12-19 11:11 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Werner Robitza
PR #21239 opened by Werner Robitza (slhck)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21239
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21239.patch
This patch enables two-pass encoding for libsvtav1 by implementing
support for AV_CODEC_FLAG_PASS1 and AV_CODEC_FLAG_PASS2.
Previously, users requiring two-pass encoding with SVT-AV1 had to use
the standalone SvtAv1EncApp tool. This patch allows 2-pass encoding
directly through FFmpeg.
Based on patch by Fredrik Lundkvist, with review feedback from James
Almer and Andreas Rheinhardt.
See: https://ffmpeg.org/pipermail/ffmpeg-devel/2024-May/327452.html
Changes:
- Use AV_BASE64_DECODE_SIZE macro for buffer size calculation
- Allocate own buffer for rc_stats_buffer (non-ownership pointer)
- Error handling with buffer cleanup
Signed-off-by: Werner Robitza <werner.robitza@gmail.com>
>From 7b70b050c059feea1a00cc0c9b0fbbca1b8ef2ab Mon Sep 17 00:00:00 2001
From: Werner Robitza <werner.robitza@gmail.com>
Date: Fri, 19 Dec 2025 11:37:28 +0100
Subject: [PATCH] libsvtav1: Enable 2-pass encoding
This patch enables two-pass encoding for libsvtav1 by implementing
support for AV_CODEC_FLAG_PASS1 and AV_CODEC_FLAG_PASS2.
Previously, users requiring two-pass encoding with SVT-AV1 had to use
the standalone SvtAv1EncApp tool. This patch allows 2-pass encoding
directly through FFmpeg.
Based on patch by Fredrik Lundkvist, with review feedback from James
Almer and Andreas Rheinhardt.
See: https://ffmpeg.org/pipermail/ffmpeg-devel/2024-May/327452.html
Changes:
- Use AV_BASE64_DECODE_SIZE macro for buffer size calculation
- Allocate own buffer for rc_stats_buffer (non-ownership pointer)
- Error handling with buffer cleanup
Signed-off-by: Werner Robitza <werner.robitza@gmail.com>
---
libavcodec/libsvtav1.c | 83 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 80 insertions(+), 3 deletions(-)
diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c
index 7047b72422..e2b589ec89 100644
--- a/libavcodec/libsvtav1.c
+++ b/libavcodec/libsvtav1.c
@@ -21,6 +21,7 @@
*/
#include <stdint.h>
+#include <inttypes.h>
#include <EbSvtAv1ErrorCodes.h>
#include <EbSvtAv1Enc.h>
#include <EbSvtAv1Metadata.h>
@@ -28,6 +29,7 @@
#include "libavutil/common.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"
+#include "libavutil/base64.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mastering_display_metadata.h"
#include "libavutil/mem.h"
@@ -65,6 +67,8 @@ typedef struct SvtContext {
DOVIContext dovi;
+ uint8_t *stats_buf;
+
// User options.
AVDictionary *svtav1_opts;
int enc_mode;
@@ -337,6 +341,42 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param,
return AVERROR(ENOSYS);
}
#endif
+ if (avctx->flags & AV_CODEC_FLAG_PASS2) {
+ int stats_sz;
+
+ if (!avctx->stats_in) {
+ av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n");
+ return AVERROR(EINVAL);
+ }
+
+ stats_sz = AV_BASE64_DECODE_SIZE(strlen(avctx->stats_in));
+ if (stats_sz <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid stats file size\n");
+ return AVERROR(EINVAL);
+ }
+
+ svt_enc->stats_buf = av_malloc(stats_sz);
+ if (!svt_enc->stats_buf) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to allocate stats buffer\n");
+ return AVERROR(ENOMEM);
+ }
+
+ stats_sz = av_base64_decode(svt_enc->stats_buf, avctx->stats_in, stats_sz);
+ if (stats_sz < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to decode stats file\n");
+ av_freep(&svt_enc->stats_buf);
+ return AVERROR(EINVAL);
+ }
+
+ param->rc_stats_buffer.buf = svt_enc->stats_buf;
+ param->rc_stats_buffer.sz = stats_sz;
+ param->pass = 2;
+
+ av_log(avctx, AV_LOG_INFO, "Using %d bytes of 2-pass stats\n", stats_sz);
+ } else if (avctx->flags & AV_CODEC_FLAG_PASS1) {
+ param->pass = 1;
+ av_log(avctx, AV_LOG_INFO, "Starting first pass\n");
+ }
param->source_width = avctx->width;
param->source_height = avctx->height;
@@ -614,9 +654,45 @@ static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
#if SVT_AV1_CHECK_VERSION(2, 0, 0)
if (headerPtr->flags & EB_BUFFERFLAG_EOS) {
- svt_enc->eos_flag = EOS_RECEIVED;
- svt_av1_enc_release_out_buffer(&headerPtr);
- return AVERROR_EOF;
+ if (avctx->flags & AV_CODEC_FLAG_PASS1) {
+ SvtAv1FixedBuf first_pass_stats = { NULL, 0 };
+ EbErrorType svt_ret_stats;
+ int b64_size;
+
+ svt_ret_stats = svt_av1_enc_get_stream_info(
+ svt_enc->svt_handle,
+ SVT_AV1_STREAM_INFO_FIRST_PASS_STATS_OUT,
+ &first_pass_stats);
+
+ if (svt_ret_stats != EB_ErrorNone) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to get first pass stats\n");
+ svt_av1_enc_release_out_buffer(&headerPtr);
+ return AVERROR_EXTERNAL;
+ }
+
+ if (first_pass_stats.sz > 0 && first_pass_stats.buf) {
+ b64_size = AV_BASE64_SIZE(first_pass_stats.sz);
+ avctx->stats_out = av_malloc(b64_size);
+ if (!avctx->stats_out) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to allocate stats output buffer\n");
+ svt_av1_enc_release_out_buffer(&headerPtr);
+ return AVERROR(ENOMEM);
+ }
+
+ av_base64_encode(avctx->stats_out, b64_size,
+ first_pass_stats.buf, first_pass_stats.sz);
+
+ av_log(avctx, AV_LOG_INFO,
+ "First pass stats: %"PRIu64" bytes, encoded to %d bytes\n",
+ first_pass_stats.sz, b64_size);
+ }
+ }
+
+ svt_enc->eos_flag = EOS_RECEIVED;
+ svt_av1_enc_release_out_buffer(&headerPtr);
+ return AVERROR_EOF;
}
#endif
@@ -684,6 +760,7 @@ static av_cold int eb_enc_close(AVCodecContext *avctx)
av_buffer_pool_uninit(&svt_enc->pool);
av_frame_free(&svt_enc->frame);
ff_dovi_ctx_unref(&svt_enc->dovi);
+ av_freep(&svt_enc->stats_buf);
return 0;
}
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-12-19 11:12 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-19 11:11 [FFmpeg-devel] [PATCH] libsvtav1: Enable 2-pass encoding (PR #21239) Werner Robitza via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git