[FFmpeg-devel] [PATCH, v3] avcodec/amfenc: increase precision of Sleep() on Windows

Araz Iusubov primeadvice at gmail.com
Sat Oct 12 01:28:00 EEST 2024


From: Cameron Gutman <aicommander at gmail.com>

This commit increase precision of Sleep() function on Windows.
This fix reduces the sleep time on Windows to improve AMF encoding
performance on low resolution input videos.

Fix for issue #10622

Co-authored-by: Araz Iusubov <Primeadvice at gmail.com>
---
 libavcodec/amfenc.c      | 21 ++++++++++++++++++---
 libavcodec/amfenc.h      |  3 +++
 libavcodec/amfenc_av1.c  |  5 +++++
 libavcodec/amfenc_h264.c |  5 +++++
 libavcodec/amfenc_hevc.c |  5 +++++
 5 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 225fb9df27..03d75031f5 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -426,6 +426,8 @@ static int amf_init_encoder(AVCodecContext *avctx)
     res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder);
     AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res);
 
+    ctx->submitted_frame = 0;
+
     return 0;
 }
 
@@ -541,7 +543,6 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff
     if ((ctx->max_b_frames > 0 || ((ctx->pa_adaptive_mini_gop == 1) ? true : false)) && ctx->dts_delay == 0) {
         int64_t timestamp_last = AV_NOPTS_VALUE;
         size_t can_read = av_fifo_can_read(ctx->timestamp_list);
-
         AMF_RETURN_IF_FALSE(ctx, can_read > 0, AVERROR_UNKNOWN,
             "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames);
         av_fifo_peek(ctx->timestamp_list, &timestamp_last, 1, can_read - 1);
@@ -826,6 +827,13 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
 
             av_frame_unref(frame);
             ret = av_fifo_write(ctx->timestamp_list, &pts, 1);
+
+            if (ctx->submitted_frame == 0)
+            {
+                ctx->use_b_frame = (ctx->max_b_frames > 0 || ((ctx->pa_adaptive_mini_gop == 1) ? true : false));
+            }
+            ctx->submitted_frame++;
+
             if (ret < 0)
                 return ret;
         }
@@ -835,7 +843,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
     do {
         block_and_wait = 0;
         // poll data
-        if (!avpkt->data && !avpkt->buf) {
+        if (!avpkt->data && !avpkt->buf && (ctx->use_b_frame ? (ctx->submitted_frame >= 2) : true) ) {
             res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);
             if (data) {
                 // copy data to packet
@@ -845,6 +853,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
                 data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface
                 ret = amf_copy_buffer(avctx, avpkt, buffer);
 
+                ctx->submitted_frame++;
                 buffer->pVtbl->Release(buffer);
 
                 if (data->pVtbl->HasProperty(data, L"av_frame_ref")) {
@@ -884,6 +893,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
                 av_frame_unref(ctx->delayed_frame);
                 AMF_RETURN_IF_FALSE(ctx, res_resubmit == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res_resubmit);
 
+                ctx->submitted_frame++;
                 ret = av_fifo_write(ctx->timestamp_list, &pts, 1);
                 if (ret < 0)
                     return ret;
@@ -902,7 +912,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 0f2abcbd82..d83ee5bf1c 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;
@@ -77,6 +78,8 @@ typedef struct AmfContext {
     // shift dts back by max_b_frames in timing
     AVFifo             *timestamp_list;
     int64_t             dts_delay;
+    int                 submitted_frame;
+    amf_bool            use_b_frame;
 
     // common encoder option options
 
diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c
index b40d54f70c..e63979f62a 100644
--- a/libavcodec/amfenc_av1.c
+++ b/libavcodec/amfenc_av1.c
@@ -468,6 +468,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 959be9eab6..07aa9deb40 100644
--- a/libavcodec/amfenc_h264.c
+++ b/libavcodec/amfenc_h264.c
@@ -483,6 +483,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 f9f6f8adb3..7244f1a250 100644
--- a/libavcodec/amfenc_hevc.c
+++ b/libavcodec/amfenc_hevc.c
@@ -430,6 +430,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);
-- 
2.45.2.windows.1



More information about the ffmpeg-devel mailing list