[FFmpeg-devel] [PATCH] avcodec/amfenc: Avoid polling with fixed sleep

Araz primeadvice at gmail.com
Thu Oct 10 17:00:45 EEST 2024


Thanks Cameron, your patch timeout mechanism has been tested and improves
performance.
But still works with some issues when B-frames are presented.
This issue was resolved in the attached data, please update your patch
with information
below:

diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
> index 41eaef9758..4c6ee58639 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);
> @@ -787,6 +788,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;
>          }
> @@ -796,7 +804,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
> @@ -806,6 +814,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")) {
> @@ -843,6 +852,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;
> @@ -861,7 +871,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..0b8ddd99ed 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 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);
>


More information about the ffmpeg-devel mailing list