PR #24055 opened by Edison Ling (edisonling) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24055 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24055.patch
# Summary of changes This replaces the hardcoded lookahead maximum `#define MAX_LOOKAHEAD_DEPTH 41` with a runtime query, and sizes `async_depth` from the value AMF actually applied rather than the raw option value. The second is what keeps the first safe, so they ship together. The runtime query has to work around an ABI bug in the unfixed AMF SDK headers, where the C bindings do not match the shipped runtime. That handling is transitional and comes out once the minimum AMF version carries the fix. ## Runtime maximum instead of the macro Replace the hardcoded `MAX_LOOKAHEAD_DEPTH 41` bound on `pa_lookahead_buffer_depth` and `async_depth` with the maximum AMF reports at runtime, so the bound tracks what the runtime accepts instead of a constant duplicated in FFmpeg. Values above that maximum are clamped with a warning instead of being rejected by the option parser. `async_depth` is now sized from the lookahead depth read back from the encoder rather than the raw option value. The read-back is the value AMF actually applied, which fixes a latent under-size that could stall the encoder: adaptive mini-GOP forces a lookahead the raw option value does not reflect, leaving `async_depth` at 1 against a lookahead of 1. The two changes cannot be split: raising the option ceiling makes a value like 1000 parse successfully, and without the read-back that would size `async_depth` to 1001, replacing a hard parse error with a throttle that never engages. `async_depth` is no longer bounded by the option parser. The old ceiling capped it at MAX_LOOKAHEAD_DEPTH + 1 at parse time, even with preanalysis off where no lookahead is running. The cap now happens at encoder init, and the maximum is only queryable when preanalysis is on, so with preanalysis off nothing caps it. This is fine because `async_depth` only limits how many frames can be in flight and sizes no allocation. The AMF runtime also applies its own input backpressure by returning AMF_INPUT_FULL, which FFmpeg handles by draining output and retrying. ## Workaround for the AMF SDK header bug The maximum comes from `GetPropertyInfo`. With unfixed AMF SDK headers its C mapping only matches the runtime on non-MSVC ABIs, so the correct call is target-dependent. `configure` probes for the `reserved` field in `AMFPropertyInfo` to detect headers where this is already corrected, and the getter selects one of three arms at compile time: - fixed headers: call `GetPropertyInfo` directly, on every target - unfixed headers on Windows: the MSVC-built AMF runtime places the by-name overload in the by-index slot, so it is called through `GetPropertyInfoAt`. Gated on `_WIN32` rather than the compiler, because the runtime's layout is what matters. MinGW builds need this too, since the AMF runtime is still MSVC-built. - unfixed headers elsewhere: declaration order already matches, so the direct call is correct Unfixed headers also shift `AMFPropertyInfo` in the C mapping. The C++ type has a virtual destructor, so its objects start with a vtable pointer that the C definition leaves out, and every field is offset by the size of one pointer. The getter skips past it before reading. Unlike the call selection above, this is gated on the probe alone and not `_WIN32`, because that vtable pointer is present under both Linux and Windows ABIs. The type check after the skip validates the arithmetic. ## Removing the workaround The ABI handling is transitional. Once the minimum AMF version includes the header fix, all of the following can be deleted in a single commit: - the `configure` probe and its `TYPES_LIST` entry - the `#elif defined(_WIN32)` and `#else` arms of the getter - the `#if !HAVE_AMFPROPERTYINFO_RESERVED` realign and its type check - comments in this commit related to unfixed/fixed headers After removing the workaround, only a single direct `GetPropertyInfo` call should remain. The clamp and async_depth helpers are unaffected; they are not part of the workaround. # Testing Tested on Radeon RX 9070 (Navi 48) and RX 7700 XT / 7800 XT (Navi 32), covering RDNA4 and RDNA3. Both `configure` probe states were built and exercised on every platform: `HAVE_AMFPROPERTYINFO_RESERVED` at 0 (unfixed headers, workaround arms) and at 1 (fixed headers, direct call). | Platform | Toolchain | Backend | |---|---|---| | Linux | GCC | Vulkan | | Windows | MSVC | D3D11 | | Windows | MinGW GCC | D3D11 | Headers and runtime were also mismatched during testing, since users typically build against the public 1.5.2 SDK while running whatever runtime their driver ships. A `--disable-amf` build was checked to confirm the new probe is skipped cleanly. All cases used the same base command, varying the preanalysis and async options: `ffmpeg -i input.mp4 -vf format=nv12 -frames:v 60 -an -c:v h264_amf -preanalysis 1 -pa_lookahead_buffer_depth 10 -async_depth 4 -f null -` On each platform, I ran a test matrix (~200 tests) over `h264_amf`, `hevc_amf` and `av1_amf`. The query returned 41 on every GPU and runtime tested, confirming it reports the same bound the removed macro hardcoded. Within the previously accepted range the only behavioural change is in how `async_depth` is sized. Relevant subset of test results (`h264_amf`, max = 41): | Options | Result | |---|---| | `-pa_lookahead_buffer_depth 40 -async_depth 1` | async 1 -> 41 | | `-pa_lookahead_buffer_depth 41 -async_depth 1` | async 1 -> 42 | | `-pa_lookahead_buffer_depth 42 -async_depth 1` | lookahead 42 -> 41, async 1 -> 42 | | `-pa_lookahead_buffer_depth 1000 -async_depth 16` | lookahead 1000 -> 41, async 16 -> 42 | | `-pa_lookahead_buffer_depth 2147483647` | lookahead -> 41, async 16 -> 42 | | `-pa_lookahead_buffer_depth 16 -async_depth 16` | async 16 -> 17 | | `-pa_lookahead_buffer_depth 10 -async_depth 42` | unchanged | | `-pa_lookahead_buffer_depth 10 -async_depth 43` | async 43 -> 42 | | `-pa_lookahead_buffer_depth 10 -async_depth 1000` | async 1000 -> 42 | | `-pa_adaptive_mini_gop 1 -async_depth 1` | async 1 -> 2 | | `-pa_lookahead_buffer_depth 20 -async_depth 4` (PA off) | unchanged | | `-async_depth 1000` (PA off) | unchanged, no cap | | `-pa_lookahead_buffer_depth -2` | rejected at parse | | `-async_depth 0` | rejected at parse | `hevc_amf` and `av1_amf` match `h264_amf` above except for adaptive mini-GOP: `hevc_amf` has no such option, and `av1_amf`'s effective lookahead is unchanged there, so no bump applies. Upstream and patched builds were also compared directly on the same hardware and toolchain. For all six of my cases within the previously accepted range, including those where `async_depth` now differs, the encoded bitstreams were byte-identical, so the change does not affect encoding decisions. Output equivalence: each container case was hashed with `-c copy -f md5`. Each configuration produces the same bitstream across both header states, and on Windows across both toolchains. Confirmed with synthetic input and with a real 1080p H.264 clip. _Note: I was unable to properly test on the RX 9060 XT. Preanalysis encodes produced no output frames for me. It doesn't appear related to this change since an unpatched master build fails the same way from the same command line._ `ffmpeg -f lavfi -i testsrc2=size=1280x720:rate=30 -vf format=nv12 -frames:v 60 -an -c:v h264_amf -preanalysis 1 -f null -` _The encode reports frame=0 and produces no output. The exit code can still be 0, so the frame count is the important part._ >From fb21753a9fc8f2c5dd7c084cdb07e046c1f79419 Mon Sep 17 00:00:00 2001 From: "Ling, Edison" <[email protected]> Date: Fri, 7 Aug 2026 14:53:46 -0400 Subject: [PATCH] avcodec/amfenc: Replace hardcoded lookahead maximum with runtime query Replace the hardcoded `MAX_LOOKAHEAD_DEPTH 41` bound on `pa_lookahead_buffer_depth` and `async_depth` with the maximum AMF reports at runtime, so the bound tracks what the runtime accepts instead of a constant duplicated in FFmpeg. Values above that maximum are clamped with a warning instead of being rejected by the option parser. `async_depth` is now sized from the lookahead depth read back from the encoder rather than the raw option value. The read-back is the value AMF actually applied, which fixes a latent under-size when adaptive mini-GOP raises the effective lookahead. The two changes cannot be split: raising the option ceiling makes a value like 1000 parse successfully, and without the read-back that would size `async_depth` to 1001, replacing a hard parse error with a silent oversized allocation. The maximum comes from `GetPropertyInfo`. With unfixed AMF SDK headers its C mapping only matches the runtime on non-MSVC ABIs, so the correct call is target-dependent. `configure` probes for the `reserved` field in `AMFPropertyInfo` to detect headers where this is already corrected, and the getter selects one of three calls at compile time: - fixed headers: call `GetPropertyInfo` directly, on every target - unfixed headers on Windows: the MSVC-built AMF runtime places the by-name overload in the by-index slot, so it is called through `GetPropertyInfoAt`. Gated on `_WIN32` rather than the compiler, because the runtime's layout is what matters -- MinGW builds need this too - unfixed headers elsewhere: declaration order already matches, so the direct call is correct Unfixed headers also shift `AMFPropertyInfo` by one pointer in the C mapping. That realign is unconditional and the type check after it validates the arithmetic, so both are scoped to that branch only. --- configure | 4 +- libavcodec/amfenc.c | 108 +++++++++++++++++++++++++++++++++++---- libavcodec/amfenc.h | 24 ++++++++- libavcodec/amfenc_av1.c | 11 ++-- libavcodec/amfenc_h264.c | 11 ++-- libavcodec/amfenc_hevc.c | 11 ++-- 6 files changed, 142 insertions(+), 27 deletions(-) diff --git a/configure b/configure index e09bbd7f04..0f645503c8 100755 --- a/configure +++ b/configure @@ -2679,6 +2679,7 @@ TYPES_LIST=" kCVImageBufferTransferFunction_ITU_R_2020 kCVImageBufferTransferFunction_SMPTE_ST_428_1 kVTQPModulationLevel_Default + AMFPropertyInfo_reserved SecPkgContext_KeyingMaterialInfo socklen_t struct_addrinfo @@ -7927,7 +7928,8 @@ fi enabled amf && check_cpp_condition amf "AMF/core/Version.h" \ - "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x1000500020000" + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x1000500020000" && + check_struct "AMF/core/PropertyStorageEx.h" "AMFPropertyInfo" reserved # Funny iconv installations are not unusual, so check it after all flags have been set if enabled libc_iconv; then diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 3ffca750d8..4c052b47a2 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -36,6 +36,8 @@ #include "amfenc.h" #include "encode.h" +#include <AMF/components/PreAnalysis.h> + #define AMF_AV_FRAME_REF L"av_frame_ref" #define PTS_PROP L"PtsProp" @@ -166,6 +168,103 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) return 0; } +int ff_amf_get_lookahead_depth_max(AVCodecContext *avctx, AMFComponent *encoder, amf_int64 *out_max) +{ + // Query the maximum accepted value of AMF_PA_LOOKAHEAD_BUFFER_DEPTH. + // With unfixed AMF SDK headers the C vtable mapping only matches the runtime on + // non-MSVC ABIs, so the correct call is target-dependent (see each arm below). + // HAVE_AMFPROPERTYINFO_RESERVED detects whether the header fix is present. + // TODO: once the minimum AMF version includes the fix, the configure probe and + // legacy branches can be dropped entirely. + const wchar_t *name = AMF_PA_LOOKAHEAD_BUFFER_DEPTH; + const AMFPropertyInfo *prop_info = NULL; + AMF_RESULT res; + + if (!encoder || !out_max) + return AVERROR(EINVAL); + +#if HAVE_AMFPROPERTYINFO_RESERVED + // Fixed SDK ABI: the C *Vtbl declaration order matches the runtime on every + // target (Win-MSVC, Win-MinGW, Linux), so pVtbl->GetPropertyInfo is the + // by-name overload. Call it directly. + res = encoder->pVtbl->GetPropertyInfo(encoder, name, &prop_info); + av_log(avctx, AV_LOG_DEBUG, "GetPropertyInfo() returned %d\n", res); +#elif defined(_WIN32) + // Unfixed SDK ABI on Windows: amfrt64.dll is MSVC-built, and MSVC lays overloaded + // virtuals in reverse declaration order, so the by-name GetPropertyInfo sits in + // the by-index GetPropertyInfoAt slot. Gated on _WIN32, not the compiler: the + // runtime's layout is what matters, so MinGW builds need this too. + typedef AMF_RESULT (AMF_STD_CALL *GetPropInfoByNameFn)(AMFComponent *, const wchar_t *, const AMFPropertyInfo **); + GetPropInfoByNameFn get_by_name = (GetPropInfoByNameFn)(void *)encoder->pVtbl->GetPropertyInfoAt; + res = get_by_name(encoder, name, &prop_info); + av_log(avctx, AV_LOG_DEBUG, "GetPropertyInfoAt() returned %d\n", res); +#else + // Unfixed SDK ABI, non-MSVC runtime (GCC/Clang on Linux; Itanium C++ ABI): + // overloaded virtuals keep declaration order, so the declared GetPropertyInfo + // slot is already by-name. Call it directly; swapping would hit by-index. + res = encoder->pVtbl->GetPropertyInfo(encoder, name, &prop_info); + av_log(avctx, AV_LOG_DEBUG, "GetPropertyInfo() returned %d\n", res); +#endif + if (res != AMF_OK || !prop_info) + return AVERROR_EXTERNAL; + +#if !HAVE_AMFPROPERTYINFO_RESERVED + // Unfixed SDK ABI: AMFPropertyInfo starts with an extra pointer the C mapping + // omits (the C++ destructor's vtable pointer), so skip it to realign before reading. + prop_info = (const AMFPropertyInfo *)((const uint8_t *)prop_info + sizeof(void *)); + if (prop_info->type != AMF_VARIANT_INT64) + return AVERROR_EXTERNAL; +#endif + + *out_max = prop_info->maxValue.int64Value; + return 0; +} + +void ff_amf_clamp_lookahead_depth(AVCodecContext *avctx, AMFEncoderContext *ctx) +{ + amf_int64 hw_max; + AMF_RESULT res; + + if (ff_amf_get_lookahead_depth_max(avctx, ctx->encoder, &hw_max) == 0 && + ctx->pa_lookahead_buffer_depth > hw_max) { + av_log(avctx, AV_LOG_WARNING, + "pa_lookahead_buffer_depth %d exceeds supported maximum %lld, clamping\n", + ctx->pa_lookahead_buffer_depth, (long long)hw_max); + ctx->pa_lookahead_buffer_depth = (int)hw_max; + } + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, ctx->pa_lookahead_buffer_depth); + if (res != AMF_OK) + av_log(avctx, AV_LOG_WARNING, "Setting lookahead buffer depth failed with error %d\n", res); +} + +void ff_amf_fit_async_depth(AVCodecContext *avctx, AMFEncoderContext *ctx) +{ + // Size async_depth to the lookahead window in two independent steps: + // - bump: widen async_depth to fit the lookahead depth read back from the + // encoder (the applied value; only present when preanalysis is enabled). + // - cap: limit async_depth to the reported maximum + 1 when it can be queried. + amf_int64 hw_max; + AMFVariantStruct var = { 0 }; + AMF_RESULT res; + + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, &var); + if (res == AMF_OK && var.int64Value >= ctx->hwsurfaces_in_queue_max) { + av_log(avctx, AV_LOG_WARNING, + "async_depth (%d) too small for lookahead (%lld), increasing to (%lld)\n", + ctx->hwsurfaces_in_queue_max, (long long)var.int64Value, (long long)(var.int64Value + 1)); + ctx->hwsurfaces_in_queue_max = (int)(var.int64Value + 1); + } + + if (ff_amf_get_lookahead_depth_max(avctx, ctx->encoder, &hw_max) == 0 && + ctx->hwsurfaces_in_queue_max > hw_max + 1) { + av_log(avctx, AV_LOG_WARNING, + "async_depth %d exceeds supported range, clamping to %lld\n", + ctx->hwsurfaces_in_queue_max, (long long)(hw_max + 1)); + ctx->hwsurfaces_in_queue_max = (int)(hw_max + 1); + } +} + static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface* surface) { @@ -326,15 +425,6 @@ int ff_amf_encode_init(AVCodecContext *avctx) AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create hardware device context (AMF) : %s\n", av_err2str(ret)); } - if (ctx->pa_lookahead_buffer_depth >= ctx->hwsurfaces_in_queue_max) { - av_log(avctx, AV_LOG_WARNING, - "async_depth (%d) too small for lookahead (%d), increasing to (%d)\n", - ctx->hwsurfaces_in_queue_max, - ctx->pa_lookahead_buffer_depth, - ctx->pa_lookahead_buffer_depth + 1); - ctx->hwsurfaces_in_queue_max = ctx->pa_lookahead_buffer_depth + 1; - } - if ((ret = amf_init_encoder(avctx)) == 0) { return 0; } diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index 1571541b9b..e68f039fdf 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -31,8 +31,6 @@ #include "avcodec.h" #include "hwconfig.h" -#define MAX_LOOKAHEAD_DEPTH 41 - /** * AMF encoder context */ @@ -158,6 +156,28 @@ int ff_amf_encode_close(AVCodecContext *avctx); */ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); +/** +* Query the maximum PA lookahead buffer depth (AMF_PA_LOOKAHEAD_BUFFER_DEPTH). +* Only available once preanalysis is enabled on the encoder. +* @return 0 and sets *out_max on success; a negative AVERROR on failure. +*/ +int ff_amf_get_lookahead_depth_max(AVCodecContext *avctx, AMFComponent *encoder, amf_int64 *out_max); + +/** +* Clamp pa_lookahead_buffer_depth to the AMF-reported maximum and assign it to +* the encoder. Call from within the preanalysis configuration block, before +* encoder Init(). +*/ +void ff_amf_clamp_lookahead_depth(AVCodecContext *avctx, AMFEncoderContext *ctx); + +/** +* Size async_depth (hwsurfaces_in_queue_max) around the lookahead window: widen +* it to hold the lookahead depth read back from the encoder, then cap it at the +* AMF-reported lookahead maximum + 1. Call before encoder Init(), after all +* lookahead/B-frame properties have been set. +*/ +void ff_amf_fit_async_depth(AVCodecContext *avctx, AMFEncoderContext *ctx); + /** * Supported formats */ diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c index af20b5d04d..00966c23a8 100644 --- a/libavcodec/amfenc_av1.c +++ b/libavcodec/amfenc_av1.c @@ -101,7 +101,7 @@ static const AVOption options[] = { { "gop", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, { "frame", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_KEY_FRAME_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, - { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, MAX_LOOKAHEAD_DEPTH + 1, VE }, + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, INT_MAX, VE }, { "preencode", "Enable preencode", OFFSET(preencode), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, @@ -169,7 +169,7 @@ static const AVOption options[] = { { "pa_frame_sad_enable", "Enable Frame SAD algorithm", OFFSET(pa_frame_sad), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_ltr_enable", "Enable long term reference frame management", OFFSET(pa_ltr), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_lookahead_buffer_depth", "Sets the PA lookahead buffer size", OFFSET(pa_lookahead_buffer_depth), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, MAX_LOOKAHEAD_DEPTH, VE }, + { "pa_lookahead_buffer_depth", "Sets the PA lookahead buffer size", OFFSET(pa_lookahead_buffer_depth), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, VE }, { "pa_paq_mode", "Sets the perceptual adaptive quantization mode", OFFSET(pa_paq_mode), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_PAQ_MODE_CAQ, VE , .unit = "paq_mode" }, { "none", "no perceptual adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_PAQ_MODE_NONE }, 0, 0, VE, .unit = "paq_mode" }, @@ -504,9 +504,8 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) if (ctx->pa_ltr != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_PA_LTR_ENABLE, ((ctx->pa_ltr == 0) ? false : true)); } - if (ctx->pa_lookahead_buffer_depth != -1) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, ctx->pa_lookahead_buffer_depth); - } + if (ctx->pa_lookahead_buffer_depth != -1) + ff_amf_clamp_lookahead_depth(avctx, ctx); if (ctx->pa_high_motion_quality_boost_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE, ctx->pa_high_motion_quality_boost_mode); } @@ -573,6 +572,8 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, &var); ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + ff_amf_fit_async_depth(avctx, ctx); + // init encoder res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c index 650a9bc7e9..994d1ec25f 100644 --- a/libavcodec/amfenc_h264.c +++ b/libavcodec/amfenc_h264.c @@ -114,7 +114,7 @@ static const AVOption options[] = { { "header_spacing", "Header Insertion Spacing", OFFSET(header_spacing), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1000, VE }, /// Maximum queued frames - { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, MAX_LOOKAHEAD_DEPTH + 1, VE }, + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, INT_MAX, VE }, /// B-Frames // BPicturesPattern=bf @@ -175,7 +175,7 @@ static const AVOption options[] = { { "pa_frame_sad_enable", "Enable Frame SAD algorithm", OFFSET(pa_frame_sad), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_ltr_enable", "Enable long term reference frame management", OFFSET(pa_ltr), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_lookahead_buffer_depth", "Sets the PA lookahead buffer size", OFFSET(pa_lookahead_buffer_depth), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, MAX_LOOKAHEAD_DEPTH, VE }, + { "pa_lookahead_buffer_depth", "Sets the PA lookahead buffer size", OFFSET(pa_lookahead_buffer_depth), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, VE }, { "pa_paq_mode", "Sets the perceptual adaptive quantization mode", OFFSET(pa_paq_mode), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_PAQ_MODE_CAQ, VE , .unit = "paq_mode" }, { "none", "no perceptual adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_PAQ_MODE_NONE }, 0, 0, VE, .unit = "paq_mode" }, @@ -465,9 +465,8 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx) if (ctx->pa_ltr != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_PA_LTR_ENABLE, ((ctx->pa_ltr == 0) ? false : true)); } - if (ctx->pa_lookahead_buffer_depth != -1) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, ctx->pa_lookahead_buffer_depth); - } + if (ctx->pa_lookahead_buffer_depth != -1) + ff_amf_clamp_lookahead_depth(avctx, ctx); if (ctx->pa_high_motion_quality_boost_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE, ctx->pa_high_motion_quality_boost_mode); } @@ -551,6 +550,8 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx) res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_QUERY_TIMEOUT, &var); ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + ff_amf_fit_async_depth(avctx, ctx); + // Initialize Encoder res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c index 6fa20d172e..e66ba3f7a8 100644 --- a/libavcodec/amfenc_hevc.c +++ b/libavcodec/amfenc_hevc.c @@ -91,7 +91,7 @@ static const AVOption options[] = { { "gop", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, { "idr", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, - { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, MAX_LOOKAHEAD_DEPTH + 1, VE }, + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, INT_MAX, VE }, { "high_motion_quality_boost_enable", "Enable High motion quality boost mode", OFFSET(hw_high_motion_quality_boost), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "gops_per_idr", "GOPs per IDR 0-no IDR will be inserted", OFFSET(gops_per_idr), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, VE }, @@ -146,7 +146,7 @@ static const AVOption options[] = { { "pa_frame_sad_enable", "Enable Frame SAD algorithm", OFFSET(pa_frame_sad), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_ltr_enable", "Enable long term reference frame management", OFFSET(pa_ltr), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_lookahead_buffer_depth", "Sets the PA lookahead buffer size", OFFSET(pa_lookahead_buffer_depth), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, MAX_LOOKAHEAD_DEPTH, VE }, + { "pa_lookahead_buffer_depth", "Sets the PA lookahead buffer size", OFFSET(pa_lookahead_buffer_depth), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, VE }, { "pa_paq_mode", "Sets the perceptual adaptive quantization mode", OFFSET(pa_paq_mode), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_PAQ_MODE_CAQ, VE , .unit = "paq_mode" }, { "none", "no perceptual adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_PAQ_MODE_NONE }, 0, 0, VE, .unit = "paq_mode" }, @@ -470,9 +470,8 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) if (ctx->pa_ltr != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_PA_LTR_ENABLE, ((ctx->pa_ltr == 0) ? false : true)); } - if (ctx->pa_lookahead_buffer_depth != -1) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, ctx->pa_lookahead_buffer_depth); - } + if (ctx->pa_lookahead_buffer_depth != -1) + ff_amf_clamp_lookahead_depth(avctx, ctx); if (ctx->pa_high_motion_quality_boost_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE, ctx->pa_high_motion_quality_boost_mode); } @@ -483,6 +482,8 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, &var); ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + ff_amf_fit_async_depth(avctx, ctx); + // init encoder res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
