Test live QP driver updates and rejection handling against patched FFmpeg

This commit is contained in:
evgeny committed 2026-10-18 22:23:23 +02:00
1 parent 2aa890201d
commit 6e0b842858
1 file changed
+66
@@ -0,0 +1,66 @@
/* Проверка патча FFmpeg 7.1.2 без GPU: настоящий receive_packet и AMF SetProperty на границе драйвера.
* AllocSurface намеренно возвращает OOM после установки QP. Проверяем применение, отсутствие повторных
* установок и повтор после отказа драйвера. Собирать с include/source и статическими библиотеками patched FFmpeg. */
#include <assert.h>
#include <wchar.h>
#include "libavcodec/amfenc.h"
#include "libavutil/opt.h"
static unsigned updates, allocations;
static const wchar_t* rejected;
static int expected;
static AMF_RESULT AMF_STD_CALL set_property(AMFComponent* component, const wchar_t* name, AMFVariantStruct value) {
(void)component;
assert(value.type == AMF_VARIANT_INT64 && value.int64Value == expected);
assert(!wcscmp(name, AMF_VIDEO_ENCODER_MAX_QP) || !wcscmp(name, AMF_VIDEO_ENCODER_HEVC_MAX_QP_I)
|| !wcscmp(name, AMF_VIDEO_ENCODER_HEVC_MAX_QP_P));
++updates;
return rejected && !wcscmp(name, rejected) ? AMF_FAIL : AMF_OK;
}
static AMF_RESULT AMF_STD_CALL alloc_surface(AMFContext* context, AMF_MEMORY_TYPE memory, AMF_SURFACE_FORMAT format,
amf_int32 width, amf_int32 height, AMFSurface** surface) {
(void)context; (void)memory; (void)format; (void)width; (void)height; (void)surface;
++allocations; return AMF_OUT_OF_MEMORY;
}
static void check_encoder(const char* name, int properties) {
const AVCodec* codec = avcodec_find_encoder_by_name(name); assert(codec);
AVCodecContext* context = avcodec_alloc_context3(codec); assert(context);
AmfContext* amf = context->priv_data;
int64_t initial = 0;
assert(av_opt_get_int(amf, "utun_qp_max", 0, &initial) == 0 && initial == -1);
AMFComponentVtbl component_vtable = {.SetProperty = set_property};
AMFComponent component = {.pVtbl = &component_vtable};
AMFContextVtbl context_vtable = {.AllocSurface = alloc_surface};
AMFContext driver = {.pVtbl = &context_vtable};
amf->encoder = &component; amf->context = &driver; amf->utun_qp_applied = -1;
amf->delayed_frame = av_frame_alloc(); assert(amf->delayed_frame);
amf->delayed_frame->buf[0] = av_buffer_alloc(1); assert(amf->delayed_frame->buf[0]);
amf->delayed_frame->format = AV_PIX_FMT_NV12;
AVPacket* packet = av_packet_alloc(); assert(packet);
updates = allocations = 0; rejected = NULL; expected = 28;
assert(av_opt_set_int(amf, "utun_qp_max", expected, 0) == 0);
assert(ff_amf_receive_packet(context, packet) == AVERROR(ENOMEM));
assert(updates == properties && amf->utun_qp_applied == 28 && allocations == 1);
assert(ff_amf_receive_packet(context, packet) == AVERROR(ENOMEM));
assert(updates == properties && allocations == 2);
expected = 29; assert(av_opt_set_int(amf, "utun_qp_max", expected, 0) == 0);
assert(ff_amf_receive_packet(context, packet) == AVERROR(ENOMEM));
assert(updates == properties * 2 && amf->utun_qp_applied == 29 && allocations == 3);
rejected = properties == 1 ? AMF_VIDEO_ENCODER_MAX_QP : AMF_VIDEO_ENCODER_HEVC_MAX_QP_P;
expected = 30; assert(av_opt_set_int(amf, "utun_qp_max", expected, 0) == 0);
assert(ff_amf_receive_packet(context, packet) == AVERROR_EXTERNAL);
assert(amf->utun_qp_applied == 29 && allocations == 3);
rejected = NULL;
assert(ff_amf_receive_packet(context, packet) == AVERROR(ENOMEM));
assert(updates == properties * 4 && amf->utun_qp_applied == 30 && allocations == 4);
av_packet_free(&packet); av_frame_free(&amf->delayed_frame);
amf->encoder = NULL; amf->context = NULL; avcodec_free_context(&context);
av_log(NULL, AV_LOG_INFO, "Live QP native boundary passed: %s\n", name);
}
int main(void) {
check_encoder("h264_amf", 1); check_encoder("hevc_amf", 2); return 0;
}