On Mon, Sep 9, 2024 at 11:05 AM Araz <primeadv...@gmail.com> wrote: >> >> > I took a look at this using AMD's AMF EncoderLatency sample and found that >> > setting the QUERY_TIMEOUT option to 50 ms (as is default for the new AMF >> > HQ and HQLL usage values) results in latency that is better than the >> > current AMF code in FFmpeg *and* this patch without having to touch >> > the process's timer precision. >> > >> > Here are the results from QUERY_TIMEOUT=0, amf_sleep(1), 1ms timer period: >> > Encoder: AMFVideoEncoderVCE_AVC >> > Total : Frames = 500 Duration = 1157.16ms FPS = 432.09frames >> > Latency: First,Min,Max = 7.12ms, 1.53ms, 3.73ms >> > Latency: Average = 1.99ms >> > >> > and the results from QUERY_TIMEOUT=50, default timer period: >> > Encoder: AMFVideoEncoderVCE_AVC >> > Total : Frames = 500 Duration = 933.03ms FPS = 535.89frames >> > Latency: First,Min,Max = 5.80ms, 1.49ms, 2.50ms >> > Latency: Average = 1.58ms >> > >> > This seems to clearly demonstrate that QUERY_TIMEOUT is a better approach >> > than adjusting timer resolution. It avoids process-wide effects *and* >> > it even performs better on top of that. >> > >> > >> > Cameron > > > Thanks everyone and Cameron, > TIMEOUT might be a possible solution. > Need some time for evaluating the performance impact of using it. > The problem is that FFmpeg calls SubmitInput and QueryOutput > from the same thread and if B-frames and/or look-ahead enabled, initially > not enough input submitted and QueryOutput will wait till timeout value.
Ah I see, I guess we can just replace the fixed 1 ms sleep with a fixed 1 ms QUERY_TIMEOUT. We won't get the full power gains of waking exactly once per frame when encoding is complete, but it should solve the issue of having to wait a full 15.6ms to realize output data is available. How about something like this? diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 41eaef9758..555cdcde85 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -861,7 +861,12 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) if (query_output_data_flag == 0) { if (res_resubmit == AMF_INPUT_FULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) { block_and_wait = 1; - av_usleep(1000); + + // Only sleep if the driver doesn't support waiting in QueryOutput() + // or if we already have output data so we will skip calling it. + if (!ctx->query_timeout_supported || avpkt->data || avpkt->buf) { + av_usleep(1000); + } } } } while (block_and_wait); diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index d985d01bb1..a634c133c6 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -68,6 +68,7 @@ typedef struct AmfContext { int hwsurfaces_in_queue; int hwsurfaces_in_queue_max; + int query_timeout_supported; // helpers to handle async calls int delayed_drain; diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c index 2a7a782063..f3058c5b96 100644 --- a/libavcodec/amfenc_av1.c +++ b/libavcodec/amfenc_av1.c @@ -467,6 +467,11 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // 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 8edd39c633..6d7c5808ee 100644 --- a/libavcodec/amfenc_h264.c +++ b/libavcodec/amfenc_h264.c @@ -482,6 +482,11 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, ctx->ref_b_frame_delta_qp); } + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // 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 4898824f3a..4457990247 100644 --- a/libavcodec/amfenc_hevc.c +++ b/libavcodec/amfenc_hevc.c @@ -429,6 +429,11 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // 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); _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".