Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Mark Thompson <sw@jkqxz.net>
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH v8 05/15] avcodec/vaapi_encode: move the dpb logic from VAAPI to base layer
Date: Tue, 14 May 2024 21:46:44 +0100
Message-ID: <371d0efe-9631-48f7-bab8-33484b7776c5@jkqxz.net> (raw)
In-Reply-To: <20240418085910.547-5-tong1.wu@intel.com>

On 18/04/2024 09:58, tong1.wu-at-intel.com@ffmpeg.org wrote:
> From: Tong Wu <tong1.wu@intel.com>
> 
> Move receive_packet function to base. This requires adding *alloc,
> *issue, *output, *free as hardware callbacks. HWBaseEncodePicture is
> introduced as the base layer structure. The related parameters in
> VAAPIEncodeContext are also extracted to HWBaseEncodeContext. Then DPB
> management logic can be fully extracted to base layer as-is.
> 
> Signed-off-by: Tong Wu <tong1.wu@intel.com>
> ---
>  libavcodec/Makefile             |   2 +-
>  libavcodec/hw_base_encode.c     | 600 ++++++++++++++++++++++++
>  libavcodec/hw_base_encode.h     | 123 +++++
>  libavcodec/vaapi_encode.c       | 793 +++++---------------------------
>  libavcodec/vaapi_encode.h       | 102 +---
>  libavcodec/vaapi_encode_av1.c   |  51 +-
>  libavcodec/vaapi_encode_h264.c  | 176 +++----
>  libavcodec/vaapi_encode_h265.c  | 121 ++---
>  libavcodec/vaapi_encode_mjpeg.c |   7 +-
>  libavcodec/vaapi_encode_mpeg2.c |  47 +-
>  libavcodec/vaapi_encode_vp8.c   |  18 +-
>  libavcodec/vaapi_encode_vp9.c   |  54 +--
>  12 files changed, 1097 insertions(+), 997 deletions(-)
>  create mode 100644 libavcodec/hw_base_encode.c
> 
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 7f6de4470e..a2174dcb2f 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -162,7 +162,7 @@ OBJS-$(CONFIG_STARTCODE)               += startcode.o
>  OBJS-$(CONFIG_TEXTUREDSP)              += texturedsp.o
>  OBJS-$(CONFIG_TEXTUREDSPENC)           += texturedspenc.o
>  OBJS-$(CONFIG_TPELDSP)                 += tpeldsp.o
> -OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o
> +OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o hw_base_encode.o
>  OBJS-$(CONFIG_AV1_AMF_ENCODER)         += amfenc_av1.o
>  OBJS-$(CONFIG_VC1DSP)                  += vc1dsp.o
>  OBJS-$(CONFIG_VIDEODSP)                += videodsp.o
> diff --git a/libavcodec/hw_base_encode.c b/libavcodec/hw_base_encode.c
> new file mode 100644
> index 0000000000..1d9a255f69
> --- /dev/null
> +++ b/libavcodec/hw_base_encode.c
> @@ -0,0 +1,600 @@
> +/*
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libavutil/avassert.h"
> +#include "libavutil/common.h"
> +#include "libavutil/internal.h"
> +#include "libavutil/log.h"
> +#include "libavutil/mem.h"
> +#include "libavutil/pixdesc.h"
> +
> +#include "encode.h"
> +#include "avcodec.h"
> +#include "hw_base_encode.h"
> +
> ...

Everything above here looks like a copy of the VAAPI code with the names changed, good if so.  (If not then please highlight any differences.)

> +
> +static int hw_base_encode_send_frame(AVCodecContext *avctx, AVFrame *frame)
> +{
> +    HWBaseEncodeContext *ctx = avctx->priv_data;
> +    HWBaseEncodePicture *pic;
> +    int err;
> +
> +    if (frame) {
> +        av_log(avctx, AV_LOG_DEBUG, "Input frame: %ux%u (%"PRId64").\n",
> +               frame->width, frame->height, frame->pts);
> +
> +        err = hw_base_encode_check_frame(avctx, frame);
> +        if (err < 0)
> +            return err;
> +
> +        pic = ctx->op->alloc(avctx, frame);
> +        if (!pic)
> +            return AVERROR(ENOMEM);

Can you push the allocation of this picture out into the base layer?  vaapi_encode_alloc() and d3d12va_encode_alloc() are identical except for the types and the input_surface setting.

> +
> +        pic->input_image = av_frame_alloc();
> +        if (!pic->input_image) {
> +            err = AVERROR(ENOMEM);
> +            goto fail;
> +        }
> +
> +        pic->recon_image = av_frame_alloc();
> +        if (!pic->recon_image) {
> +            err = AVERROR(ENOMEM);
> +            goto fail;
> +        }
> +
> +        if (ctx->input_order == 0 || frame->pict_type == AV_PICTURE_TYPE_I)
> +            pic->force_idr = 1;
> +
> +        pic->pts = frame->pts;
> +        pic->duration = frame->duration;
> +
> +        if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
> +            err = av_buffer_replace(&pic->opaque_ref, frame->opaque_ref);
> +            if (err < 0)
> +                goto fail;
> +
> +            pic->opaque = frame->opaque;
> +        }
> +
> +        av_frame_move_ref(pic->input_image, frame);
> +
> +        if (ctx->input_order == 0)
> +            ctx->first_pts = pic->pts;
> +        if (ctx->input_order == ctx->decode_delay)
> +            ctx->dts_pts_diff = pic->pts - ctx->first_pts;
> +        if (ctx->output_delay > 0)
> +            ctx->ts_ring[ctx->input_order %
> +                        (3 * ctx->output_delay + ctx->async_depth)] = pic->pts;
> +
> +        pic->display_order = ctx->input_order;
> +        ++ctx->input_order;
> +
> +        if (ctx->pic_start) {
> +            ctx->pic_end->next = pic;
> +            ctx->pic_end       = pic;
> +        } else {
> +            ctx->pic_start     = pic;
> +            ctx->pic_end       = pic;
> +        }
> +
> +    } else {
> +        ctx->end_of_stream = 1;
> +
> +        // Fix timestamps if we hit end-of-stream before the initial decode
> +        // delay has elapsed.
> +        if (ctx->input_order < ctx->decode_delay)
> +            ctx->dts_pts_diff = ctx->pic_end->pts - ctx->first_pts;
> +    }
> +
> +    return 0;
> +
> +fail:
> +    ctx->op->free(avctx, pic);

Maybe same with free, since it mixes the two layers?  hw_base_encode_free() in this file calling the API-specific free might be cleaner.

> +    return err;
> +}
> +
> +int ff_hw_base_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
> +{
> +    HWBaseEncodeContext *ctx = avctx->priv_data;
> +    HWBaseEncodePicture *pic = NULL;
> +    AVFrame *frame = ctx->frame;
> +    int err;
> +
> +start:
> +    /** if no B frame before repeat P frame, sent repeat P frame out. */
> +    if (ctx->tail_pkt->size) {
> +        for (HWBaseEncodePicture *tmp = ctx->pic_start; tmp; tmp = tmp->next) {
> +            if (tmp->type == PICTURE_TYPE_B && tmp->pts < ctx->tail_pkt->pts)
> +                break;
> +            else if (!tmp->next) {
> +                av_packet_move_ref(pkt, ctx->tail_pkt);
> +                goto end;
> +            }
> +        }
> +    }
> +
> +    err = ff_encode_get_frame(avctx, frame);
> +    if (err < 0 && err != AVERROR_EOF)
> +        return err;
> +
> +    if (err == AVERROR_EOF)
> +        frame = NULL;
> +
> +    if (!(ctx->op && ctx->op->alloc && ctx->op->issue &&
> +          ctx->op->output && ctx->op->free)) {
> +        err = AVERROR(EINVAL);
> +        return err;
> +    }

This check feels like it should have been done earlier?

Also, it should probably be an assert - EINVAL is indicating that the caller has got something wrong, while this would be a bug in this case.

> +
> +    err = hw_base_encode_send_frame(avctx, frame);
> +    if (err < 0)
> +        return err;
> +
> +    if (!ctx->pic_start) {
> +        if (ctx->end_of_stream)
> +            return AVERROR_EOF;
> +        else
> +            return AVERROR(EAGAIN);
> +    }
> +
> +    if (ctx->async_encode) {

Is async_encode false tested after this series?  (I see that D3D12 has it set unconditionally.)

> +        if (av_fifo_can_write(ctx->encode_fifo)) {
> +            err = hw_base_encode_pick_next(avctx, &pic);
> +            if (!err) {
> +                av_assert0(pic);
> +                pic->encode_order = ctx->encode_order +
> +                    av_fifo_can_read(ctx->encode_fifo);
> +                err = ctx->op->issue(avctx, pic);
> +                if (err < 0) {
> +                    av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err);
> +                    return err;
> +                }
> +                pic->encode_issued = 1;
> +                av_fifo_write(ctx->encode_fifo, &pic, 1);
> +            }
> +        }
> +
> +        if (!av_fifo_can_read(ctx->encode_fifo))
> +            return err;
> +
> +        // More frames can be buffered
> +        if (av_fifo_can_write(ctx->encode_fifo) && !ctx->end_of_stream)
> +            return AVERROR(EAGAIN);
> +
> +        av_fifo_read(ctx->encode_fifo, &pic, 1);
> +        ctx->encode_order = pic->encode_order + 1;
> +    } else {
> +        err = hw_base_encode_pick_next(avctx, &pic);
> +        if (err < 0)
> +            return err;
> +        av_assert0(pic);
> +
> +        pic->encode_order = ctx->encode_order++;
> +
> +        err = ctx->op->issue(avctx, pic);
> +        if (err < 0) {
> +            av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err);
> +            return err;
> +        }
> +
> +        pic->encode_issued = 1;
> +    }
> +
> +    err = ctx->op->output(avctx, pic, pkt);
> +    if (err < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err);
> +        return err;
> +    }
> +
> +    ctx->output_order = pic->encode_order;
> +    hw_base_encode_clear_old(avctx);
> +
> +    /** loop to get an available pkt in encoder flushing. */
> +    if (ctx->end_of_stream && !pkt->size)
> +        goto start;
> +
> +end:
> +    if (pkt->size)
> +        av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts %"PRId64", "
> +               "size %d bytes.\n", pkt->pts, pkt->dts, pkt->size);
> +
> +    return 0;
> +}
> diff --git a/libavcodec/hw_base_encode.h b/libavcodec/hw_base_encode.h
> index a578db8c06..b5b676b9a8 100644
> --- a/libavcodec/hw_base_encode.h
> +++ b/libavcodec/hw_base_encode.h
> @@ -19,6 +19,8 @@
>  #ifndef AVCODEC_HW_BASE_ENCODE_H
>  #define AVCODEC_HW_BASE_ENCODE_H
>  
> +#include "libavutil/fifo.h"
> +
>  #define MAX_DPB_SIZE 16
>  #define MAX_PICTURE_REFERENCES 2
>  #define MAX_REORDER_DELAY 16
> @@ -53,13 +55,134 @@ enum {
>      FLAG_NON_IDR_KEY_PICTURES  = 1 << 5,
>  };
>  
> +typedef struct HWBaseEncodePicture {
> +    struct HWBaseEncodePicture *next;

"next" does not seem like the right name for this field.

> +
> +    int64_t         display_order;
> +    int64_t         encode_order;
> +    int64_t         pts;
> +    int64_t         duration;
> +    int             force_idr;
> +
> +    void           *opaque;
> +    AVBufferRef    *opaque_ref;
> +
> +    int             type;
> +    int             b_depth;
> +    int             encode_issued;
> +    int             encode_complete;
> +
> +    AVFrame        *input_image;
> +    AVFrame        *recon_image;
> +
> +    void           *priv_data;
> +
> +    // Whether this picture is a reference picture.
> +    int             is_reference;
> +
> +    // The contents of the DPB after this picture has been decoded.
> +    // This will contain the picture itself if it is a reference picture,
> +    // but not if it isn't.
> +    int                     nb_dpb_pics;
> +    struct HWBaseEncodePicture *dpb[MAX_DPB_SIZE];
> +    // The reference pictures used in decoding this picture. If they are
> +    // used by later pictures they will also appear in the DPB. ref[0][] for
> +    // previous reference frames. ref[1][] for future reference frames.
> +    int                     nb_refs[MAX_REFERENCE_LIST_NUM];
> +    struct HWBaseEncodePicture *refs[MAX_REFERENCE_LIST_NUM][MAX_PICTURE_REFERENCES];
> +    // The previous reference picture in encode order.  Must be in at least
> +    // one of the reference list and DPB list.
> +    struct HWBaseEncodePicture *prev;
> +    // Reference count for other pictures referring to this one through
> +    // the above pointers, directly from incomplete pictures and indirectly
> +    // through completed pictures.
> +    int             ref_count[2];
> +    int             ref_removed[2];
> +} HWBaseEncodePicture;
> +
> +typedef struct HWEncodePictureOperation {
> +    // Alloc memory for the picture structure.

Maybe something like "Allocate API-specific internals of a new picture structure based on the given frame."?

(Assuming you move the allocation of the structure itself out as suggested above.)

> +    HWBaseEncodePicture * (*alloc)(AVCodecContext *avctx, const AVFrame *frame);
> +    // Issue the picture structure, which will send the frame surface to HW Encode API.
> +    int (*issue)(AVCodecContext *avctx, const HWBaseEncodePicture *base_pic);
> +    // Get the output AVPacket.
> +    int (*output)(AVCodecContext *avctx, const HWBaseEncodePicture *base_pic, AVPacket *pkt);
> +    // Free the picture structure.
> +    int (*free)(AVCodecContext *avctx, HWBaseEncodePicture *base_pic);
> +}  HWEncodePictureOperation;
> +
>  typedef struct HWBaseEncodeContext {
>      const AVClass *class;
>  
> +    // Hardware-specific hooks.
> +    const struct HWEncodePictureOperation *op;
> +
> +    // Current encoding window, in display (input) order.
> +    HWBaseEncodePicture *pic_start, *pic_end;
> +    // The next picture to use as the previous reference picture in
> +    // encoding order. Order from small to large in encoding order.
> +    HWBaseEncodePicture *next_prev[MAX_PICTURE_REFERENCES];
> +    int                  nb_next_prev;
> +
> +    // Next input order index (display order).
> +    int64_t         input_order;
> +    // Number of frames that output is behind input.
> +    int64_t         output_delay;
> +    // Next encode order index.
> +    int64_t         encode_order;
> +    // Number of frames decode output will need to be delayed.
> +    int64_t         decode_delay;
> +    // Next output order index (in encode order).
> +    int64_t         output_order;
> +
> +    // Timestamp handling.
> +    int64_t         first_pts;
> +    int64_t         dts_pts_diff;
> +    int64_t         ts_ring[MAX_REORDER_DELAY * 3 +
> +                            MAX_ASYNC_DEPTH];
> +
> +    // Frame type decision.
> +    int gop_size;
> +    int closed_gop;
> +    int gop_per_idr;
> +    int p_per_i;
> +    int max_b_depth;
> +    int b_per_p;
> +    int force_idr;
> +    int idr_counter;
> +    int gop_counter;
> +    int end_of_stream;
> +    int p_to_gpb;
> +
> +    // Whether the driver supports ROI at all.
> +    int             roi_allowed;
> +
> +    // The encoder does not support cropping information, so warn about
> +    // it the first time we encounter any nonzero crop fields.
> +    int             crop_warned;
> +    // If the driver does not support ROI then warn the first time we
> +    // encounter a frame with ROI side data.
> +    int             roi_warned;
> +
> +    // The frame to be filled with data.
> +    AVFrame         *frame;
> +
> +    // Whether the HW supports sync buffer function.
> +    // If supported, encode_fifo/async_depth will be used together.
> +    // Used for output buffer synchronization.
> +    int             async_encode;
> +
> +    // Store buffered pic.
> +    AVFifo          *encode_fifo;
>      // Max number of frame buffered in encoder.
>      int             async_depth;
> +
> +    /** Tail data of a pic, now only used for av1 repeat frame header. */
> +    AVPacket        *tail_pkt;
>  } HWBaseEncodeContext;
>  
> +int ff_hw_base_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt);
> +
>  #define HW_BASE_ENCODE_COMMON_OPTIONS \
>      { "async_depth", "Maximum processing parallelism. " \
>        "Increase this to improve single channel performance.", \
> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
> index 227cccae64..18966596e1 100644
> --- a/libavcodec/vaapi_encode.c
> +++ b/libavcodec/vaapi_encode.c
> @@ -138,22 +138,26 @@ static int vaapi_encode_make_misc_param_buffer(AVCodecContext *avctx,
>  static int vaapi_encode_wait(AVCodecContext *avctx,
>                               VAAPIEncodePicture *pic)
>  {
> +#if VA_CHECK_VERSION(1, 9, 0)
> +    HWBaseEncodeContext *base_ctx = avctx->priv_data;
> +#endif
>      VAAPIEncodeContext *ctx = avctx->priv_data;
> +    HWBaseEncodePicture *base_pic = (HWBaseEncodePicture*)pic;

Use "base_foo = &foo->base_field" instead to avoid overriding the type-checking.

(Also in move places below.)

>      VAStatus vas;
>  
> -    av_assert0(pic->encode_issued);
> +    av_assert0(base_pic->encode_issued);
>  
> -    if (pic->encode_complete) {
> +    if (base_pic->encode_complete) {
>          // Already waited for this picture.
>          return 0;
>      }
>  
>      av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" "
> -           "(input surface %#x).\n", pic->display_order,
> -           pic->encode_order, pic->input_surface);
> +           "(input surface %#x).\n", base_pic->display_order,
> +           base_pic->encode_order, pic->input_surface);
>  
>  #if VA_CHECK_VERSION(1, 9, 0)
> -    if (ctx->has_sync_buffer_func) {
> +    if (base_ctx->async_encode) {
>          vas = vaSyncBuffer(ctx->hwctx->display,
>                             pic->output_buffer,
>                             VA_TIMEOUT_INFINITE);
> @@ -174,9 +178,9 @@ static int vaapi_encode_wait(AVCodecContext *avctx,
>      }
>  
>      // Input is definitely finished with now.
> -    av_frame_free(&pic->input_image);
> +    av_frame_free(&base_pic->input_image);
>  
> -    pic->encode_complete = 1;
> +    base_pic->encode_complete = 1;
>      return 0;
>  }
>  
> @@ -263,9 +267,11 @@ static int vaapi_encode_make_tile_slice(AVCodecContext *avctx,
>  }
>  
>  static int vaapi_encode_issue(AVCodecContext *avctx,
> -                              VAAPIEncodePicture *pic)
> +                              const HWBaseEncodePicture *base_pic)
>  {
> -    VAAPIEncodeContext *ctx = avctx->priv_data;
> +    HWBaseEncodeContext *base_ctx = avctx->priv_data;
> +    VAAPIEncodeContext       *ctx = avctx->priv_data;
> +    VAAPIEncodePicture *pic = (VAAPIEncodePicture*)base_pic;
>      VAAPIEncodeSlice *slice;
>      VAStatus vas;
>      int err, i;
> @@ -274,52 +280,46 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>      av_unused AVFrameSideData *sd;
>  
>      av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" "
> -           "as type %s.\n", pic->display_order, pic->encode_order,
> -           ff_hw_base_encode_get_pictype_name(pic->type));
> -    if (pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0) {
> +           "as type %s.\n", base_pic->display_order, base_pic->encode_order,
> +           ff_hw_base_encode_get_pictype_name(base_pic->type));
> +    if (base_pic->nb_refs[0] == 0 && base_pic->nb_refs[1] == 0) {
>          av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n");
>      } else {
>          av_log(avctx, AV_LOG_DEBUG, "L0 refers to");
> -        for (i = 0; i < pic->nb_refs[0]; i++) {
> +        for (i = 0; i < base_pic->nb_refs[0]; i++) {
>              av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
> -                   pic->refs[0][i]->display_order, pic->refs[0][i]->encode_order);
> +                   base_pic->refs[0][i]->display_order, base_pic->refs[0][i]->encode_order);
>          }
>          av_log(avctx, AV_LOG_DEBUG, ".\n");
>  
> -        if (pic->nb_refs[1]) {
> +        if (base_pic->nb_refs[1]) {
>              av_log(avctx, AV_LOG_DEBUG, "L1 refers to");
> -            for (i = 0; i < pic->nb_refs[1]; i++) {
> +            for (i = 0; i < base_pic->nb_refs[1]; i++) {
>                  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
> -                       pic->refs[1][i]->display_order, pic->refs[1][i]->encode_order);
> +                       base_pic->refs[1][i]->display_order, base_pic->refs[1][i]->encode_order);
>              }
>              av_log(avctx, AV_LOG_DEBUG, ".\n");
>          }
>      }
>  
> -    av_assert0(!pic->encode_issued);
> -    for (i = 0; i < pic->nb_refs[0]; i++) {
> -        av_assert0(pic->refs[0][i]);
> -        av_assert0(pic->refs[0][i]->encode_issued);
> +    av_assert0(!base_pic->encode_issued);
> +    for (i = 0; i < base_pic->nb_refs[0]; i++) {
> +        av_assert0(base_pic->refs[0][i]);
> +        av_assert0(base_pic->refs[0][i]->encode_issued);
>      }
> -    for (i = 0; i < pic->nb_refs[1]; i++) {
> -        av_assert0(pic->refs[1][i]);
> -        av_assert0(pic->refs[1][i]->encode_issued);
> +    for (i = 0; i < base_pic->nb_refs[1]; i++) {
> +        av_assert0(base_pic->refs[1][i]);
> +        av_assert0(base_pic->refs[1][i]->encode_issued);
>      }
>  
>      av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface);
>  
> -    pic->recon_image = av_frame_alloc();
> -    if (!pic->recon_image) {
> -        err = AVERROR(ENOMEM);
> -        goto fail;
> -    }
> -
> -    err = av_hwframe_get_buffer(ctx->recon_frames_ref, pic->recon_image, 0);
> +    err = av_hwframe_get_buffer(ctx->recon_frames_ref, base_pic->recon_image, 0);
>      if (err < 0) {
>          err = AVERROR(ENOMEM);
>          goto fail;
>      }
> -    pic->recon_surface = (VASurfaceID)(uintptr_t)pic->recon_image->data[3];
> +    pic->recon_surface = (VASurfaceID)(uintptr_t)base_pic->recon_image->data[3];
>      av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface);
>  
>      pic->output_buffer_ref = ff_refstruct_pool_get(ctx->output_buffer_pool);
> @@ -343,7 +343,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>  
>      pic->nb_param_buffers = 0;
>  
> -    if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) {
> +    if (base_pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) {
>          err = vaapi_encode_make_param_buffer(avctx, pic,
>                                               VAEncSequenceParameterBufferType,
>                                               ctx->codec_sequence_params,
> @@ -352,7 +352,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>              goto fail;
>      }
>  
> -    if (pic->type == PICTURE_TYPE_IDR) {
> +    if (base_pic->type == PICTURE_TYPE_IDR) {
>          for (i = 0; i < ctx->nb_global_params; i++) {
>              err = vaapi_encode_make_misc_param_buffer(avctx, pic,
>                                                        ctx->global_params_type[i],
> @@ -389,7 +389,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>      }
>  #endif
>  
> -    if (pic->type == PICTURE_TYPE_IDR) {
> +    if (base_pic->type == PICTURE_TYPE_IDR) {
>          if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE &&
>              ctx->codec->write_sequence_header) {
>              bit_len = 8 * sizeof(data);
> @@ -529,9 +529,9 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>      }
>  
>  #if VA_CHECK_VERSION(1, 0, 0)
> -    sd = av_frame_get_side_data(pic->input_image,
> +    sd = av_frame_get_side_data(base_pic->input_image,
>                                  AV_FRAME_DATA_REGIONS_OF_INTEREST);
> -    if (sd && ctx->roi_allowed) {
> +    if (sd && base_ctx->roi_allowed) {
>          const AVRegionOfInterest *roi;
>          uint32_t roi_size;
>          VAEncMiscParameterBufferROI param_roi;
> @@ -542,11 +542,11 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>          av_assert0(roi_size && sd->size % roi_size == 0);
>          nb_roi = sd->size / roi_size;
>          if (nb_roi > ctx->roi_max_regions) {
> -            if (!ctx->roi_warned) {
> +            if (!base_ctx->roi_warned) {
>                  av_log(avctx, AV_LOG_WARNING, "More ROIs set than "
>                         "supported by driver (%d > %d).\n",
>                         nb_roi, ctx->roi_max_regions);
> -                ctx->roi_warned = 1;
> +                base_ctx->roi_warned = 1;
>              }
>              nb_roi = ctx->roi_max_regions;
>          }
> @@ -639,8 +639,6 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>          }
>      }
>  
> -    pic->encode_issued = 1;
> -
>      return 0;
>  
>  fail_with_picture:
> @@ -657,14 +655,13 @@ fail_at_end:
>      av_freep(&pic->param_buffers);
>      av_freep(&pic->slices);
>      av_freep(&pic->roi);
> -    av_frame_free(&pic->recon_image);
>      ff_refstruct_unref(&pic->output_buffer_ref);
>      pic->output_buffer = VA_INVALID_ID;
>      return err;
>  }

All the churn in this function makes me wonder whether it would be better to have VAAPIEncodePicture *vaapi_pic and HWBaseEncodePicture *pic to avoid it?  (Perhaps not given that it uses both.)

> ...
> diff --git a/libavcodec/vaapi_encode_av1.c b/libavcodec/vaapi_encode_av1.c
> index f4b4586583..393b479f99 100644
> --- a/libavcodec/vaapi_encode_av1.c
> +++ b/libavcodec/vaapi_encode_av1.c
> @@ -357,6 +357,7 @@ static int vaapi_encode_av1_write_sequence_header(AVCodecContext *avctx,
>  
>  static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx)
>  {
> +    HWBaseEncodeContext         *base_ctx = avctx->priv_data;
>      VAAPIEncodeContext               *ctx = avctx->priv_data;
>      VAAPIEncodeAV1Context           *priv = avctx->priv_data;
>      AV1RawOBU                     *sh_obu = &priv->sh;
> @@ -438,8 +439,8 @@ static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx)
>      vseq->seq_level_idx           = sh->seq_level_idx[0];
>      vseq->seq_tier                = sh->seq_tier[0];
>      vseq->order_hint_bits_minus_1 = sh->order_hint_bits_minus_1;
> -    vseq->intra_period            = ctx->gop_size;
> -    vseq->ip_period               = ctx->b_per_p + 1;
> +    vseq->intra_period            = base_ctx->gop_size;
> +    vseq->ip_period               = base_ctx->b_per_p + 1;
>  
>      vseq->seq_fields.bits.enable_order_hint = sh->enable_order_hint;
>  
> @@ -466,12 +467,13 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>  {
>      VAAPIEncodeContext              *ctx = avctx->priv_data;
>      VAAPIEncodeAV1Context          *priv = avctx->priv_data;
> -    VAAPIEncodeAV1Picture          *hpic = pic->priv_data;
> +    HWBaseEncodePicture        *base_pic = (HWBaseEncodePicture *)pic;

base_pic is const here?

Also consider whether this naming is the best way around.

> +    VAAPIEncodeAV1Picture          *hpic = base_pic->priv_data;
>      AV1RawOBU                    *fh_obu = &priv->fh;
>      AV1RawFrameHeader                *fh = &fh_obu->obu.frame.header;
>      VAEncPictureParameterBufferAV1 *vpic = pic->codec_picture_params;
>      CodedBitstreamFragment          *obu = &priv->current_obu;
> -    VAAPIEncodePicture    *ref;
> +    HWBaseEncodePicture    *ref;
>      VAAPIEncodeAV1Picture *href;
>      int slot, i;
>      int ret;
> @@ -480,24 +482,24 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>  
>      memset(fh_obu, 0, sizeof(*fh_obu));
>      pic->nb_slices = priv->tile_groups;
> -    pic->non_independent_frame = pic->encode_order < pic->display_order;
> +    pic->non_independent_frame = base_pic->encode_order < base_pic->display_order;
>      fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
>      fh_obu->header.obu_has_size_field = 1;
>  
> -    switch (pic->type) {
> +    switch (base_pic->type) {
>      case PICTURE_TYPE_IDR:
> -        av_assert0(pic->nb_refs[0] == 0 || pic->nb_refs[1]);
> +        av_assert0(base_pic->nb_refs[0] == 0 || base_pic->nb_refs[1]);
>          fh->frame_type = AV1_FRAME_KEY;
>          fh->refresh_frame_flags = 0xFF;
>          fh->base_q_idx = priv->q_idx_idr;
>          hpic->slot = 0;
> -        hpic->last_idr_frame = pic->display_order;
> +        hpic->last_idr_frame = base_pic->display_order;
>          break;
>      case PICTURE_TYPE_P:
> -        av_assert0(pic->nb_refs[0]);
> +        av_assert0(base_pic->nb_refs[0]);
>          fh->frame_type = AV1_FRAME_INTER;
>          fh->base_q_idx = priv->q_idx_p;
> -        ref = pic->refs[0][pic->nb_refs[0] - 1];
> +        ref = base_pic->refs[0][base_pic->nb_refs[0] - 1];
>          href = ref->priv_data;
>          hpic->slot = !href->slot;
>          hpic->last_idr_frame = href->last_idr_frame;
> @@ -512,8 +514,8 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>          vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST;
>  
>          /** set the 2nd nearest frame in L0 as Golden frame. */
> -        if (pic->nb_refs[0] > 1) {
> -            ref = pic->refs[0][pic->nb_refs[0] - 2];
> +        if (base_pic->nb_refs[0] > 1) {
> +            ref = base_pic->refs[0][base_pic->nb_refs[0] - 2];
>              href = ref->priv_data;
>              fh->ref_frame_idx[3] = href->slot;
>              fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
> @@ -521,7 +523,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>          }
>          break;
>      case PICTURE_TYPE_B:
> -        av_assert0(pic->nb_refs[0] && pic->nb_refs[1]);
> +        av_assert0(base_pic->nb_refs[0] && base_pic->nb_refs[1]);
>          fh->frame_type = AV1_FRAME_INTER;
>          fh->base_q_idx = priv->q_idx_b;
>          fh->refresh_frame_flags = 0x0;
> @@ -534,7 +536,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>          vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST;
>          vpic->ref_frame_ctrl_l1.fields.search_idx0 = AV1_REF_FRAME_BWDREF;
>  
> -        ref                            = pic->refs[0][pic->nb_refs[0] - 1];
> +        ref                            = base_pic->refs[0][base_pic->nb_refs[0] - 1];
>          href                           = ref->priv_data;
>          hpic->last_idr_frame           = href->last_idr_frame;
>          fh->primary_ref_frame          = href->slot;
> @@ -543,7 +545,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>              fh->ref_frame_idx[i] = href->slot;
>          }
>  
> -        ref                            = pic->refs[1][pic->nb_refs[1] - 1];
> +        ref                            = base_pic->refs[1][base_pic->nb_refs[1] - 1];
>          href                           = ref->priv_data;
>          fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
>          for (i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++) {
> @@ -554,13 +556,13 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>          av_assert0(0 && "invalid picture type");
>      }
>  
> -    fh->show_frame                = pic->display_order <= pic->encode_order;
> +    fh->show_frame                = base_pic->display_order <= base_pic->encode_order;
>      fh->showable_frame            = fh->frame_type != AV1_FRAME_KEY;
>      fh->frame_width_minus_1       = avctx->width - 1;
>      fh->frame_height_minus_1      = avctx->height - 1;
>      fh->render_width_minus_1      = fh->frame_width_minus_1;
>      fh->render_height_minus_1     = fh->frame_height_minus_1;
> -    fh->order_hint                = pic->display_order - hpic->last_idr_frame;
> +    fh->order_hint                = base_pic->display_order - hpic->last_idr_frame;
>      fh->tile_cols                 = priv->tile_cols;
>      fh->tile_rows                 = priv->tile_rows;
>      fh->tile_cols_log2            = priv->tile_cols_log2;
> @@ -626,13 +628,13 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>          vpic->reference_frames[i] = VA_INVALID_SURFACE;
>  
>      for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) {
> -        for (int j = 0; j < pic->nb_refs[i]; j++) {
> -            VAAPIEncodePicture *ref_pic = pic->refs[i][j];
> +        for (int j = 0; j < base_pic->nb_refs[i]; j++) {
> +            HWBaseEncodePicture *ref_pic = base_pic->refs[i][j];
>  
>              slot = ((VAAPIEncodeAV1Picture*)ref_pic->priv_data)->slot;
>              av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE);
>  
> -            vpic->reference_frames[slot] = ref_pic->recon_surface;
> +            vpic->reference_frames[slot] = ((VAAPIEncodePicture *)ref_pic)->recon_surface;
>          }
>      }
>  
> @@ -653,7 +655,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
>          vpic->bit_offset_cdef_params         = priv->cdef_start_offset;
>          vpic->size_in_bits_cdef_params       = priv->cdef_param_size;
>          vpic->size_in_bits_frame_hdr_obu     = priv->fh_data_len;
> -        vpic->byte_offset_frame_hdr_obu_size = (((pic->type == PICTURE_TYPE_IDR) ?
> +        vpic->byte_offset_frame_hdr_obu_size = (((base_pic->type == PICTURE_TYPE_IDR) ?
>                                                 priv->sh_data_len / 8 : 0) +
>                                                 (fh_obu->header.obu_extension_flag ?
>                                                 2 : 1));
> @@ -695,14 +697,15 @@ static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx,
>      CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
>      AV1RawOBU               *fh_obu = &priv->fh;
>      AV1RawFrameHeader       *rep_fh = &fh_obu->obu.frame_header;
> +    HWBaseEncodePicture   *base_pic = (HWBaseEncodePicture *)pic;

Also const.

>      VAAPIEncodeAV1Picture *href;
>      int ret = 0;
>  
>      pic->tail_size = 0;
>      /** Pack repeat frame header. */
> -    if (pic->display_order > pic->encode_order) {
> +    if (base_pic->display_order > base_pic->encode_order) {
>          memset(fh_obu, 0, sizeof(*fh_obu));
> -        href = pic->refs[0][pic->nb_refs[0] - 1]->priv_data;
> +        href = base_pic->refs[0][base_pic->nb_refs[0] - 1]->priv_data;
>          fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
>          fh_obu->header.obu_has_size_field = 1;
>  
> @@ -937,7 +940,7 @@ const FFCodec ff_av1_vaapi_encoder = {
>      .p.id           = AV_CODEC_ID_AV1,
>      .priv_data_size = sizeof(VAAPIEncodeAV1Context),
>      .init           = &vaapi_encode_av1_init,
> -    FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
> +    FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
>      .close          = &vaapi_encode_av1_close,
>      .p.priv_class   = &vaapi_encode_av1_class,
>      .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
> ...

I didn't look carefully through the other codecs here.

Thanks,

- Mark
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  reply	other threads:[~2024-05-14 20:46 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-18  8:58 [FFmpeg-devel] [PATCH v8 01/15] avcodec/vaapi_encode: introduce a base layer for vaapi encode tong1.wu-at-intel.com
2024-04-18  8:58 ` [FFmpeg-devel] [PATCH v8 02/15] avcodec/vaapi_encode: add async_depth to common options tong1.wu-at-intel.com
2024-04-18  8:58 ` [FFmpeg-devel] [PATCH v8 03/15] avcodec/vaapi_encode: add picture type name to base tong1.wu-at-intel.com
2024-04-18  8:58 ` [FFmpeg-devel] [PATCH v8 04/15] avcodec/vaapi_encode: move pic->input_surface initialization to encode_alloc tong1.wu-at-intel.com
2024-04-18  8:58 ` [FFmpeg-devel] [PATCH v8 05/15] avcodec/vaapi_encode: move the dpb logic from VAAPI to base layer tong1.wu-at-intel.com
2024-05-14 20:46   ` Mark Thompson [this message]
2024-05-15 10:14     ` Wu, Tong1
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 06/15] avcodec/vaapi_encode: extract the init function " tong1.wu-at-intel.com
2024-05-14 20:56   ` Mark Thompson
2024-05-15 10:14     ` Wu, Tong1
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 07/15] avcodec/vaapi_encode: extract gop configuration and two options " tong1.wu-at-intel.com
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 08/15] avcodec/vaapi_encode: move two reconstructed frames parameters " tong1.wu-at-intel.com
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 09/15] avcodec/vaapi_encode: extract a close function for " tong1.wu-at-intel.com
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 10/15] avcodec/vaapi_encode: extract set_output_property to " tong1.wu-at-intel.com
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 11/15] avcodec/vaapi_encode: extract a get_recon_format function " tong1.wu-at-intel.com
2024-05-14 21:06   ` Mark Thompson
2024-05-15 10:14     ` Wu, Tong1
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 12/15] avcodec/vaapi_encode: extract a free funtion " tong1.wu-at-intel.com
2024-05-14 21:07   ` Mark Thompson
2024-05-20 15:10     ` Wu, Tong1
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 13/15] avutil/hwcontext_d3d12va: add Flags for resource creation tong1.wu-at-intel.com
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 14/15] avcodec: add D3D12VA hardware HEVC encoder tong1.wu-at-intel.com
2024-05-09  5:32   ` Wu, Tong1
2024-04-18  8:59 ` [FFmpeg-devel] [PATCH v8 15/15] Changelog: add D3D12VA HEVC encoder changelog tong1.wu-at-intel.com
2024-05-14 19:55 ` [FFmpeg-devel] [PATCH v8 01/15] avcodec/vaapi_encode: introduce a base layer for vaapi encode Mark Thompson
2024-05-15  9:43   ` Wu, Tong1

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=371d0efe-9631-48f7-bab8-33484b7776c5@jkqxz.net \
    --to=sw@jkqxz.net \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git