diff mbox series

[FFmpeg-devel,5/5] avcodec/avcodec: Add FFHWAccel, hide internals of AVHWAccel

Message ID GV1P250MB0737EB13529D51DDCB4985688F0BA@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM
State Accepted
Commit e35dfe864d8fb1ee9e28684a5a93e4b75d0d8092
Headers show
Series [FFmpeg-devel,1/5] avcodec/nvdec_(mjpeg|vp8): Constify AVHWAccels | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Andreas Rheinhardt Aug. 2, 2023, 6:43 a.m. UTC
This commit is the AVHWAccel analogue of commit
20f972701806be20a77f808db332d9489343bb78: It moves the private fields
of AVHWAccel to a new struct FFHWAccel extending AVHWAccel
in an internal header (namely hwaccel_internal.h).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
I wonder whether I should make a shortcut that returns the FFHWAccel
from an avctx; but I don't know a better name than "ffhwaccel2".

 configure                     |   2 +-
 libavcodec/av1dec.c           |  21 +++--
 libavcodec/avcodec.h          | 133 ------------------------------
 libavcodec/decode.c           |  21 ++---
 libavcodec/dxva2_av1.c        |  31 +++----
 libavcodec/dxva2_h264.c       |  31 +++----
 libavcodec/dxva2_hevc.c       |  31 +++----
 libavcodec/dxva2_mpeg2.c      |  31 +++----
 libavcodec/dxva2_vc1.c        |  61 +++++++-------
 libavcodec/dxva2_vp9.c        |  31 +++----
 libavcodec/h263dec.c          |   9 +-
 libavcodec/h264_picture.c     |   3 +-
 libavcodec/h264dec.c          |  25 +++---
 libavcodec/hevcdec.c          |  43 ++++------
 libavcodec/hwaccel_internal.h | 150 ++++++++++++++++++++++++++++++++++
 libavcodec/hwaccels.h         | 128 ++++++++++++++---------------
 libavcodec/hwconfig.h         |   2 +-
 libavcodec/mjpegdec.c         |  16 ++--
 libavcodec/mpeg12dec.c        |   9 +-
 libavcodec/nvdec_av1.c        |  11 +--
 libavcodec/nvdec_h264.c       |  11 +--
 libavcodec/nvdec_hevc.c       |  11 +--
 libavcodec/nvdec_mjpeg.c      |  11 +--
 libavcodec/nvdec_mpeg12.c     |  21 ++---
 libavcodec/nvdec_mpeg4.c      |  11 +--
 libavcodec/nvdec_vc1.c        |  21 ++---
 libavcodec/nvdec_vp8.c        |  11 +--
 libavcodec/nvdec_vp9.c        |  11 +--
 libavcodec/proresdec2.c       |   8 +-
 libavcodec/pthread_frame.c    |  19 +++--
 libavcodec/vaapi_av1.c        |  10 +--
 libavcodec/vaapi_h264.c       |  10 +--
 libavcodec/vaapi_hevc.c       |  10 +--
 libavcodec/vaapi_mjpeg.c      |  10 +--
 libavcodec/vaapi_mpeg2.c      |  10 +--
 libavcodec/vaapi_mpeg4.c      |  20 ++---
 libavcodec/vaapi_vc1.c        |  20 ++---
 libavcodec/vaapi_vp8.c        |  10 +--
 libavcodec/vaapi_vp9.c        |  10 +--
 libavcodec/vc1dec.c           |  56 +++++++++----
 libavcodec/vdpau.c            |   5 +-
 libavcodec/vdpau_av1.c        |  10 +--
 libavcodec/vdpau_h264.c       |  10 +--
 libavcodec/vdpau_hevc.c       |  10 +--
 libavcodec/vdpau_mpeg12.c     |  20 ++---
 libavcodec/vdpau_mpeg4.c      |  10 +--
 libavcodec/vdpau_vc1.c        |  20 ++---
 libavcodec/vdpau_vp9.c        |  10 +--
 libavcodec/videotoolbox.c     |  71 ++++++++--------
 libavcodec/videotoolbox_vp9.c |  11 +--
 libavcodec/vp8.c              |  12 +--
 libavcodec/vp9.c              |  12 +--
 libavcodec/vulkan_av1.c       |  10 +--
 libavcodec/vulkan_h264.c      |  10 +--
 libavcodec/vulkan_hevc.c      |  10 +--
 55 files changed, 691 insertions(+), 630 deletions(-)
diff mbox series

Patch

diff --git a/configure b/configure
index 99388e7664..d9372c5be6 100755
--- a/configure
+++ b/configure
@@ -4102,7 +4102,7 @@  CODEC_LIST="
 "
 PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parsers.c)
 BSF_LIST=$(find_things_extern bsf FFBitStreamFilter libavcodec/bitstream_filters.c)
-HWACCEL_LIST=$(find_things_extern hwaccel AVHWAccel libavcodec/hwaccels.h)
+HWACCEL_LIST=$(find_things_extern hwaccel FFHWAccel libavcodec/hwaccels.h)
 PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c)
 
 AVCODEC_COMPONENTS_LIST="
diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index 09339529f7..03283ab064 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -33,6 +33,7 @@ 
 #include "bytestream.h"
 #include "codec_internal.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "hwconfig.h"
 #include "profiles.h"
@@ -1233,9 +1234,9 @@  static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
                 }
             }
 
-            if (avctx->hwaccel && avctx->hwaccel->decode_params) {
-                ret = avctx->hwaccel->decode_params(avctx, unit->type, unit->data,
-                                                    unit->data_size);
+            if (FF_HW_HAS_CB(avctx, decode_params)) {
+                ret = FF_HW_CALL(avctx, decode_params, unit->type,
+                                 unit->data, unit->data_size);
                 if (ret < 0) {
                     av_log(avctx, AV_LOG_ERROR, "HW accel decode params fail.\n");
                     s->raw_seq = NULL;
@@ -1305,8 +1306,7 @@  static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
             s->cur_frame.temporal_id = header->temporal_id;
 
             if (avctx->hwaccel && s->cur_frame.f->buf[0]) {
-                ret = avctx->hwaccel->start_frame(avctx, unit->data,
-                                                  unit->data_size);
+                ret = FF_HW_CALL(avctx, start_frame, unit->data, unit->data_size);
                 if (ret < 0) {
                     av_log(avctx, AV_LOG_ERROR, "HW accel start frame fail.\n");
                     goto end;
@@ -1332,9 +1332,8 @@  static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
                 goto end;
 
             if (avctx->hwaccel && s->cur_frame.f->buf[0]) {
-                ret = avctx->hwaccel->decode_slice(avctx,
-                                                   raw_tile_group->tile_data.data,
-                                                   raw_tile_group->tile_data.data_size);
+                ret = FF_HW_CALL(avctx, decode_slice, raw_tile_group->tile_data.data,
+                                 raw_tile_group->tile_data.data_size);
                 if (ret < 0) {
                     av_log(avctx, AV_LOG_ERROR,
                            "HW accel decode slice fail.\n");
@@ -1396,7 +1395,7 @@  static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
         if (raw_tile_group && (s->tile_num == raw_tile_group->tg_end + 1)) {
             int show_frame = s->raw_frame_header->show_frame;
             if (avctx->hwaccel && s->cur_frame.f->buf[0]) {
-                ret = avctx->hwaccel->end_frame(avctx);
+                ret = FF_HW_SIMPLE_CALL(avctx, end_frame);
                 if (ret < 0) {
                     av_log(avctx, AV_LOG_ERROR, "HW accel end frame fail.\n");
                     goto end;
@@ -1492,8 +1491,8 @@  static void av1_decode_flush(AVCodecContext *avctx)
     ff_cbs_fragment_reset(&s->current_obu);
     ff_cbs_flush(s->cbc);
 
-    if (avctx->hwaccel && avctx->hwaccel->flush)
-        avctx->hwaccel->flush(avctx);
+    if (FF_HW_HAS_CB(avctx, flush))
+        FF_HW_SIMPLE_CALL(avctx, flush);
 }
 
 #define OFFSET(x) offsetof(AV1DecContext, x)
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index fe41ecc3c9..a2680256d7 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2146,139 +2146,6 @@  typedef struct AVHWAccel {
      * see AV_HWACCEL_CODEC_CAP_*
      */
     int capabilities;
-
-    /*****************************************************************
-     * No fields below this line are part of the public API. They
-     * may not be used outside of libavcodec and can be changed and
-     * removed at will.
-     * New public fields should be added right above.
-     *****************************************************************
-     */
-
-    /**
-     * Allocate a custom buffer
-     */
-    int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame);
-
-    /**
-     * Called at the beginning of each frame or field picture.
-     *
-     * Meaningful frame information (codec specific) is guaranteed to
-     * be parsed at this point. This function is mandatory.
-     *
-     * Note that buf can be NULL along with buf_size set to 0.
-     * Otherwise, this means the whole frame is available at this point.
-     *
-     * @param avctx the codec context
-     * @param buf the frame data buffer base
-     * @param buf_size the size of the frame in bytes
-     * @return zero if successful, a negative value otherwise
-     */
-    int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
-
-    /**
-     * Callback for parameter data (SPS/PPS/VPS etc).
-     *
-     * Useful for hardware decoders which keep persistent state about the
-     * video parameters, and need to receive any changes to update that state.
-     *
-     * @param avctx the codec context
-     * @param type the nal unit type
-     * @param buf the nal unit data buffer
-     * @param buf_size the size of the nal unit in bytes
-     * @return zero if successful, a negative value otherwise
-     */
-    int (*decode_params)(AVCodecContext *avctx, int type, const uint8_t *buf, uint32_t buf_size);
-
-    /**
-     * Callback for each slice.
-     *
-     * Meaningful slice information (codec specific) is guaranteed to
-     * be parsed at this point. This function is mandatory.
-     *
-     * @param avctx the codec context
-     * @param buf the slice data buffer base
-     * @param buf_size the size of the slice in bytes
-     * @return zero if successful, a negative value otherwise
-     */
-    int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
-
-    /**
-     * Called at the end of each frame or field picture.
-     *
-     * The whole picture is parsed at this point and can now be sent
-     * to the hardware accelerator. This function is mandatory.
-     *
-     * @param avctx the codec context
-     * @return zero if successful, a negative value otherwise
-     */
-    int (*end_frame)(AVCodecContext *avctx);
-
-    /**
-     * Size of per-frame hardware accelerator private data.
-     *
-     * Private data is allocated with av_mallocz() before
-     * AVCodecContext.get_buffer() and deallocated after
-     * AVCodecContext.release_buffer().
-     */
-    int frame_priv_data_size;
-
-    /**
-     * Initialize the hwaccel private data.
-     *
-     * This will be called from ff_get_format(), after hwaccel and
-     * hwaccel_context are set and the hwaccel private data in AVCodecInternal
-     * is allocated.
-     */
-    int (*init)(AVCodecContext *avctx);
-
-    /**
-     * Uninitialize the hwaccel private data.
-     *
-     * This will be called from get_format() or avcodec_close(), after hwaccel
-     * and hwaccel_context are already uninitialized.
-     */
-    int (*uninit)(AVCodecContext *avctx);
-
-    /**
-     * Size of the private data to allocate in
-     * AVCodecInternal.hwaccel_priv_data.
-     */
-    int priv_data_size;
-
-    /**
-     * Internal hwaccel capabilities.
-     */
-    int caps_internal;
-
-    /**
-     * Fill the given hw_frames context with current codec parameters. Called
-     * from get_format. Refer to avcodec_get_hw_frames_parameters() for
-     * details.
-     *
-     * This CAN be called before AVHWAccel.init is called, and you must assume
-     * that avctx->hwaccel_priv_data is invalid.
-     */
-    int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx);
-
-    /**
-     * Copy necessary context variables from a previous thread context to the current one.
-     * For thread-safe hwaccels only.
-     */
-    int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src);
-
-    /**
-     * Callback to free the hwaccel-specific frame data.
-     *
-     * @param hwctx a pointer to an AVHWDeviceContext.
-     * @param data the per-frame hardware accelerator private data to be freed.
-     */
-    void (*free_frame_priv)(void *hwctx, uint8_t *data);
-
-    /**
-     * Callback to flush the hwaccel state.
-     */
-    void (*flush)(AVCodecContext *avctx);
 } AVHWAccel;
 
 /**
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index be761873a3..7eada8e9ab 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -46,6 +46,7 @@ 
 #include "bsf.h"
 #include "codec_internal.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "internal.h"
 #include "packet_internal.h"
@@ -1159,7 +1160,7 @@  int avcodec_get_hw_frames_parameters(AVCodecContext *avctx,
 {
     AVBufferRef *frames_ref = NULL;
     const AVCodecHWConfigInternal *hw_config;
-    const AVHWAccel *hwa;
+    const FFHWAccel *hwa;
     int i, ret;
 
     for (i = 0;; i++) {
@@ -1211,14 +1212,14 @@  int avcodec_get_hw_frames_parameters(AVCodecContext *avctx,
 }
 
 static int hwaccel_init(AVCodecContext *avctx,
-                        const AVHWAccel *hwaccel)
+                        const FFHWAccel *hwaccel)
 {
     int err;
 
-    if (hwaccel->capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL &&
+    if (hwaccel->p.capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL &&
         avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
         av_log(avctx, AV_LOG_WARNING, "Ignoring experimental hwaccel: %s\n",
-               hwaccel->name);
+               hwaccel->p.name);
         return AVERROR_PATCHWELCOME;
     }
 
@@ -1229,13 +1230,13 @@  static int hwaccel_init(AVCodecContext *avctx,
             return AVERROR(ENOMEM);
     }
 
-    avctx->hwaccel = hwaccel;
+    avctx->hwaccel = &hwaccel->p;
     if (hwaccel->init) {
         err = hwaccel->init(avctx);
         if (err < 0) {
             av_log(avctx, AV_LOG_ERROR, "Failed setup for format %s: "
                    "hwaccel initialisation returned error.\n",
-                   av_get_pix_fmt_name(hwaccel->pix_fmt));
+                   av_get_pix_fmt_name(hwaccel->p.pix_fmt));
             av_freep(&avctx->internal->hwaccel_priv_data);
             avctx->hwaccel = NULL;
             return err;
@@ -1247,8 +1248,8 @@  static int hwaccel_init(AVCodecContext *avctx,
 
 void ff_hwaccel_uninit(AVCodecContext *avctx)
 {
-    if (avctx->hwaccel && avctx->hwaccel->uninit)
-        avctx->hwaccel->uninit(avctx);
+    if (FF_HW_HAS_CB(avctx, uninit))
+        FF_HW_SIMPLE_CALL(avctx, uninit);
 
     av_freep(&avctx->internal->hwaccel_priv_data);
 
@@ -1569,7 +1570,7 @@  int ff_attach_decode_data(AVFrame *frame)
 
 int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
 {
-    const AVHWAccel *hwaccel = avctx->hwaccel;
+    const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
     int override_dimensions = 1;
     int ret;
 
@@ -1791,7 +1792,7 @@  int ff_copy_palette(void *dst, const AVPacket *src, void *logctx)
 int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void **hwaccel_picture_private,
                                 AVBufferRef **hwaccel_priv_buf)
 {
-    const AVHWAccel *hwaccel = avctx->hwaccel;
+    const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
     AVBufferRef *ref;
     AVHWFramesContext *frames_ctx;
     uint8_t *data;
diff --git a/libavcodec/dxva2_av1.c b/libavcodec/dxva2_av1.c
index 228f72ba18..ab118a4356 100644
--- a/libavcodec/dxva2_av1.c
+++ b/libavcodec/dxva2_av1.c
@@ -27,6 +27,7 @@ 
 
 #include "dxva2_internal.h"
 #include "av1dec.h"
+#include "hwaccel_internal.h"
 
 #define MAX_TILES 256
 
@@ -457,11 +458,11 @@  static int dxva2_av1_uninit(AVCodecContext *avctx)
 }
 
 #if CONFIG_AV1_DXVA2_HWACCEL
-const AVHWAccel ff_av1_dxva2_hwaccel = {
-    .name           = "av1_dxva2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_AV1,
-    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
+const FFHWAccel ff_av1_dxva2_hwaccel = {
+    .p.name         = "av1_dxva2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_AV1,
+    .p.pix_fmt      = AV_PIX_FMT_DXVA2_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = dxva2_av1_uninit,
     .start_frame    = dxva2_av1_start_frame,
@@ -474,11 +475,11 @@  const AVHWAccel ff_av1_dxva2_hwaccel = {
 #endif
 
 #if CONFIG_AV1_D3D11VA_HWACCEL
-const AVHWAccel ff_av1_d3d11va_hwaccel = {
-    .name           = "av1_d3d11va",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_AV1,
-    .pix_fmt        = AV_PIX_FMT_D3D11VA_VLD,
+const FFHWAccel ff_av1_d3d11va_hwaccel = {
+    .p.name         = "av1_d3d11va",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_AV1,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11VA_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = dxva2_av1_uninit,
     .start_frame    = dxva2_av1_start_frame,
@@ -491,11 +492,11 @@  const AVHWAccel ff_av1_d3d11va_hwaccel = {
 #endif
 
 #if CONFIG_AV1_D3D11VA2_HWACCEL
-const AVHWAccel ff_av1_d3d11va2_hwaccel = {
-    .name           = "av1_d3d11va2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_AV1,
-    .pix_fmt        = AV_PIX_FMT_D3D11,
+const FFHWAccel ff_av1_d3d11va2_hwaccel = {
+    .p.name         = "av1_d3d11va2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_AV1,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11,
     .init           = ff_dxva2_decode_init,
     .uninit         = dxva2_av1_uninit,
     .start_frame    = dxva2_av1_start_frame,
diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c
index 6300b1418d..20e64f848d 100644
--- a/libavcodec/dxva2_h264.c
+++ b/libavcodec/dxva2_h264.c
@@ -28,6 +28,7 @@ 
 #include "h264dec.h"
 #include "h264data.h"
 #include "h264_ps.h"
+#include "hwaccel_internal.h"
 #include "mpegutils.h"
 
 struct dxva2_picture_context {
@@ -516,11 +517,11 @@  static int dxva2_h264_end_frame(AVCodecContext *avctx)
 }
 
 #if CONFIG_H264_DXVA2_HWACCEL
-const AVHWAccel ff_h264_dxva2_hwaccel = {
-    .name           = "h264_dxva2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_H264,
-    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
+const FFHWAccel ff_h264_dxva2_hwaccel = {
+    .p.name         = "h264_dxva2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_H264,
+    .p.pix_fmt      = AV_PIX_FMT_DXVA2_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_h264_start_frame,
@@ -533,11 +534,11 @@  const AVHWAccel ff_h264_dxva2_hwaccel = {
 #endif
 
 #if CONFIG_H264_D3D11VA_HWACCEL
-const AVHWAccel ff_h264_d3d11va_hwaccel = {
-    .name           = "h264_d3d11va",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_H264,
-    .pix_fmt        = AV_PIX_FMT_D3D11VA_VLD,
+const FFHWAccel ff_h264_d3d11va_hwaccel = {
+    .p.name         = "h264_d3d11va",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_H264,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11VA_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_h264_start_frame,
@@ -550,11 +551,11 @@  const AVHWAccel ff_h264_d3d11va_hwaccel = {
 #endif
 
 #if CONFIG_H264_D3D11VA2_HWACCEL
-const AVHWAccel ff_h264_d3d11va2_hwaccel = {
-    .name           = "h264_d3d11va2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_H264,
-    .pix_fmt        = AV_PIX_FMT_D3D11,
+const FFHWAccel ff_h264_d3d11va2_hwaccel = {
+    .p.name         = "h264_d3d11va2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_H264,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_h264_start_frame,
diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c
index 6b239d9917..b6c08943f0 100644
--- a/libavcodec/dxva2_hevc.c
+++ b/libavcodec/dxva2_hevc.c
@@ -27,6 +27,7 @@ 
 #include "dxva2_internal.h"
 #include "hevc_data.h"
 #include "hevcdec.h"
+#include "hwaccel_internal.h"
 
 #define MAX_SLICES 256
 
@@ -420,11 +421,11 @@  static int dxva2_hevc_end_frame(AVCodecContext *avctx)
 }
 
 #if CONFIG_HEVC_DXVA2_HWACCEL
-const AVHWAccel ff_hevc_dxva2_hwaccel = {
-    .name           = "hevc_dxva2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_HEVC,
-    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
+const FFHWAccel ff_hevc_dxva2_hwaccel = {
+    .p.name         = "hevc_dxva2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_HEVC,
+    .p.pix_fmt      = AV_PIX_FMT_DXVA2_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_hevc_start_frame,
@@ -437,11 +438,11 @@  const AVHWAccel ff_hevc_dxva2_hwaccel = {
 #endif
 
 #if CONFIG_HEVC_D3D11VA_HWACCEL
-const AVHWAccel ff_hevc_d3d11va_hwaccel = {
-    .name           = "hevc_d3d11va",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_HEVC,
-    .pix_fmt        = AV_PIX_FMT_D3D11VA_VLD,
+const FFHWAccel ff_hevc_d3d11va_hwaccel = {
+    .p.name         = "hevc_d3d11va",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_HEVC,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11VA_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_hevc_start_frame,
@@ -454,11 +455,11 @@  const AVHWAccel ff_hevc_d3d11va_hwaccel = {
 #endif
 
 #if CONFIG_HEVC_D3D11VA2_HWACCEL
-const AVHWAccel ff_hevc_d3d11va2_hwaccel = {
-    .name           = "hevc_d3d11va2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_HEVC,
-    .pix_fmt        = AV_PIX_FMT_D3D11,
+const FFHWAccel ff_hevc_d3d11va2_hwaccel = {
+    .p.name         = "hevc_d3d11va2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_HEVC,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_hevc_start_frame,
diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c
index 1989c588dc..75c416654f 100644
--- a/libavcodec/dxva2_mpeg2.c
+++ b/libavcodec/dxva2_mpeg2.c
@@ -25,6 +25,7 @@ 
 #include "libavutil/log.h"
 
 #include "dxva2_internal.h"
+#include "hwaccel_internal.h"
 #include "mpegutils.h"
 #include "mpegvideodec.h"
 
@@ -316,11 +317,11 @@  static int dxva2_mpeg2_end_frame(AVCodecContext *avctx)
 }
 
 #if CONFIG_MPEG2_DXVA2_HWACCEL
-const AVHWAccel ff_mpeg2_dxva2_hwaccel = {
-    .name           = "mpeg2_dxva2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG2VIDEO,
-    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
+const FFHWAccel ff_mpeg2_dxva2_hwaccel = {
+    .p.name         = "mpeg2_dxva2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt      = AV_PIX_FMT_DXVA2_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_mpeg2_start_frame,
@@ -333,11 +334,11 @@  const AVHWAccel ff_mpeg2_dxva2_hwaccel = {
 #endif
 
 #if CONFIG_MPEG2_D3D11VA_HWACCEL
-const AVHWAccel ff_mpeg2_d3d11va_hwaccel = {
-    .name           = "mpeg2_d3d11va",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG2VIDEO,
-    .pix_fmt        = AV_PIX_FMT_D3D11VA_VLD,
+const FFHWAccel ff_mpeg2_d3d11va_hwaccel = {
+    .p.name         = "mpeg2_d3d11va",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11VA_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_mpeg2_start_frame,
@@ -350,11 +351,11 @@  const AVHWAccel ff_mpeg2_d3d11va_hwaccel = {
 #endif
 
 #if CONFIG_MPEG2_D3D11VA2_HWACCEL
-const AVHWAccel ff_mpeg2_d3d11va2_hwaccel = {
-    .name           = "mpeg2_d3d11va2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG2VIDEO,
-    .pix_fmt        = AV_PIX_FMT_D3D11,
+const FFHWAccel ff_mpeg2_d3d11va2_hwaccel = {
+    .p.name         = "mpeg2_d3d11va2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_mpeg2_start_frame,
diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c
index 12e3de59ec..b35fb115f7 100644
--- a/libavcodec/dxva2_vc1.c
+++ b/libavcodec/dxva2_vc1.c
@@ -23,6 +23,7 @@ 
 #include "config_components.h"
 
 #include "dxva2_internal.h"
+#include "hwaccel_internal.h"
 #include "mpegutils.h"
 #include "mpegvideodec.h"
 #include "vc1.h"
@@ -376,11 +377,11 @@  static int dxva2_vc1_end_frame(AVCodecContext *avctx)
 }
 
 #if CONFIG_WMV3_DXVA2_HWACCEL
-const AVHWAccel ff_wmv3_dxva2_hwaccel = {
-    .name           = "wmv3_dxva2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_WMV3,
-    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
+const FFHWAccel ff_wmv3_dxva2_hwaccel = {
+    .p.name         = "wmv3_dxva2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_WMV3,
+    .p.pix_fmt      = AV_PIX_FMT_DXVA2_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vc1_start_frame,
@@ -393,11 +394,11 @@  const AVHWAccel ff_wmv3_dxva2_hwaccel = {
 #endif
 
 #if CONFIG_VC1_DXVA2_HWACCEL
-const AVHWAccel ff_vc1_dxva2_hwaccel = {
-    .name           = "vc1_dxva2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VC1,
-    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
+const FFHWAccel ff_vc1_dxva2_hwaccel = {
+    .p.name         = "vc1_dxva2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VC1,
+    .p.pix_fmt      = AV_PIX_FMT_DXVA2_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vc1_start_frame,
@@ -410,11 +411,11 @@  const AVHWAccel ff_vc1_dxva2_hwaccel = {
 #endif
 
 #if CONFIG_WMV3_D3D11VA_HWACCEL
-const AVHWAccel ff_wmv3_d3d11va_hwaccel = {
-    .name           = "wmv3_d3d11va",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_WMV3,
-    .pix_fmt        = AV_PIX_FMT_D3D11VA_VLD,
+const FFHWAccel ff_wmv3_d3d11va_hwaccel = {
+    .p.name         = "wmv3_d3d11va",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_WMV3,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11VA_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vc1_start_frame,
@@ -427,11 +428,11 @@  const AVHWAccel ff_wmv3_d3d11va_hwaccel = {
 #endif
 
 #if CONFIG_WMV3_D3D11VA2_HWACCEL
-const AVHWAccel ff_wmv3_d3d11va2_hwaccel = {
-    .name           = "wmv3_d3d11va2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_WMV3,
-    .pix_fmt        = AV_PIX_FMT_D3D11,
+const FFHWAccel ff_wmv3_d3d11va2_hwaccel = {
+    .p.name         = "wmv3_d3d11va2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_WMV3,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vc1_start_frame,
@@ -444,11 +445,11 @@  const AVHWAccel ff_wmv3_d3d11va2_hwaccel = {
 #endif
 
 #if CONFIG_VC1_D3D11VA_HWACCEL
-const AVHWAccel ff_vc1_d3d11va_hwaccel = {
-    .name           = "vc1_d3d11va",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VC1,
-    .pix_fmt        = AV_PIX_FMT_D3D11VA_VLD,
+const FFHWAccel ff_vc1_d3d11va_hwaccel = {
+    .p.name         = "vc1_d3d11va",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VC1,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11VA_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vc1_start_frame,
@@ -461,11 +462,11 @@  const AVHWAccel ff_vc1_d3d11va_hwaccel = {
 #endif
 
 #if CONFIG_VC1_D3D11VA2_HWACCEL
-const AVHWAccel ff_vc1_d3d11va2_hwaccel = {
-    .name           = "vc1_d3d11va2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VC1,
-    .pix_fmt        = AV_PIX_FMT_D3D11,
+const FFHWAccel ff_vc1_d3d11va2_hwaccel = {
+    .p.name         = "vc1_d3d11va2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VC1,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vc1_start_frame,
diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c
index dbe6c08ad1..eba4df9031 100644
--- a/libavcodec/dxva2_vp9.c
+++ b/libavcodec/dxva2_vp9.c
@@ -26,6 +26,7 @@ 
 #include "libavutil/pixdesc.h"
 
 #include "dxva2_internal.h"
+#include "hwaccel_internal.h"
 #include "vp9shared.h"
 
 struct vp9_dxva2_picture_context {
@@ -307,11 +308,11 @@  static int dxva2_vp9_end_frame(AVCodecContext *avctx)
 }
 
 #if CONFIG_VP9_DXVA2_HWACCEL
-const AVHWAccel ff_vp9_dxva2_hwaccel = {
-    .name           = "vp9_dxva2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VP9,
-    .pix_fmt        = AV_PIX_FMT_DXVA2_VLD,
+const FFHWAccel ff_vp9_dxva2_hwaccel = {
+    .p.name         = "vp9_dxva2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VP9,
+    .p.pix_fmt      = AV_PIX_FMT_DXVA2_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vp9_start_frame,
@@ -324,11 +325,11 @@  const AVHWAccel ff_vp9_dxva2_hwaccel = {
 #endif
 
 #if CONFIG_VP9_D3D11VA_HWACCEL
-const AVHWAccel ff_vp9_d3d11va_hwaccel = {
-    .name           = "vp9_d3d11va",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VP9,
-    .pix_fmt        = AV_PIX_FMT_D3D11VA_VLD,
+const FFHWAccel ff_vp9_d3d11va_hwaccel = {
+    .p.name         = "vp9_d3d11va",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VP9,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11VA_VLD,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vp9_start_frame,
@@ -341,11 +342,11 @@  const AVHWAccel ff_vp9_d3d11va_hwaccel = {
 #endif
 
 #if CONFIG_VP9_D3D11VA2_HWACCEL
-const AVHWAccel ff_vp9_d3d11va2_hwaccel = {
-    .name           = "vp9_d3d11va2",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VP9,
-    .pix_fmt        = AV_PIX_FMT_D3D11,
+const FFHWAccel ff_vp9_d3d11va2_hwaccel = {
+    .p.name         = "vp9_d3d11va2",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VP9,
+    .p.pix_fmt      = AV_PIX_FMT_D3D11,
     .init           = ff_dxva2_decode_init,
     .uninit         = ff_dxva2_decode_uninit,
     .start_frame    = dxva2_vp9_start_frame,
diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
index 68a618a7ed..52e51dd489 100644
--- a/libavcodec/h263dec.c
+++ b/libavcodec/h263dec.c
@@ -36,6 +36,7 @@ 
 #include "flvdec.h"
 #include "h263.h"
 #include "h263dec.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "mpeg_er.h"
 #include "mpeg4video.h"
@@ -190,7 +191,7 @@  static int decode_slice(MpegEncContext *s)
 
     if (s->avctx->hwaccel) {
         const uint8_t *start = s->gb.buffer + get_bits_count(&s->gb) / 8;
-        ret = s->avctx->hwaccel->decode_slice(s->avctx, start, s->gb.buffer_end - start);
+        ret = FF_HW_CALL(s->avctx, decode_slice, start, s->gb.buffer_end - start);
         // ensure we exit decode loop
         s->mb_y = s->mb_height;
         return ret;
@@ -568,8 +569,8 @@  retry:
         ff_thread_finish_setup(avctx);
 
     if (avctx->hwaccel) {
-        ret = avctx->hwaccel->start_frame(avctx, s->gb.buffer,
-                                          s->gb.buffer_end - s->gb.buffer);
+        ret = FF_HW_CALL(avctx, start_frame,
+                         s->gb.buffer, s->gb.buffer_end - s->gb.buffer);
         if (ret < 0 )
             return ret;
     }
@@ -624,7 +625,7 @@  frame_end:
         ff_er_frame_end(&s->er);
 
     if (avctx->hwaccel) {
-        ret = avctx->hwaccel->end_frame(avctx);
+        ret = FF_HW_SIMPLE_CALL(avctx, end_frame);
         if (ret < 0)
             return ret;
     }
diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c
index dcaf0fdb0a..3192c70a91 100644
--- a/libavcodec/h264_picture.c
+++ b/libavcodec/h264_picture.c
@@ -29,6 +29,7 @@ 
 #include "error_resilience.h"
 #include "avcodec.h"
 #include "h264dec.h"
+#include "hwaccel_internal.h"
 #include "mpegutils.h"
 #include "thread.h"
 #include "threadframe.h"
@@ -233,7 +234,7 @@  int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup)
     }
 
     if (avctx->hwaccel) {
-        err = avctx->hwaccel->end_frame(avctx);
+        err = FF_HW_SIMPLE_CALL(avctx, end_frame);
         if (err < 0)
             av_log(avctx, AV_LOG_ERROR,
                    "hardware accelerator failed to decode picture\n");
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 19f8dba131..1c79d9842f 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -45,6 +45,7 @@ 
 #include "h264data.h"
 #include "h264_ps.h"
 #include "golomb.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "mpegutils.h"
 #include "profiles.h"
@@ -485,8 +486,8 @@  static void h264_decode_flush(AVCodecContext *avctx)
     ff_h264_free_tables(h);
     h->context_initialized = 0;
 
-    if (avctx->hwaccel && avctx->hwaccel->flush)
-        avctx->hwaccel->flush(avctx);
+    if (FF_HW_HAS_CB(avctx, flush))
+        FF_HW_SIMPLE_CALL(avctx, flush);
 }
 
 static int get_last_needed_nal(H264Context *h)
@@ -652,14 +653,14 @@  static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
                 }
 
                 if (h->avctx->hwaccel &&
-                    (ret = h->avctx->hwaccel->start_frame(h->avctx, buf, buf_size)) < 0)
+                    (ret = FF_HW_CALL(h->avctx, start_frame, buf, buf_size)) < 0)
                     goto end;
             }
 
             max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx;
             if (h->nb_slice_ctx_queued == max_slice_ctx) {
                 if (h->avctx->hwaccel) {
-                    ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size);
+                    ret = FF_HW_CALL(avctx, decode_slice, nal->raw_data, nal->raw_size);
                     h->nb_slice_ctx_queued = 0;
                 } else
                     ret = ff_h264_execute_decode_slices(h);
@@ -686,11 +687,9 @@  static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
             break;
         case H264_NAL_SPS: {
             GetBitContext tmp_gb = nal->gb;
-            if (avctx->hwaccel && avctx->hwaccel->decode_params) {
-                ret = avctx->hwaccel->decode_params(avctx,
-                                                    nal->type,
-                                                    nal->raw_data,
-                                                    nal->raw_size);
+            if (FF_HW_HAS_CB(avctx, decode_params)) {
+                ret = FF_HW_CALL(avctx, decode_params,
+                                 nal->type, nal->raw_data, nal->raw_size);
                 if (ret < 0)
                     goto end;
             }
@@ -705,11 +704,9 @@  static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
             break;
         }
         case H264_NAL_PPS:
-            if (avctx->hwaccel && avctx->hwaccel->decode_params) {
-                ret = avctx->hwaccel->decode_params(avctx,
-                                                    nal->type,
-                                                    nal->raw_data,
-                                                    nal->raw_size);
+            if (FF_HW_HAS_CB(avctx, decode_params)) {
+                ret = FF_HW_CALL(avctx, decode_params,
+                                 nal->type, nal->raw_data, nal->raw_size);
                 if (ret < 0)
                     goto end;
             }
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 15276edd33..df40c91ba6 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -46,6 +46,7 @@ 
 #include "hevc_data.h"
 #include "hevc_parse.h"
 #include "hevcdec.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "internal.h"
 #include "profiles.h"
@@ -2948,11 +2949,9 @@  static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
 
     switch (s->nal_unit_type) {
     case HEVC_NAL_VPS:
-        if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) {
-            ret = s->avctx->hwaccel->decode_params(s->avctx,
-                                                   nal->type,
-                                                   nal->raw_data,
-                                                   nal->raw_size);
+        if (FF_HW_HAS_CB(s->avctx, decode_params)) {
+            ret = FF_HW_CALL(s->avctx, decode_params,
+                             nal->type, nal->raw_data, nal->raw_size);
             if (ret < 0)
                 goto fail;
         }
@@ -2961,11 +2960,9 @@  static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
             goto fail;
         break;
     case HEVC_NAL_SPS:
-        if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) {
-            ret = s->avctx->hwaccel->decode_params(s->avctx,
-                                                   nal->type,
-                                                   nal->raw_data,
-                                                   nal->raw_size);
+        if (FF_HW_HAS_CB(s->avctx, decode_params)) {
+            ret = FF_HW_CALL(s->avctx, decode_params,
+                             nal->type, nal->raw_data, nal->raw_size);
             if (ret < 0)
                 goto fail;
         }
@@ -2975,11 +2972,9 @@  static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
             goto fail;
         break;
     case HEVC_NAL_PPS:
-        if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) {
-            ret = s->avctx->hwaccel->decode_params(s->avctx,
-                                                   nal->type,
-                                                   nal->raw_data,
-                                                   nal->raw_size);
+        if (FF_HW_HAS_CB(s->avctx, decode_params)) {
+            ret = FF_HW_CALL(s->avctx, decode_params,
+                             nal->type, nal->raw_data, nal->raw_size);
             if (ret < 0)
                 goto fail;
         }
@@ -2989,11 +2984,9 @@  static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
         break;
     case HEVC_NAL_SEI_PREFIX:
     case HEVC_NAL_SEI_SUFFIX:
-        if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) {
-            ret = s->avctx->hwaccel->decode_params(s->avctx,
-                                                   nal->type,
-                                                   nal->raw_data,
-                                                   nal->raw_size);
+        if (FF_HW_HAS_CB(s->avctx, decode_params)) {
+            ret = FF_HW_CALL(s->avctx, decode_params,
+                             nal->type, nal->raw_data, nal->raw_size);
             if (ret < 0)
                 goto fail;
         }
@@ -3079,13 +3072,13 @@  static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
         }
 
         if (s->sh.first_slice_in_pic_flag && s->avctx->hwaccel) {
-            ret = s->avctx->hwaccel->start_frame(s->avctx, NULL, 0);
+            ret = FF_HW_CALL(s->avctx, start_frame, NULL, 0);
             if (ret < 0)
                 goto fail;
         }
 
         if (s->avctx->hwaccel) {
-            ret = s->avctx->hwaccel->decode_slice(s->avctx, nal->raw_data, nal->raw_size);
+            ret = FF_HW_CALL(s->avctx, decode_slice, nal->raw_data, nal->raw_size);
             if (ret < 0)
                 goto fail;
         } else {
@@ -3353,7 +3346,7 @@  static int hevc_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         return ret;
 
     if (avctx->hwaccel) {
-        if (s->ref && (ret = avctx->hwaccel->end_frame(avctx)) < 0) {
+        if (s->ref && (ret = FF_HW_SIMPLE_CALL(avctx, end_frame)) < 0) {
             av_log(avctx, AV_LOG_ERROR,
                    "hardware accelerator failed to decode picture\n");
             ff_hevc_unref_frame(s, s->ref, ~0);
@@ -3669,8 +3662,8 @@  static void hevc_decode_flush(AVCodecContext *avctx)
     s->max_ra = INT_MAX;
     s->eos = 1;
 
-    if (avctx->hwaccel && avctx->hwaccel->flush)
-        avctx->hwaccel->flush(avctx);
+    if (FF_HW_HAS_CB(avctx, flush))
+        FF_HW_SIMPLE_CALL(avctx, flush);
 }
 
 #define OFFSET(x) offsetof(HEVCContext, x)
diff --git a/libavcodec/hwaccel_internal.h b/libavcodec/hwaccel_internal.h
index 6e6f5c7cf9..edfe283150 100644
--- a/libavcodec/hwaccel_internal.h
+++ b/libavcodec/hwaccel_internal.h
@@ -23,7 +23,157 @@ 
 #ifndef AVCODEC_HWACCEL_INTERNAL_H
 #define AVCODEC_HWACCEL_INTERNAL_H
 
+#include <stdint.h>
+
+#include "avcodec.h"
+
 #define HWACCEL_CAP_ASYNC_SAFE      (1 << 0)
 #define HWACCEL_CAP_THREAD_SAFE     (1 << 1)
 
+typedef struct FFHWAccel {
+    /**
+     * The public AVHWAccel. See avcodec.h for it.
+     */
+    AVHWAccel p;
+
+    /**
+     * Allocate a custom buffer
+     */
+    int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame);
+
+    /**
+     * Called at the beginning of each frame or field picture.
+     *
+     * Meaningful frame information (codec specific) is guaranteed to
+     * be parsed at this point. This function is mandatory.
+     *
+     * Note that buf can be NULL along with buf_size set to 0.
+     * Otherwise, this means the whole frame is available at this point.
+     *
+     * @param avctx the codec context
+     * @param buf the frame data buffer base
+     * @param buf_size the size of the frame in bytes
+     * @return zero if successful, a negative value otherwise
+     */
+    int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
+
+    /**
+     * Callback for parameter data (SPS/PPS/VPS etc).
+     *
+     * Useful for hardware decoders which keep persistent state about the
+     * video parameters, and need to receive any changes to update that state.
+     *
+     * @param avctx the codec context
+     * @param type the nal unit type
+     * @param buf the nal unit data buffer
+     * @param buf_size the size of the nal unit in bytes
+     * @return zero if successful, a negative value otherwise
+     */
+    int (*decode_params)(AVCodecContext *avctx, int type, const uint8_t *buf, uint32_t buf_size);
+
+    /**
+     * Callback for each slice.
+     *
+     * Meaningful slice information (codec specific) is guaranteed to
+     * be parsed at this point. This function is mandatory.
+     *
+     * @param avctx the codec context
+     * @param buf the slice data buffer base
+     * @param buf_size the size of the slice in bytes
+     * @return zero if successful, a negative value otherwise
+     */
+    int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
+
+    /**
+     * Called at the end of each frame or field picture.
+     *
+     * The whole picture is parsed at this point and can now be sent
+     * to the hardware accelerator. This function is mandatory.
+     *
+     * @param avctx the codec context
+     * @return zero if successful, a negative value otherwise
+     */
+    int (*end_frame)(AVCodecContext *avctx);
+
+    /**
+     * Size of per-frame hardware accelerator private data.
+     *
+     * Private data is allocated with av_mallocz() before
+     * AVCodecContext.get_buffer() and deallocated after
+     * AVCodecContext.release_buffer().
+     */
+    int frame_priv_data_size;
+
+    /**
+     * Size of the private data to allocate in
+     * AVCodecInternal.hwaccel_priv_data.
+     */
+    int priv_data_size;
+
+    /**
+     * Internal hwaccel capabilities.
+     */
+    int caps_internal;
+
+    /**
+     * Initialize the hwaccel private data.
+     *
+     * This will be called from ff_get_format(), after hwaccel and
+     * hwaccel_context are set and the hwaccel private data in AVCodecInternal
+     * is allocated.
+     */
+    int (*init)(AVCodecContext *avctx);
+
+    /**
+     * Uninitialize the hwaccel private data.
+     *
+     * This will be called from get_format() or avcodec_close(), after hwaccel
+     * and hwaccel_context are already uninitialized.
+     */
+    int (*uninit)(AVCodecContext *avctx);
+
+    /**
+     * Fill the given hw_frames context with current codec parameters. Called
+     * from get_format. Refer to avcodec_get_hw_frames_parameters() for
+     * details.
+     *
+     * This CAN be called before AVHWAccel.init is called, and you must assume
+     * that avctx->hwaccel_priv_data is invalid.
+     */
+    int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx);
+
+    /**
+     * Copy necessary context variables from a previous thread context to the current one.
+     * For thread-safe hwaccels only.
+     */
+    int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src);
+
+    /**
+     * Callback to free the hwaccel-specific frame data.
+     *
+     * @param hwctx a pointer to an AVHWDeviceContext.
+     * @param data the per-frame hardware accelerator private data to be freed.
+     */
+    void (*free_frame_priv)(void *hwctx, uint8_t *data);
+
+    /**
+     * Callback to flush the hwaccel state.
+     */
+    void (*flush)(AVCodecContext *avctx);
+} FFHWAccel;
+
+static inline const FFHWAccel *ffhwaccel(const AVHWAccel *codec)
+{
+    return (const FFHWAccel*)codec;
+}
+
+#define FF_HW_CALL(avctx, function, ...) \
+        (ffhwaccel((avctx)->hwaccel)->function((avctx), __VA_ARGS__))
+
+#define FF_HW_SIMPLE_CALL(avctx, function) \
+        (ffhwaccel((avctx)->hwaccel)->function(avctx))
+
+#define FF_HW_HAS_CB(avctx, function) \
+        ((avctx)->hwaccel && ffhwaccel((avctx)->hwaccel)->function)
+
 #endif /* AVCODEC_HWACCEL_INTERNAL */
diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
index 48dfc17f72..c4630718cf 100644
--- a/libavcodec/hwaccels.h
+++ b/libavcodec/hwaccels.h
@@ -19,70 +19,68 @@ 
 #ifndef AVCODEC_HWACCELS_H
 #define AVCODEC_HWACCELS_H
 
-#include "avcodec.h"
-
-extern const AVHWAccel ff_av1_d3d11va_hwaccel;
-extern const AVHWAccel ff_av1_d3d11va2_hwaccel;
-extern const AVHWAccel ff_av1_dxva2_hwaccel;
-extern const AVHWAccel ff_av1_nvdec_hwaccel;
-extern const AVHWAccel ff_av1_vaapi_hwaccel;
-extern const AVHWAccel ff_av1_vdpau_hwaccel;
-extern const AVHWAccel ff_av1_vulkan_hwaccel;
-extern const AVHWAccel ff_h263_vaapi_hwaccel;
-extern const AVHWAccel ff_h263_videotoolbox_hwaccel;
-extern const AVHWAccel ff_h264_d3d11va_hwaccel;
-extern const AVHWAccel ff_h264_d3d11va2_hwaccel;
-extern const AVHWAccel ff_h264_dxva2_hwaccel;
-extern const AVHWAccel ff_h264_nvdec_hwaccel;
-extern const AVHWAccel ff_h264_vaapi_hwaccel;
-extern const AVHWAccel ff_h264_vdpau_hwaccel;
-extern const AVHWAccel ff_h264_videotoolbox_hwaccel;
-extern const AVHWAccel ff_h264_vulkan_hwaccel;
-extern const AVHWAccel ff_hevc_d3d11va_hwaccel;
-extern const AVHWAccel ff_hevc_d3d11va2_hwaccel;
-extern const AVHWAccel ff_hevc_dxva2_hwaccel;
-extern const AVHWAccel ff_hevc_nvdec_hwaccel;
-extern const AVHWAccel ff_hevc_vaapi_hwaccel;
-extern const AVHWAccel ff_hevc_vdpau_hwaccel;
-extern const AVHWAccel ff_hevc_videotoolbox_hwaccel;
-extern const AVHWAccel ff_hevc_vulkan_hwaccel;
-extern const AVHWAccel ff_mjpeg_nvdec_hwaccel;
-extern const AVHWAccel ff_mjpeg_vaapi_hwaccel;
-extern const AVHWAccel ff_mpeg1_nvdec_hwaccel;
-extern const AVHWAccel ff_mpeg1_vdpau_hwaccel;
-extern const AVHWAccel ff_mpeg1_videotoolbox_hwaccel;
-extern const AVHWAccel ff_mpeg2_d3d11va_hwaccel;
-extern const AVHWAccel ff_mpeg2_d3d11va2_hwaccel;
-extern const AVHWAccel ff_mpeg2_nvdec_hwaccel;
-extern const AVHWAccel ff_mpeg2_dxva2_hwaccel;
-extern const AVHWAccel ff_mpeg2_vaapi_hwaccel;
-extern const AVHWAccel ff_mpeg2_vdpau_hwaccel;
-extern const AVHWAccel ff_mpeg2_videotoolbox_hwaccel;
-extern const AVHWAccel ff_mpeg4_nvdec_hwaccel;
-extern const AVHWAccel ff_mpeg4_vaapi_hwaccel;
-extern const AVHWAccel ff_mpeg4_vdpau_hwaccel;
-extern const AVHWAccel ff_mpeg4_videotoolbox_hwaccel;
-extern const AVHWAccel ff_prores_videotoolbox_hwaccel;
-extern const AVHWAccel ff_vc1_d3d11va_hwaccel;
-extern const AVHWAccel ff_vc1_d3d11va2_hwaccel;
-extern const AVHWAccel ff_vc1_dxva2_hwaccel;
-extern const AVHWAccel ff_vc1_nvdec_hwaccel;
-extern const AVHWAccel ff_vc1_vaapi_hwaccel;
-extern const AVHWAccel ff_vc1_vdpau_hwaccel;
-extern const AVHWAccel ff_vp8_nvdec_hwaccel;
-extern const AVHWAccel ff_vp8_vaapi_hwaccel;
-extern const AVHWAccel ff_vp9_d3d11va_hwaccel;
-extern const AVHWAccel ff_vp9_d3d11va2_hwaccel;
-extern const AVHWAccel ff_vp9_dxva2_hwaccel;
-extern const AVHWAccel ff_vp9_nvdec_hwaccel;
-extern const AVHWAccel ff_vp9_vaapi_hwaccel;
-extern const AVHWAccel ff_vp9_vdpau_hwaccel;
-extern const AVHWAccel ff_vp9_videotoolbox_hwaccel;
-extern const AVHWAccel ff_wmv3_d3d11va_hwaccel;
-extern const AVHWAccel ff_wmv3_d3d11va2_hwaccel;
-extern const AVHWAccel ff_wmv3_dxva2_hwaccel;
-extern const AVHWAccel ff_wmv3_nvdec_hwaccel;
-extern const AVHWAccel ff_wmv3_vaapi_hwaccel;
-extern const AVHWAccel ff_wmv3_vdpau_hwaccel;
+extern const struct FFHWAccel ff_av1_d3d11va_hwaccel;
+extern const struct FFHWAccel ff_av1_d3d11va2_hwaccel;
+extern const struct FFHWAccel ff_av1_dxva2_hwaccel;
+extern const struct FFHWAccel ff_av1_nvdec_hwaccel;
+extern const struct FFHWAccel ff_av1_vaapi_hwaccel;
+extern const struct FFHWAccel ff_av1_vdpau_hwaccel;
+extern const struct FFHWAccel ff_av1_vulkan_hwaccel;
+extern const struct FFHWAccel ff_h263_vaapi_hwaccel;
+extern const struct FFHWAccel ff_h263_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_h264_d3d11va_hwaccel;
+extern const struct FFHWAccel ff_h264_d3d11va2_hwaccel;
+extern const struct FFHWAccel ff_h264_dxva2_hwaccel;
+extern const struct FFHWAccel ff_h264_nvdec_hwaccel;
+extern const struct FFHWAccel ff_h264_vaapi_hwaccel;
+extern const struct FFHWAccel ff_h264_vdpau_hwaccel;
+extern const struct FFHWAccel ff_h264_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_h264_vulkan_hwaccel;
+extern const struct FFHWAccel ff_hevc_d3d11va_hwaccel;
+extern const struct FFHWAccel ff_hevc_d3d11va2_hwaccel;
+extern const struct FFHWAccel ff_hevc_dxva2_hwaccel;
+extern const struct FFHWAccel ff_hevc_nvdec_hwaccel;
+extern const struct FFHWAccel ff_hevc_vaapi_hwaccel;
+extern const struct FFHWAccel ff_hevc_vdpau_hwaccel;
+extern const struct FFHWAccel ff_hevc_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_hevc_vulkan_hwaccel;
+extern const struct FFHWAccel ff_mjpeg_nvdec_hwaccel;
+extern const struct FFHWAccel ff_mjpeg_vaapi_hwaccel;
+extern const struct FFHWAccel ff_mpeg1_nvdec_hwaccel;
+extern const struct FFHWAccel ff_mpeg1_vdpau_hwaccel;
+extern const struct FFHWAccel ff_mpeg1_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_d3d11va_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_d3d11va2_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_dxva2_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_nvdec_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_vaapi_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_vdpau_hwaccel;
+extern const struct FFHWAccel ff_mpeg2_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_mpeg4_nvdec_hwaccel;
+extern const struct FFHWAccel ff_mpeg4_vaapi_hwaccel;
+extern const struct FFHWAccel ff_mpeg4_vdpau_hwaccel;
+extern const struct FFHWAccel ff_mpeg4_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_prores_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_vc1_d3d11va_hwaccel;
+extern const struct FFHWAccel ff_vc1_d3d11va2_hwaccel;
+extern const struct FFHWAccel ff_vc1_dxva2_hwaccel;
+extern const struct FFHWAccel ff_vc1_nvdec_hwaccel;
+extern const struct FFHWAccel ff_vc1_vaapi_hwaccel;
+extern const struct FFHWAccel ff_vc1_vdpau_hwaccel;
+extern const struct FFHWAccel ff_vp8_nvdec_hwaccel;
+extern const struct FFHWAccel ff_vp8_vaapi_hwaccel;
+extern const struct FFHWAccel ff_vp9_d3d11va_hwaccel;
+extern const struct FFHWAccel ff_vp9_d3d11va2_hwaccel;
+extern const struct FFHWAccel ff_vp9_dxva2_hwaccel;
+extern const struct FFHWAccel ff_vp9_nvdec_hwaccel;
+extern const struct FFHWAccel ff_vp9_vaapi_hwaccel;
+extern const struct FFHWAccel ff_vp9_vdpau_hwaccel;
+extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_wmv3_d3d11va_hwaccel;
+extern const struct FFHWAccel ff_wmv3_d3d11va2_hwaccel;
+extern const struct FFHWAccel ff_wmv3_dxva2_hwaccel;
+extern const struct FFHWAccel ff_wmv3_nvdec_hwaccel;
+extern const struct FFHWAccel ff_wmv3_vaapi_hwaccel;
+extern const struct FFHWAccel ff_wmv3_vdpau_hwaccel;
 
 #endif /* AVCODEC_HWACCELS_H */
diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h
index 3b19d5edad..e164722a94 100644
--- a/libavcodec/hwconfig.h
+++ b/libavcodec/hwconfig.h
@@ -32,7 +32,7 @@  typedef struct AVCodecHWConfigInternal {
      * If this configuration uses a hwaccel, a pointer to it.
      * If not, NULL.
      */
-    const AVHWAccel *hwaccel;
+    const struct FFHWAccel *hwaccel;
 } AVCodecHWConfigInternal;
 
 void ff_hwaccel_uninit(AVCodecContext *avctx);
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index b42e75bcdd..cef8625791 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -41,6 +41,7 @@ 
 #include "codec_internal.h"
 #include "copy_block.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "idctdsp.h"
 #include "internal.h"
@@ -796,13 +797,14 @@  int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
     }
 
     if (s->avctx->hwaccel) {
+        const FFHWAccel *hwaccel = ffhwaccel(s->avctx->hwaccel);
         s->hwaccel_picture_private =
-            av_mallocz(s->avctx->hwaccel->frame_priv_data_size);
+            av_mallocz(hwaccel->frame_priv_data_size);
         if (!s->hwaccel_picture_private)
             return AVERROR(ENOMEM);
 
-        ret = s->avctx->hwaccel->start_frame(s->avctx, s->raw_image_buffer,
-                                             s->raw_image_buffer_size);
+        ret = hwaccel->start_frame(s->avctx, s->raw_image_buffer,
+                                   s->raw_image_buffer_size);
         if (ret < 0)
             return ret;
     }
@@ -1774,9 +1776,9 @@  next_field:
         av_assert0(bytes_to_start >= 0 &&
                    s->raw_scan_buffer_size >= bytes_to_start);
 
-        ret = s->avctx->hwaccel->decode_slice(s->avctx,
-                                              s->raw_scan_buffer      + bytes_to_start,
-                                              s->raw_scan_buffer_size - bytes_to_start);
+        ret = FF_HW_CALL(s->avctx, decode_slice,
+                         s->raw_scan_buffer      + bytes_to_start,
+                         s->raw_scan_buffer_size - bytes_to_start);
         if (ret < 0)
             return ret;
 
@@ -2547,7 +2549,7 @@  eoi_parser:
                 goto the_end_no_picture;
             }
             if (s->avctx->hwaccel) {
-                ret = s->avctx->hwaccel->end_frame(s->avctx);
+                ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame);
                 if (ret < 0)
                     return ret;
 
diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index 3737d77eca..e645b8e24a 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -42,6 +42,7 @@ 
 #include "codec_internal.h"
 #include "decode.h"
 #include "error_resilience.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "idctdsp.h"
 #include "internal.h"
@@ -1656,7 +1657,7 @@  static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
         }
 
         if (s->avctx->hwaccel) {
-            if ((ret = s->avctx->hwaccel->end_frame(s->avctx)) < 0) {
+            if ((ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame)) < 0) {
                 av_log(avctx, AV_LOG_ERROR,
                        "hardware accelerator failed to decode first field\n");
                 return ret;
@@ -1672,7 +1673,7 @@  static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
     }
 
     if (avctx->hwaccel) {
-        if ((ret = avctx->hwaccel->start_frame(avctx, buf, buf_size)) < 0)
+        if ((ret = FF_HW_CALL(avctx, start_frame, buf, buf_size)) < 0)
             return ret;
     }
 
@@ -1757,7 +1758,7 @@  static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
         if (buf_end < *buf + buf_size)
             buf_end -= 4;
         s->mb_y = mb_y;
-        if (avctx->hwaccel->decode_slice(avctx, buf_start, buf_end - buf_start) < 0)
+        if (FF_HW_CALL(avctx, decode_slice, buf_start, buf_end - buf_start) < 0)
             return DECODE_SLICE_ERROR;
         *buf = buf_end;
         return DECODE_SLICE_OK;
@@ -2026,7 +2027,7 @@  static int slice_end(AVCodecContext *avctx, AVFrame *pict)
         return 0;
 
     if (s->avctx->hwaccel) {
-        int ret = s->avctx->hwaccel->end_frame(s->avctx);
+        int ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame);
         if (ret < 0) {
             av_log(avctx, AV_LOG_ERROR,
                    "hardware accelerator failed to decode picture\n");
diff --git a/libavcodec/nvdec_av1.c b/libavcodec/nvdec_av1.c
index 3bbcd76123..74b0442177 100644
--- a/libavcodec/nvdec_av1.c
+++ b/libavcodec/nvdec_av1.c
@@ -23,6 +23,7 @@ 
 #include "avcodec.h"
 #include "nvdec.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "av1dec.h"
 
@@ -337,11 +338,11 @@  static int nvdec_av1_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_
     return ff_nvdec_frame_params(avctx, hw_frames_ctx, 8 * 2, 0);
 }
 
-const AVHWAccel ff_av1_nvdec_hwaccel = {
-    .name                 = "av1_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_AV1,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_av1_nvdec_hwaccel = {
+    .p.name               = "av1_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_AV1,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_av1_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = nvdec_av1_decode_slice,
diff --git a/libavcodec/nvdec_h264.c b/libavcodec/nvdec_h264.c
index 116bd4fb5d..f022619b64 100644
--- a/libavcodec/nvdec_h264.c
+++ b/libavcodec/nvdec_h264.c
@@ -28,6 +28,7 @@ 
 #include "decode.h"
 #include "internal.h"
 #include "h264dec.h"
+#include "hwaccel_internal.h"
 
 static void dpb_add(const H264Context *h, CUVIDH264DPBENTRY *dst, const H264Picture *src,
                     int frame_idx)
@@ -169,11 +170,11 @@  static int nvdec_h264_frame_params(AVCodecContext *avctx,
     return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->ref_frame_count + sps->num_reorder_frames, 0);
 }
 
-const AVHWAccel ff_h264_nvdec_hwaccel = {
-    .name                 = "h264_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_H264,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_h264_nvdec_hwaccel = {
+    .p.name               = "h264_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_H264,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_h264_start_frame,
     .end_frame            = ff_nvdec_end_frame,
     .decode_slice         = nvdec_h264_decode_slice,
diff --git a/libavcodec/nvdec_hevc.c b/libavcodec/nvdec_hevc.c
index cd549d2ef6..91fb9f5384 100644
--- a/libavcodec/nvdec_hevc.c
+++ b/libavcodec/nvdec_hevc.c
@@ -29,6 +29,7 @@ 
 #include "internal.h"
 #include "hevcdec.h"
 #include "hevc_data.h"
+#include "hwaccel_internal.h"
 
 static void dpb_add(CUVIDHEVCPICPARAMS *pp, int idx, const HEVCFrame *src)
 {
@@ -308,11 +309,11 @@  static int nvdec_hevc_decode_init(AVCodecContext *avctx) {
     return ff_nvdec_decode_init(avctx);
 }
 
-const AVHWAccel ff_hevc_nvdec_hwaccel = {
-    .name                 = "hevc_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_HEVC,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_hevc_nvdec_hwaccel = {
+    .p.name               = "hevc_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_HEVC,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_hevc_start_frame,
     .end_frame            = ff_nvdec_end_frame,
     .decode_slice         = nvdec_hevc_decode_slice,
diff --git a/libavcodec/nvdec_mjpeg.c b/libavcodec/nvdec_mjpeg.c
index daaf0072ed..850634bf1a 100644
--- a/libavcodec/nvdec_mjpeg.c
+++ b/libavcodec/nvdec_mjpeg.c
@@ -25,6 +25,7 @@ 
 #include "mjpegdec.h"
 #include "nvdec.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 
 static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
 {
@@ -69,11 +70,11 @@  static int nvdec_mjpeg_frame_params(AVCodecContext *avctx,
     return ff_nvdec_frame_params(avctx, hw_frames_ctx, 1, 0);
 }
 
-const AVHWAccel ff_mjpeg_nvdec_hwaccel = {
-    .name                 = "mjpeg_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_MJPEG,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_mjpeg_nvdec_hwaccel = {
+    .p.name               = "mjpeg_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_MJPEG,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_mjpeg_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = nvdec_mjpeg_decode_slice,
diff --git a/libavcodec/nvdec_mpeg12.c b/libavcodec/nvdec_mpeg12.c
index 3b9ff60734..a4603c7ea7 100644
--- a/libavcodec/nvdec_mpeg12.c
+++ b/libavcodec/nvdec_mpeg12.c
@@ -23,6 +23,7 @@ 
 #include "config_components.h"
 
 #include "avcodec.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "mpegvideo.h"
 #include "nvdec.h"
@@ -99,11 +100,11 @@  static int nvdec_mpeg12_frame_params(AVCodecContext *avctx,
 }
 
 #if CONFIG_MPEG2_NVDEC_HWACCEL
-const AVHWAccel ff_mpeg2_nvdec_hwaccel = {
-    .name                 = "mpeg2_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_MPEG2VIDEO,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_mpeg2_nvdec_hwaccel = {
+    .p.name               = "mpeg2_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_mpeg12_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = ff_nvdec_simple_decode_slice,
@@ -115,11 +116,11 @@  const AVHWAccel ff_mpeg2_nvdec_hwaccel = {
 #endif
 
 #if CONFIG_MPEG1_NVDEC_HWACCEL
-const AVHWAccel ff_mpeg1_nvdec_hwaccel = {
-    .name                 = "mpeg1_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_MPEG1VIDEO,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_mpeg1_nvdec_hwaccel = {
+    .p.name               = "mpeg1_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_MPEG1VIDEO,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_mpeg12_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = ff_nvdec_simple_decode_slice,
diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c
index c193f6b6e4..20a0499437 100644
--- a/libavcodec/nvdec_mpeg4.c
+++ b/libavcodec/nvdec_mpeg4.c
@@ -26,6 +26,7 @@ 
 #include "mpeg4videodefs.h"
 #include "nvdec.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 
 static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
 {
@@ -109,11 +110,11 @@  static int nvdec_mpeg4_frame_params(AVCodecContext *avctx,
     return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2, 0);
 }
 
-const AVHWAccel ff_mpeg4_nvdec_hwaccel = {
-    .name                 = "mpeg4_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_MPEG4,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_mpeg4_nvdec_hwaccel = {
+    .p.name               = "mpeg4_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_MPEG4,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_mpeg4_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = nvdec_mpeg4_decode_slice,
diff --git a/libavcodec/nvdec_vc1.c b/libavcodec/nvdec_vc1.c
index fae1cb0ab2..5096d784df 100644
--- a/libavcodec/nvdec_vc1.c
+++ b/libavcodec/nvdec_vc1.c
@@ -23,6 +23,7 @@ 
 #include "config_components.h"
 
 #include "avcodec.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "nvdec.h"
 #include "decode.h"
@@ -113,11 +114,11 @@  static int nvdec_vc1_frame_params(AVCodecContext *avctx,
     return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2, 0);
 }
 
-const AVHWAccel ff_vc1_nvdec_hwaccel = {
-    .name                 = "vc1_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_VC1,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_vc1_nvdec_hwaccel = {
+    .p.name               = "vc1_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_VC1,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_vc1_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = ff_nvdec_simple_decode_slice,
@@ -128,11 +129,11 @@  const AVHWAccel ff_vc1_nvdec_hwaccel = {
 };
 
 #if CONFIG_WMV3_NVDEC_HWACCEL
-const AVHWAccel ff_wmv3_nvdec_hwaccel = {
-    .name                 = "wmv3_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_WMV3,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_wmv3_nvdec_hwaccel = {
+    .p.name               = "wmv3_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_WMV3,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_vc1_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = ff_nvdec_simple_decode_slice,
diff --git a/libavcodec/nvdec_vp8.c b/libavcodec/nvdec_vp8.c
index 3812ef3e1a..ff3b3f259c 100644
--- a/libavcodec/nvdec_vp8.c
+++ b/libavcodec/nvdec_vp8.c
@@ -23,6 +23,7 @@ 
 #include "avcodec.h"
 #include "nvdec.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "vp8.h"
 
@@ -90,11 +91,11 @@  static int nvdec_vp8_frame_params(AVCodecContext *avctx,
     return ff_nvdec_frame_params(avctx, hw_frames_ctx, 3, 0);
 }
 
-const AVHWAccel ff_vp8_nvdec_hwaccel = {
-    .name                 = "vp8_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_VP8,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_vp8_nvdec_hwaccel = {
+    .p.name               = "vp8_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_VP8,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_vp8_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = ff_nvdec_simple_decode_slice,
diff --git a/libavcodec/nvdec_vp9.c b/libavcodec/nvdec_vp9.c
index a76bcf9943..e196391c6d 100644
--- a/libavcodec/nvdec_vp9.c
+++ b/libavcodec/nvdec_vp9.c
@@ -25,6 +25,7 @@ 
 #include "avcodec.h"
 #include "nvdec.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "vp9shared.h"
 
@@ -169,11 +170,11 @@  static int nvdec_vp9_frame_params(AVCodecContext *avctx,
     return ff_nvdec_frame_params(avctx, hw_frames_ctx, 8, 0);
 }
 
-const AVHWAccel ff_vp9_nvdec_hwaccel = {
-    .name                 = "vp9_nvdec",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_VP9,
-    .pix_fmt              = AV_PIX_FMT_CUDA,
+const FFHWAccel ff_vp9_nvdec_hwaccel = {
+    .p.name               = "vp9_nvdec",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_VP9,
+    .p.pix_fmt            = AV_PIX_FMT_CUDA,
     .start_frame          = nvdec_vp9_start_frame,
     .end_frame            = ff_nvdec_simple_end_frame,
     .decode_slice         = ff_nvdec_simple_decode_slice,
diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c
index b86614adc0..ae5838eca4 100644
--- a/libavcodec/proresdec2.c
+++ b/libavcodec/proresdec2.c
@@ -37,6 +37,7 @@ 
 #include "codec_internal.h"
 #include "decode.h"
 #include "get_bits.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "idctdsp.h"
 #include "profiles.h"
@@ -804,13 +805,14 @@  static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
     ff_thread_finish_setup(avctx);
 
     if (avctx->hwaccel) {
-        ret = avctx->hwaccel->start_frame(avctx, NULL, 0);
+        const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
+        ret = hwaccel->start_frame(avctx, NULL, 0);
         if (ret < 0)
             return ret;
-        ret = avctx->hwaccel->decode_slice(avctx, avpkt->data, avpkt->size);
+        ret = hwaccel->decode_slice(avctx, avpkt->data, avpkt->size);
         if (ret < 0)
             return ret;
-        ret = avctx->hwaccel->end_frame(avctx);
+        ret = hwaccel->end_frame(avctx);
         if (ret < 0)
             return ret;
         goto finish;
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index c14010d803..6b792bfc39 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -151,7 +151,7 @@  typedef struct FrameThreadContext {
 
 static int hwaccel_serial(const AVCodecContext *avctx)
 {
-    return avctx->hwaccel && !(avctx->hwaccel->caps_internal & HWACCEL_CAP_THREAD_SAFE);
+    return avctx->hwaccel && !(ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE);
 }
 
 static void async_lock(FrameThreadContext *fctx)
@@ -246,7 +246,7 @@  static attribute_align_arg void *frame_worker_thread(void *arg)
             pthread_mutex_unlock(&p->parent->hwaccel_mutex);
         }
         av_assert0(!avctx->hwaccel ||
-                   (avctx->hwaccel->caps_internal & HWACCEL_CAP_THREAD_SAFE));
+                   (ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE));
 
         if (p->async_serializing) {
             p->async_serializing = 0;
@@ -368,12 +368,13 @@  FF_ENABLE_DEPRECATION_WARNINGS
 
         // propagate hwaccel state for threadsafe hwaccels
         if (p_src->hwaccel_threadsafe) {
+            const FFHWAccel *hwaccel = ffhwaccel(src->hwaccel);
             if (!dst->hwaccel) {
-                if (src->hwaccel->priv_data_size) {
-                    av_assert0(src->hwaccel->update_thread_context);
+                if (hwaccel->priv_data_size) {
+                    av_assert0(hwaccel->update_thread_context);
 
                     dst->internal->hwaccel_priv_data =
-                            av_mallocz(src->hwaccel->priv_data_size);
+                            av_mallocz(hwaccel->priv_data_size);
                     if (!dst->internal->hwaccel_priv_data)
                         return AVERROR(ENOMEM);
                 }
@@ -381,8 +382,8 @@  FF_ENABLE_DEPRECATION_WARNINGS
             }
             av_assert0(dst->hwaccel == src->hwaccel);
 
-            if (src->hwaccel->update_thread_context) {
-                err = src->hwaccel->update_thread_context(dst, src);
+            if (hwaccel->update_thread_context) {
+                err = hwaccel->update_thread_context(dst, src);
                 if (err < 0) {
                     av_log(dst, AV_LOG_ERROR, "Error propagating hwaccel state\n");
                     ff_hwaccel_uninit(dst);
@@ -658,7 +659,7 @@  void ff_thread_finish_setup(AVCodecContext *avctx) {
     if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return;
 
     p->hwaccel_threadsafe = avctx->hwaccel &&
-                            (avctx->hwaccel->caps_internal & HWACCEL_CAP_THREAD_SAFE);
+                            (ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE);
 
     if (hwaccel_serial(avctx) && !p->hwaccel_serializing) {
         pthread_mutex_lock(&p->parent->hwaccel_mutex);
@@ -667,7 +668,7 @@  void ff_thread_finish_setup(AVCodecContext *avctx) {
 
     /* this assumes that no hwaccel calls happen before ff_thread_finish_setup() */
     if (avctx->hwaccel &&
-        !(avctx->hwaccel->caps_internal & HWACCEL_CAP_ASYNC_SAFE)) {
+        !(ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_ASYNC_SAFE)) {
         p->async_serializing = 1;
 
         async_lock(p->parent);
diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c
index 67ea6af697..85b508438e 100644
--- a/libavcodec/vaapi_av1.c
+++ b/libavcodec/vaapi_av1.c
@@ -433,11 +433,11 @@  static int vaapi_av1_decode_slice(AVCodecContext *avctx,
     return 0;
 }
 
-const AVHWAccel ff_av1_vaapi_hwaccel = {
-    .name                 = "av1_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_AV1,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_av1_vaapi_hwaccel = {
+    .p.name               = "av1_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_AV1,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = vaapi_av1_start_frame,
     .end_frame            = vaapi_av1_end_frame,
     .decode_slice         = vaapi_av1_decode_slice,
diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c
index e7f8e920b2..55cf5a05ee 100644
--- a/libavcodec/vaapi_h264.c
+++ b/libavcodec/vaapi_h264.c
@@ -385,11 +385,11 @@  static int vaapi_h264_decode_slice(AVCodecContext *avctx,
     return 0;
 }
 
-const AVHWAccel ff_h264_vaapi_hwaccel = {
-    .name                 = "h264_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_H264,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_h264_vaapi_hwaccel = {
+    .p.name               = "h264_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_H264,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_h264_start_frame,
     .end_frame            = &vaapi_h264_end_frame,
     .decode_slice         = &vaapi_h264_decode_slice,
diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c
index 87584d1edb..d464fda18c 100644
--- a/libavcodec/vaapi_hevc.c
+++ b/libavcodec/vaapi_hevc.c
@@ -654,11 +654,11 @@  end:
         return VAProfileNone;
 }
 
-const AVHWAccel ff_hevc_vaapi_hwaccel = {
-    .name                 = "hevc_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_HEVC,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_hevc_vaapi_hwaccel = {
+    .p.name               = "hevc_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_HEVC,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = vaapi_hevc_start_frame,
     .end_frame            = vaapi_hevc_end_frame,
     .decode_slice         = vaapi_hevc_decode_slice,
diff --git a/libavcodec/vaapi_mjpeg.c b/libavcodec/vaapi_mjpeg.c
index 1947540ea1..5b8d47bb2a 100644
--- a/libavcodec/vaapi_mjpeg.c
+++ b/libavcodec/vaapi_mjpeg.c
@@ -142,11 +142,11 @@  fail:
     return err;
 }
 
-const AVHWAccel ff_mjpeg_vaapi_hwaccel = {
-    .name                 = "mjpeg_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_MJPEG,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_mjpeg_vaapi_hwaccel = {
+    .p.name               = "mjpeg_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_MJPEG,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_mjpeg_start_frame,
     .end_frame            = &vaapi_mjpeg_end_frame,
     .decode_slice         = &vaapi_mjpeg_decode_slice,
diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c
index 09636e0d26..eeb4e87321 100644
--- a/libavcodec/vaapi_mpeg2.c
+++ b/libavcodec/vaapi_mpeg2.c
@@ -172,11 +172,11 @@  static int vaapi_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer
     return 0;
 }
 
-const AVHWAccel ff_mpeg2_vaapi_hwaccel = {
-    .name                 = "mpeg2_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_MPEG2VIDEO,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_mpeg2_vaapi_hwaccel = {
+    .p.name               = "mpeg2_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_mpeg2_start_frame,
     .end_frame            = &vaapi_mpeg2_end_frame,
     .decode_slice         = &vaapi_mpeg2_decode_slice,
diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c
index ff31ca4d92..363b686e42 100644
--- a/libavcodec/vaapi_mpeg4.c
+++ b/libavcodec/vaapi_mpeg4.c
@@ -180,11 +180,11 @@  static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer
 }
 
 #if CONFIG_MPEG4_VAAPI_HWACCEL
-const AVHWAccel ff_mpeg4_vaapi_hwaccel = {
-    .name                 = "mpeg4_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_MPEG4,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_mpeg4_vaapi_hwaccel = {
+    .p.name               = "mpeg4_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_MPEG4,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_mpeg4_start_frame,
     .end_frame            = &vaapi_mpeg4_end_frame,
     .decode_slice         = &vaapi_mpeg4_decode_slice,
@@ -198,11 +198,11 @@  const AVHWAccel ff_mpeg4_vaapi_hwaccel = {
 #endif
 
 #if CONFIG_H263_VAAPI_HWACCEL
-const AVHWAccel ff_h263_vaapi_hwaccel = {
-    .name                 = "h263_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_H263,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_h263_vaapi_hwaccel = {
+    .p.name               = "h263_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_H263,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_mpeg4_start_frame,
     .end_frame            = &vaapi_mpeg4_end_frame,
     .decode_slice         = &vaapi_mpeg4_decode_slice,
diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c
index a179e4df11..09a5c852fc 100644
--- a/libavcodec/vaapi_vc1.c
+++ b/libavcodec/vaapi_vc1.c
@@ -500,11 +500,11 @@  static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer,
 }
 
 #if CONFIG_WMV3_VAAPI_HWACCEL
-const AVHWAccel ff_wmv3_vaapi_hwaccel = {
-    .name                 = "wmv3_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_WMV3,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_wmv3_vaapi_hwaccel = {
+    .p.name               = "wmv3_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_WMV3,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_vc1_start_frame,
     .end_frame            = &vaapi_vc1_end_frame,
     .decode_slice         = &vaapi_vc1_decode_slice,
@@ -517,11 +517,11 @@  const AVHWAccel ff_wmv3_vaapi_hwaccel = {
 };
 #endif
 
-const AVHWAccel ff_vc1_vaapi_hwaccel = {
-    .name                 = "vc1_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_VC1,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_vc1_vaapi_hwaccel = {
+    .p.name               = "vc1_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_VC1,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_vc1_start_frame,
     .end_frame            = &vaapi_vc1_end_frame,
     .decode_slice         = &vaapi_vc1_decode_slice,
diff --git a/libavcodec/vaapi_vp8.c b/libavcodec/vaapi_vp8.c
index f833133f9f..31137a45bd 100644
--- a/libavcodec/vaapi_vp8.c
+++ b/libavcodec/vaapi_vp8.c
@@ -220,11 +220,11 @@  fail:
     return err;
 }
 
-const AVHWAccel ff_vp8_vaapi_hwaccel = {
-    .name                 = "vp8_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_VP8,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_vp8_vaapi_hwaccel = {
+    .p.name               = "vp8_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_VP8,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = &vaapi_vp8_start_frame,
     .end_frame            = &vaapi_vp8_end_frame,
     .decode_slice         = &vaapi_vp8_decode_slice,
diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c
index cf735bb7b2..9dc7d5e72b 100644
--- a/libavcodec/vaapi_vp9.c
+++ b/libavcodec/vaapi_vp9.c
@@ -168,11 +168,11 @@  static int vaapi_vp9_decode_slice(AVCodecContext *avctx,
     return 0;
 }
 
-const AVHWAccel ff_vp9_vaapi_hwaccel = {
-    .name                 = "vp9_vaapi",
-    .type                 = AVMEDIA_TYPE_VIDEO,
-    .id                   = AV_CODEC_ID_VP9,
-    .pix_fmt              = AV_PIX_FMT_VAAPI,
+const FFHWAccel ff_vp9_vaapi_hwaccel = {
+    .p.name               = "vp9_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_VP9,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
     .start_frame          = vaapi_vp9_start_frame,
     .end_frame            = vaapi_vp9_end_frame,
     .decode_slice         = vaapi_vp9_decode_slice,
diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c
index 9e343d003f..a2a0e8f56f 100644
--- a/libavcodec/vc1dec.c
+++ b/libavcodec/vc1dec.c
@@ -34,6 +34,7 @@ 
 #include "decode.h"
 #include "get_bits.h"
 #include "h263dec.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "mpeg_er.h"
 #include "mpegvideo.h"
@@ -1096,19 +1097,26 @@  static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict,
     }
 
     if (avctx->hwaccel) {
+        const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
         s->mb_y = 0;
         if (v->field_mode && buf_start_second_field) {
             // decode first field
             s->picture_structure = PICT_BOTTOM_FIELD - v->tff;
-            if ((ret = avctx->hwaccel->start_frame(avctx, buf_start, buf_start_second_field - buf_start)) < 0)
+            ret = hwaccel->start_frame(avctx, buf_start,
+                                       buf_start_second_field - buf_start);
+            if (ret < 0)
                 goto err;
 
             if (n_slices1 == -1) {
                 // no slices, decode the field as-is
-                if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start, buf_start_second_field - buf_start)) < 0)
+                ret = hwaccel->decode_slice(avctx, buf_start,
+                                            buf_start_second_field - buf_start);
+                if (ret < 0)
                     goto err;
             } else {
-                if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start, slices[0].rawbuf - buf_start)) < 0)
+                ret = hwaccel->decode_slice(avctx, buf_start,
+                                            slices[0].rawbuf - buf_start);
+                if (ret < 0)
                     goto err;
 
                 for (i = 0 ; i < n_slices1 + 1; i++) {
@@ -1126,12 +1134,14 @@  static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict,
                         }
                     }
 
-                    if ((ret = avctx->hwaccel->decode_slice(avctx, slices[i].rawbuf, slices[i].raw_size)) < 0)
+                    ret = hwaccel->decode_slice(avctx, slices[i].rawbuf,
+                                                       slices[i].raw_size);
+                    if (ret < 0)
                         goto err;
                 }
             }
 
-            if ((ret = avctx->hwaccel->end_frame(avctx)) < 0)
+            if ((ret = hwaccel->end_frame(avctx)) < 0)
                 goto err;
 
             // decode second field
@@ -1147,15 +1157,21 @@  static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict,
             }
             v->s.current_picture_ptr->f->pict_type = v->s.pict_type;
 
-            if ((ret = avctx->hwaccel->start_frame(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field)) < 0)
+            ret = hwaccel->start_frame(avctx, buf_start_second_field,
+                                       (buf + buf_size) - buf_start_second_field);
+            if (ret < 0)
                 goto err;
 
             if (n_slices - n_slices1 == 2) {
                 // no slices, decode the field as-is
-                if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field)) < 0)
+                ret = hwaccel->decode_slice(avctx, buf_start_second_field,
+                                            (buf + buf_size) - buf_start_second_field);
+                if (ret < 0)
                     goto err;
             } else {
-                if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start_second_field, slices[n_slices1 + 2].rawbuf - buf_start_second_field)) < 0)
+                ret = hwaccel->decode_slice(avctx, buf_start_second_field,
+                                            slices[n_slices1 + 2].rawbuf - buf_start_second_field);
+                if (ret < 0)
                     goto err;
 
                 for (i = n_slices1 + 2; i < n_slices; i++) {
@@ -1173,25 +1189,33 @@  static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict,
                         }
                     }
 
-                    if ((ret = avctx->hwaccel->decode_slice(avctx, slices[i].rawbuf, slices[i].raw_size)) < 0)
+                    ret = hwaccel->decode_slice(avctx, slices[i].rawbuf,
+                                                slices[i].raw_size);
+                    if (ret < 0)
                         goto err;
                 }
             }
 
-            if ((ret = avctx->hwaccel->end_frame(avctx)) < 0)
+            if ((ret = hwaccel->end_frame(avctx)) < 0)
                 goto err;
         } else {
             s->picture_structure = PICT_FRAME;
-            if ((ret = avctx->hwaccel->start_frame(avctx, buf_start, (buf + buf_size) - buf_start)) < 0)
+            ret = hwaccel->start_frame(avctx, buf_start,
+                                       (buf + buf_size) - buf_start);
+            if (ret < 0)
                 goto err;
 
             if (n_slices == 0) {
                 // no slices, decode the frame as-is
-                if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start, (buf + buf_size) - buf_start)) < 0)
+                ret = hwaccel->decode_slice(avctx, buf_start,
+                                            (buf + buf_size) - buf_start);
+                if (ret < 0)
                     goto err;
             } else {
                 // decode the frame part as the first slice
-                if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start, slices[0].rawbuf - buf_start)) < 0)
+                ret = hwaccel->decode_slice(avctx, buf_start,
+                                            slices[0].rawbuf - buf_start);
+                if (ret < 0)
                     goto err;
 
                 // and process the slices as additional slices afterwards
@@ -1210,11 +1234,13 @@  static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict,
                         }
                     }
 
-                    if ((ret = avctx->hwaccel->decode_slice(avctx, slices[i].rawbuf, slices[i].raw_size)) < 0)
+                    ret = hwaccel->decode_slice(avctx, slices[i].rawbuf,
+                                                       slices[i].raw_size);
+                    if (ret < 0)
                         goto err;
                 }
             }
-            if ((ret = avctx->hwaccel->end_frame(avctx)) < 0)
+            if ((ret = hwaccel->end_frame(avctx)) < 0)
                 goto err;
         }
     } else {
diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c
index 0bb793c010..2b9b78d8d0 100644
--- a/libavcodec/vdpau.c
+++ b/libavcodec/vdpau.c
@@ -27,6 +27,7 @@ 
 
 #include "avcodec.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "mpegvideodec.h"
 #include "vc1.h"
@@ -324,8 +325,8 @@  static int ff_vdpau_common_reinit(AVCodecContext *avctx)
         avctx->coded_height == vdctx->height && (!hwctx || !hwctx->reset))
         return 0;
 
-    avctx->hwaccel->uninit(avctx);
-    return avctx->hwaccel->init(avctx);
+    FF_HW_SIMPLE_CALL(avctx, uninit);
+    return FF_HW_SIMPLE_CALL(avctx, init);
 }
 
 int ff_vdpau_common_start_frame(struct vdpau_picture_context *pic_ctx,
diff --git a/libavcodec/vdpau_av1.c b/libavcodec/vdpau_av1.c
index 557cbcebd7..0ae62301cb 100644
--- a/libavcodec/vdpau_av1.c
+++ b/libavcodec/vdpau_av1.c
@@ -353,11 +353,11 @@  static int vdpau_av1_init(AVCodecContext *avctx)
     return ff_vdpau_common_init(avctx, profile, level);
 }
 
-const AVHWAccel ff_av1_vdpau_hwaccel = {
-    .name           = "av1_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_AV1,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_av1_vdpau_hwaccel = {
+    .p.name         = "av1_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_AV1,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_av1_start_frame,
     .end_frame      = vdpau_av1_end_frame,
     .decode_slice   = vdpau_av1_decode_slice,
diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c
index 1c5622662b..8694292fe3 100644
--- a/libavcodec/vdpau_h264.c
+++ b/libavcodec/vdpau_h264.c
@@ -261,11 +261,11 @@  static int vdpau_h264_init(AVCodecContext *avctx)
     return ff_vdpau_common_init(avctx, profile, level);
 }
 
-const AVHWAccel ff_h264_vdpau_hwaccel = {
-    .name           = "h264_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_H264,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_h264_vdpau_hwaccel = {
+    .p.name         = "h264_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_H264,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_h264_start_frame,
     .end_frame      = vdpau_h264_end_frame,
     .decode_slice   = vdpau_h264_decode_slice,
diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c
index fb1b71abdc..fea98805d5 100644
--- a/libavcodec/vdpau_hevc.c
+++ b/libavcodec/vdpau_hevc.c
@@ -540,11 +540,11 @@  static int vdpau_hevc_init(AVCodecContext *avctx)
     return ff_vdpau_common_init(avctx, profile, level);
 }
 
-const AVHWAccel ff_hevc_vdpau_hwaccel = {
-    .name           = "hevc_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_HEVC,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_hevc_vdpau_hwaccel = {
+    .p.name         = "hevc_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_HEVC,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_hevc_start_frame,
     .end_frame      = vdpau_hevc_end_frame,
     .decode_slice   = vdpau_hevc_decode_slice,
diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c
index d7223cdb4a..a5f21ca3a5 100644
--- a/libavcodec/vdpau_mpeg12.c
+++ b/libavcodec/vdpau_mpeg12.c
@@ -106,11 +106,11 @@  static int vdpau_mpeg1_init(AVCodecContext *avctx)
                                 VDP_DECODER_LEVEL_MPEG1_NA);
 }
 
-const AVHWAccel ff_mpeg1_vdpau_hwaccel = {
-    .name           = "mpeg1_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG1VIDEO,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_mpeg1_vdpau_hwaccel = {
+    .p.name         = "mpeg1_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG1VIDEO,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_mpeg_start_frame,
     .end_frame      = ff_vdpau_mpeg_end_frame,
     .decode_slice   = vdpau_mpeg_decode_slice,
@@ -141,11 +141,11 @@  static int vdpau_mpeg2_init(AVCodecContext *avctx)
     return ff_vdpau_common_init(avctx, profile, VDP_DECODER_LEVEL_MPEG2_HL);
 }
 
-const AVHWAccel ff_mpeg2_vdpau_hwaccel = {
-    .name           = "mpeg2_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG2VIDEO,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_mpeg2_vdpau_hwaccel = {
+    .p.name         = "mpeg2_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_mpeg_start_frame,
     .end_frame      = ff_vdpau_mpeg_end_frame,
     .decode_slice   = vdpau_mpeg_decode_slice,
diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c
index ce6d421196..0c3852efdf 100644
--- a/libavcodec/vdpau_mpeg4.c
+++ b/libavcodec/vdpau_mpeg4.c
@@ -111,11 +111,11 @@  static int vdpau_mpeg4_init(AVCodecContext *avctx)
     return ff_vdpau_common_init(avctx, profile, avctx->level);
 }
 
-const AVHWAccel ff_mpeg4_vdpau_hwaccel = {
-    .name           = "mpeg4_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG4,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_mpeg4_vdpau_hwaccel = {
+    .p.name         = "mpeg4_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG4,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_mpeg4_start_frame,
     .end_frame      = ff_vdpau_mpeg_end_frame,
     .decode_slice   = vdpau_mpeg4_decode_slice,
diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c
index 851a89d7cf..a7ab36e431 100644
--- a/libavcodec/vdpau_vc1.c
+++ b/libavcodec/vdpau_vc1.c
@@ -138,11 +138,11 @@  static int vdpau_vc1_init(AVCodecContext *avctx)
 }
 
 #if CONFIG_WMV3_VDPAU_HWACCEL
-const AVHWAccel ff_wmv3_vdpau_hwaccel = {
-    .name           = "wm3_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_WMV3,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_wmv3_vdpau_hwaccel = {
+    .p.name         = "wm3_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_WMV3,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_vc1_start_frame,
     .end_frame      = ff_vdpau_mpeg_end_frame,
     .decode_slice   = vdpau_vc1_decode_slice,
@@ -155,11 +155,11 @@  const AVHWAccel ff_wmv3_vdpau_hwaccel = {
 };
 #endif
 
-const AVHWAccel ff_vc1_vdpau_hwaccel = {
-    .name           = "vc1_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VC1,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_vc1_vdpau_hwaccel = {
+    .p.name         = "vc1_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VC1,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_vc1_start_frame,
     .end_frame      = ff_vdpau_mpeg_end_frame,
     .decode_slice   = vdpau_vc1_decode_slice,
diff --git a/libavcodec/vdpau_vp9.c b/libavcodec/vdpau_vp9.c
index 1e6a1fc007..fa55101536 100644
--- a/libavcodec/vdpau_vp9.c
+++ b/libavcodec/vdpau_vp9.c
@@ -222,11 +222,11 @@  static int vdpau_vp9_init(AVCodecContext *avctx)
     return ff_vdpau_common_init(avctx, profile, level);
 }
 
-const AVHWAccel ff_vp9_vdpau_hwaccel = {
-    .name           = "vp9_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VP9,
-    .pix_fmt        = AV_PIX_FMT_VDPAU,
+const FFHWAccel ff_vp9_vdpau_hwaccel = {
+    .p.name         = "vp9_vdpau",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VP9,
+    .p.pix_fmt      = AV_PIX_FMT_VDPAU,
     .start_frame    = vdpau_vp9_start_frame,
     .end_frame      = vdpau_vp9_end_frame,
     .decode_slice   = vdpau_vp9_decode_slice,
diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c
index 6444325591..963379d483 100644
--- a/libavcodec/videotoolbox.c
+++ b/libavcodec/videotoolbox.c
@@ -33,6 +33,7 @@ 
 #include "internal.h"
 #include "h264dec.h"
 #include "hevcdec.h"
+#include "hwaccel_internal.h"
 #include "mpegvideo.h"
 #include "proresdec.h"
 #include <Availability.h>
@@ -1284,11 +1285,11 @@  int ff_videotoolbox_frame_params(AVCodecContext *avctx,
     return 0;
 }
 
-const AVHWAccel ff_h263_videotoolbox_hwaccel = {
-    .name           = "h263_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_H263,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_h263_videotoolbox_hwaccel = {
+    .p.name         = "h263_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_H263,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = videotoolbox_mpeg_start_frame,
     .decode_slice   = videotoolbox_mpeg_decode_slice,
@@ -1299,11 +1300,11 @@  const AVHWAccel ff_h263_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };
 
-const AVHWAccel ff_hevc_videotoolbox_hwaccel = {
-    .name           = "hevc_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_HEVC,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_hevc_videotoolbox_hwaccel = {
+    .p.name         = "hevc_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_HEVC,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = videotoolbox_hevc_start_frame,
     .decode_slice   = videotoolbox_hevc_decode_slice,
@@ -1315,11 +1316,11 @@  const AVHWAccel ff_hevc_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };
 
-const AVHWAccel ff_h264_videotoolbox_hwaccel = {
-    .name           = "h264_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_H264,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_h264_videotoolbox_hwaccel = {
+    .p.name         = "h264_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_H264,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = ff_videotoolbox_h264_start_frame,
     .decode_slice   = ff_videotoolbox_h264_decode_slice,
@@ -1331,11 +1332,11 @@  const AVHWAccel ff_h264_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };
 
-const AVHWAccel ff_mpeg1_videotoolbox_hwaccel = {
-    .name           = "mpeg1_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG1VIDEO,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_mpeg1_videotoolbox_hwaccel = {
+    .p.name         = "mpeg1_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG1VIDEO,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = videotoolbox_mpeg_start_frame,
     .decode_slice   = videotoolbox_mpeg_decode_slice,
@@ -1346,11 +1347,11 @@  const AVHWAccel ff_mpeg1_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };
 
-const AVHWAccel ff_mpeg2_videotoolbox_hwaccel = {
-    .name           = "mpeg2_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG2VIDEO,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_mpeg2_videotoolbox_hwaccel = {
+    .p.name         = "mpeg2_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG2VIDEO,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = videotoolbox_mpeg_start_frame,
     .decode_slice   = videotoolbox_mpeg_decode_slice,
@@ -1361,11 +1362,11 @@  const AVHWAccel ff_mpeg2_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };
 
-const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = {
-    .name           = "mpeg4_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_MPEG4,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_mpeg4_videotoolbox_hwaccel = {
+    .p.name         = "mpeg4_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_MPEG4,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = videotoolbox_mpeg_start_frame,
     .decode_slice   = videotoolbox_mpeg_decode_slice,
@@ -1376,11 +1377,11 @@  const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };
 
-const AVHWAccel ff_prores_videotoolbox_hwaccel = {
-    .name           = "prores_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_PRORES,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_prores_videotoolbox_hwaccel = {
+    .p.name         = "prores_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_PRORES,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = videotoolbox_prores_start_frame,
     .decode_slice   = videotoolbox_prores_decode_slice,
diff --git a/libavcodec/videotoolbox_vp9.c b/libavcodec/videotoolbox_vp9.c
index a998f36d1a..f5489854e3 100644
--- a/libavcodec/videotoolbox_vp9.c
+++ b/libavcodec/videotoolbox_vp9.c
@@ -31,6 +31,7 @@ 
 #include "libavutil/intreadwrite.h"
 #include "libavutil/pixdesc.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "internal.h"
 #include "vp9shared.h"
 
@@ -125,11 +126,11 @@  static int videotoolbox_vp9_end_frame(AVCodecContext *avctx)
     return ff_videotoolbox_common_end_frame(avctx, frame);
 }
 
-const AVHWAccel ff_vp9_videotoolbox_hwaccel = {
-    .name           = "vp9_videotoolbox",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_VP9,
-    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+const FFHWAccel ff_vp9_videotoolbox_hwaccel = {
+    .p.name         = "vp9_videotoolbox",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_VP9,
+    .p.pix_fmt      = AV_PIX_FMT_VIDEOTOOLBOX,
     .alloc_frame    = ff_videotoolbox_alloc_frame,
     .start_frame    = videotoolbox_vp9_start_frame,
     .decode_slice   = videotoolbox_vp9_decode_slice,
diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
index 15a2961f56..64b1c7f60e 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -31,6 +31,7 @@ 
 #include "avcodec.h"
 #include "codec_internal.h"
 #include "decode.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "mathops.h"
 #include "thread.h"
@@ -166,8 +167,8 @@  static void vp8_decode_flush_impl(AVCodecContext *avctx, int free_mem)
     if (free_mem)
         free_buffers(s);
 
-    if (avctx->hwaccel && avctx->hwaccel->flush)
-        avctx->hwaccel->flush(avctx);
+    if (FF_HW_HAS_CB(avctx, flush))
+        FF_HW_SIMPLE_CALL(avctx, flush);
 }
 
 static void vp8_decode_flush(AVCodecContext *avctx)
@@ -2764,15 +2765,16 @@  int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame,
         ff_thread_finish_setup(avctx);
 
     if (avctx->hwaccel) {
-        ret = avctx->hwaccel->start_frame(avctx, avpkt->data, avpkt->size);
+        const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
+        ret = hwaccel->start_frame(avctx, avpkt->data, avpkt->size);
         if (ret < 0)
             goto err;
 
-        ret = avctx->hwaccel->decode_slice(avctx, avpkt->data, avpkt->size);
+        ret = hwaccel->decode_slice(avctx, avpkt->data, avpkt->size);
         if (ret < 0)
             goto err;
 
-        ret = avctx->hwaccel->end_frame(avctx);
+        ret = hwaccel->end_frame(avctx);
         if (ret < 0)
             goto err;
 
diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 751dc7271f..89f7549ef0 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -27,6 +27,7 @@ 
 #include "codec_internal.h"
 #include "decode.h"
 #include "get_bits.h"
+#include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "profiles.h"
 #include "thread.h"
@@ -1635,13 +1636,14 @@  static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
     }
 
     if (avctx->hwaccel) {
-        ret = avctx->hwaccel->start_frame(avctx, NULL, 0);
+        const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
+        ret = hwaccel->start_frame(avctx, NULL, 0);
         if (ret < 0)
             return ret;
-        ret = avctx->hwaccel->decode_slice(avctx, pkt->data, pkt->size);
+        ret = hwaccel->decode_slice(avctx, pkt->data, pkt->size);
         if (ret < 0)
             return ret;
-        ret = avctx->hwaccel->end_frame(avctx);
+        ret = hwaccel->end_frame(avctx);
         if (ret < 0)
             return ret;
         goto finish;
@@ -1798,8 +1800,8 @@  static void vp9_decode_flush(AVCodecContext *avctx)
     for (i = 0; i < 8; i++)
         ff_thread_release_ext_buffer(avctx, &s->s.refs[i]);
 
-    if (avctx->hwaccel && avctx->hwaccel->flush)
-        avctx->hwaccel->flush(avctx);
+    if (FF_HW_HAS_CB(avctx, flush))
+        FF_HW_SIMPLE_CALL(avctx, flush);
 }
 
 static av_cold int vp9_decode_init(AVCodecContext *avctx)
diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c
index d0f4019248..adaebb2818 100644
--- a/libavcodec/vulkan_av1.c
+++ b/libavcodec/vulkan_av1.c
@@ -572,11 +572,11 @@  static void vk_av1_free_frame_priv(void *_hwctx, uint8_t *data)
     av_free(ap);
 }
 
-const AVHWAccel ff_av1_vulkan_hwaccel = {
-    .name                  = "av1_vulkan",
-    .type                  = AVMEDIA_TYPE_VIDEO,
-    .id                    = AV_CODEC_ID_AV1,
-    .pix_fmt               = AV_PIX_FMT_VULKAN,
+const FFHWAccel ff_av1_vulkan_hwaccel = {
+    .p.name                = "av1_vulkan",
+    .p.type                = AVMEDIA_TYPE_VIDEO,
+    .p.id                  = AV_CODEC_ID_AV1,
+    .p.pix_fmt             = AV_PIX_FMT_VULKAN,
     .start_frame           = &vk_av1_start_frame,
     .decode_slice          = &vk_av1_decode_slice,
     .end_frame             = &vk_av1_end_frame,
diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c
index 84bcef7933..f08a107a36 100644
--- a/libavcodec/vulkan_h264.c
+++ b/libavcodec/vulkan_h264.c
@@ -558,11 +558,11 @@  static void vk_h264_free_frame_priv(void *_hwctx, uint8_t *data)
     av_free(hp);
 }
 
-const AVHWAccel ff_h264_vulkan_hwaccel = {
-    .name                  = "h264_vulkan",
-    .type                  = AVMEDIA_TYPE_VIDEO,
-    .id                    = AV_CODEC_ID_H264,
-    .pix_fmt               = AV_PIX_FMT_VULKAN,
+const FFHWAccel ff_h264_vulkan_hwaccel = {
+    .p.name                = "h264_vulkan",
+    .p.type                = AVMEDIA_TYPE_VIDEO,
+    .p.id                  = AV_CODEC_ID_H264,
+    .p.pix_fmt             = AV_PIX_FMT_VULKAN,
     .start_frame           = &vk_h264_start_frame,
     .decode_slice          = &vk_h264_decode_slice,
     .end_frame             = &vk_h264_end_frame,
diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c
index d56252399c..672694a19d 100644
--- a/libavcodec/vulkan_hevc.c
+++ b/libavcodec/vulkan_hevc.c
@@ -952,11 +952,11 @@  static void vk_hevc_free_frame_priv(void *_hwctx, uint8_t *data)
     av_free(hp);
 }
 
-const AVHWAccel ff_hevc_vulkan_hwaccel = {
-    .name                  = "hevc_vulkan",
-    .type                  = AVMEDIA_TYPE_VIDEO,
-    .id                    = AV_CODEC_ID_HEVC,
-    .pix_fmt               = AV_PIX_FMT_VULKAN,
+const FFHWAccel ff_hevc_vulkan_hwaccel = {
+    .p.name                = "hevc_vulkan",
+    .p.type                = AVMEDIA_TYPE_VIDEO,
+    .p.id                  = AV_CODEC_ID_HEVC,
+    .p.pix_fmt             = AV_PIX_FMT_VULKAN,
     .start_frame           = &vk_hevc_start_frame,
     .decode_slice          = &vk_hevc_decode_slice,
     .end_frame             = &vk_hevc_end_frame,