This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch master
in repository ffmpeg.
The following commit(s) were added to refs/heads/master by this push:
new 5ba2525c7a avcodec/libsvtav1: enable 2-pass encoding
5ba2525c7a is described below
commit 5ba2525c7affc29cbd99e6266946b382d3fffe8b
Author: Werner Robitza <[email protected]>
AuthorDate: Wed Feb 25 16:43:53 2026 +0100
Commit: Werner Robitza <[email protected]>
CommitDate: Wed Feb 25 16:43:53 2026 +0100
avcodec/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 <[email protected]>
---
libavcodec/libsvtav1.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 80 insertions(+), 3 deletions(-)
diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c
index 90c61b98a1..fec2ed596e 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;
@@ -341,6 +345,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_VERBOSE, "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_VERBOSE, "Starting first pass\n");
+ }
param->source_width = avctx->width;
param->source_height = avctx->height;
@@ -618,9 +658,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 = { 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_VERBOSE,
+ "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
@@ -688,6 +764,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;
}
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]