diff mbox series

[FFmpeg-devel,02/10] hw_base_encode: move VAAPI SPS/PPS constructors to a shared file

Message ID 20240901000314.379276-1-dev@lynne.ee
State New
Headers show
Series None | expand

Commit Message

Lynne Sept. 1, 2024, 12:02 a.m. UTC
---
 libavcodec/Makefile              |   2 +-
 libavcodec/hw_base_encode_h264.c | 265 +++++++++++++++++++++++++++++++
 libavcodec/hw_base_encode_h264.h |  53 +++++++
 libavcodec/vaapi_encode_h264.c   | 262 +++---------------------------
 4 files changed, 341 insertions(+), 241 deletions(-)
 create mode 100644 libavcodec/hw_base_encode_h264.c
 create mode 100644 libavcodec/hw_base_encode_h264.h

Comments

Tong Wu Sept. 4, 2024, 2:09 p.m. UTC | #1
Lynne:
>Subject: [FFmpeg-devel] [PATCH 02/10] hw_base_encode: move VAAPI SPS/PPS
>constructors to a shared file
>
>---
> libavcodec/Makefile              |   2 +-
> libavcodec/hw_base_encode_h264.c | 265
>+++++++++++++++++++++++++++++++  libavcodec/hw_base_encode_h264.h |  53
>+++++++
> libavcodec/vaapi_encode_h264.c   | 262 +++---------------------------
> 4 files changed, 341 insertions(+), 241 deletions(-)  create mode 100644
>libavcodec/hw_base_encode_h264.c  create mode 100644
>libavcodec/hw_base_encode_h264.h
>
>diff --git a/libavcodec/Makefile b/libavcodec/Makefile index
>3b4b8681f5..2e53dd723a 100644
>--- a/libavcodec/Makefile
>+++ b/libavcodec/Makefile
>@@ -166,7 +166,7 @@ OBJS-$(CONFIG_STARTCODE)               += startcode.o
> OBJS-$(CONFIG_TEXTUREDSP)              += texturedsp.o
> OBJS-$(CONFIG_TEXTUREDSPENC)           += texturedspenc.o
> OBJS-$(CONFIG_TPELDSP)                 += tpeldsp.o
>-OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o hw_base_encode.o
>+OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o hw_base_encode.o
>hw_base_encode_h264.o
> OBJS-$(CONFIG_AV1_AMF_ENCODER)         += amfenc_av1.o
> OBJS-$(CONFIG_VC1DSP)                  += vc1dsp.o
> OBJS-$(CONFIG_VIDEODSP)                += videodsp.o
>diff --git a/libavcodec/hw_base_encode_h264.c
>b/libavcodec/hw_base_encode_h264.c
>new file mode 100644
>index 0000000000..5c3957cddb
>--- /dev/null
>+++ b/libavcodec/hw_base_encode_h264.c
>@@ -0,0 +1,265 @@
>+/*
>+ * This file is part of FFmpeg.
>+ *
>+ * FFmpeg is free software; you can redistribute it and/or
>+ * modify it under the terms of the GNU Lesser General Public
>+ * License as published by the Free Software Foundation; either
>+ * version 2.1 of the License, or (at your option) any later version.
>+ *
>+ * FFmpeg is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>+ * Lesser General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>+ * License along with FFmpeg; if not, write to the Free Software
>+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>+02110-1301 USA  */
>+
>+#include "hw_base_encode_h264.h"
>+
>+#include "h2645data.h"
>+#include "h264_levels.h"
>+
>+#include "libavutil/pixdesc.h"
>+
>+int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx,
>+                                       AVCodecContext *avctx,
>+                                       FFHWBaseEncodeH264 *common,
>+                                       FFHWBaseEncodeH264Opts *opts) {
>+    H264RawSPS *sps = &common->raw_sps;
>+    H264RawPPS *pps = &common->raw_pps;
>+    const AVPixFmtDescriptor *desc;
>+    int bit_depth;
>+
>+    memset(sps, 0, sizeof(*sps));
>+    memset(pps, 0, sizeof(*pps));
>+
>+    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>+    av_assert0(desc);
>+    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc-
>>log2_chroma_h != 1) {
>+        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>+                "%s is not supported.\n", desc->name);
>+        return AVERROR(EINVAL);
>+    }
>+    bit_depth = desc->comp[0].depth;
>+
>+    sps->nal_unit_header.nal_ref_idc   = 3;
>+    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>+
>+    sps->profile_idc = avctx->profile & 0xff;
>+
>+    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>+        avctx->profile == AV_PROFILE_H264_MAIN)
>+        sps->constraint_set1_flag = 1;
>+
>+    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>AV_PROFILE_H264_HIGH_10)
>+        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>+
>+    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>+        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>AV_PROFILE_H264_HIGH_10) {
>+        sps->constraint_set4_flag = 1;
>+        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>+    }
>+
>+    if (base_ctx->gop_size == 1)
>+        common->dpb_frames = 0;
>+    else
>+        common->dpb_frames = 1 + base_ctx->max_b_depth;
>+
>+    if (avctx->level != AV_LEVEL_UNKNOWN) {
>+        sps->level_idc = avctx->level;
>+    } else {
>+        const H264LevelDescriptor *level;
>+        int framerate;
>+
>+        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>+            framerate = avctx->framerate.num / avctx->framerate.den;
>+        else
>+            framerate = 0;
>+
>+        level = ff_h264_guess_level(sps->profile_idc,
>+                                    opts->bit_rate,
>+                                    framerate,
>+                                    common->mb_width  * 16,
>+                                    common->mb_height * 16,
>+                                    common->dpb_frames);
>+        if (level) {
>+            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>+            if (level->constraint_set3_flag)
>+                sps->constraint_set3_flag = 1;
>+            sps->level_idc = level->level_idc;
>+        } else {
>+            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>+                   "to any level: using level 6.2.\n");
>+            sps->level_idc = 62;
>+        }
>+    }
>+
>+    sps->seq_parameter_set_id = 0;
>+    sps->chroma_format_idc    = 1;
>+    sps->bit_depth_luma_minus8 = bit_depth - 8;
>+    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>+
>+    sps->log2_max_frame_num_minus4 = 4;
>+    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>+    if (sps->pic_order_cnt_type == 0) {
>+        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>+    }
>+
>+    sps->max_num_ref_frames = common->dpb_frames;
>+
>+    sps->pic_width_in_mbs_minus1        = common->mb_width  - 1;
>+    sps->pic_height_in_map_units_minus1 = common->mb_height - 1;
>+
>+    sps->frame_mbs_only_flag = 1;
>+    sps->direct_8x8_inference_flag = 1;
>+
>+    if (avctx->width  != 16 * common->mb_width ||
>+        avctx->height != 16 * common->mb_height) {
>+        sps->frame_cropping_flag = 1;
>+
>+        sps->frame_crop_left_offset   = 0;
>+        sps->frame_crop_right_offset  =
>+            (16 * common->mb_width - avctx->width) / 2;
>+        sps->frame_crop_top_offset    = 0;
>+        sps->frame_crop_bottom_offset =
>+            (16 * common->mb_height - avctx->height) / 2;
>+    } else {
>+        sps->frame_cropping_flag = 0;
>+    }
>+
>+    sps->vui_parameters_present_flag = 1;
>+
>+    if (avctx->sample_aspect_ratio.num != 0 &&
>+        avctx->sample_aspect_ratio.den != 0) {
>+        int num, den, i;
>+        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>+                  avctx->sample_aspect_ratio.den, 65535);
>+        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>+            if (num == ff_h2645_pixel_aspect[i].num &&
>+                den == ff_h2645_pixel_aspect[i].den) {
>+                sps->vui.aspect_ratio_idc = i;
>+                break;
>+            }
>+        }
>+        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>+            sps->vui.aspect_ratio_idc = 255;
>+            sps->vui.sar_width  = num;
>+            sps->vui.sar_height = den;
>+        }
>+        sps->vui.aspect_ratio_info_present_flag = 1;
>+    }
>+
>+    // Unspecified video format, from table E-2.
>+    sps->vui.video_format             = 5;
>+    sps->vui.video_full_range_flag    =
>+        avctx->color_range == AVCOL_RANGE_JPEG;
>+    sps->vui.colour_primaries         = avctx->color_primaries;
>+    sps->vui.transfer_characteristics = avctx->color_trc;
>+    sps->vui.matrix_coefficients      = avctx->colorspace;
>+    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>+        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>+        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>+        sps->vui.colour_description_present_flag = 1;
>+    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>+        sps->vui.colour_description_present_flag)
>+        sps->vui.video_signal_type_present_flag = 1;
>+
>+    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>+        sps->vui.chroma_loc_info_present_flag = 1;
>+        sps->vui.chroma_sample_loc_type_top_field    =
>+        sps->vui.chroma_sample_loc_type_bottom_field =
>+            avctx->chroma_sample_location - 1;
>+    }
>+
>+    sps->vui.timing_info_present_flag = 1;
>+    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>+        sps->vui.num_units_in_tick = avctx->framerate.den;
>+        sps->vui.time_scale        = 2 * avctx->framerate.num;
>+        sps->vui.fixed_frame_rate_flag = 1;
>+    } else {
>+        sps->vui.num_units_in_tick = avctx->time_base.num;
>+        sps->vui.time_scale        = 2 * avctx->time_base.den;
>+        sps->vui.fixed_frame_rate_flag = 0;
>+    }
>+
>+    if (opts->flags & FF_HW_H264_SEI_TIMING) {
>+        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>+        H264RawSEIBufferingPeriod *bp = &common->sei_buffering_period;
>+
>+        sps->vui.nal_hrd_parameters_present_flag = 1;
>+
>+        hrd->cpb_cnt_minus1 = 0;
>+
>+        // Try to scale these to a sensible range so that the
>+        // golomb encode of the value is not overlong.
>+        hrd->bit_rate_scale =
>+            av_clip_uintp2(av_log2(opts->bit_rate) - 15 - 6, 4);
>+        hrd->bit_rate_value_minus1[0] =
>+            (opts->bit_rate >> hrd->bit_rate_scale + 6) - 1;
>+
>+        hrd->cpb_size_scale =
>+            av_clip_uintp2(av_log2(opts->hrd_buffer_size) - 15 - 4, 4);
>+        hrd->cpb_size_value_minus1[0] =
>+            (opts->hrd_buffer_size >> hrd->cpb_size_scale + 4) - 1;
>+
>+        // CBR mode as defined for the HRD cannot be achieved without filler
>+        // data, so this flag cannot be set even with VAAPI CBR modes.
>+        hrd->cbr_flag[0] = 0;
>+
>+        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>+        hrd->cpb_removal_delay_length_minus1         = 23;
>+        hrd->dpb_output_delay_length_minus1          = 7;
>+        hrd->time_offset_length                      = 0;
>+
>+        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>+
>+        // This calculation can easily overflow 32 bits.
>+        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>+            (uint64_t)opts->initial_buffer_fullness /
>+            opts->hrd_buffer_size;
>+        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>+    } else {
>+        sps->vui.nal_hrd_parameters_present_flag = 0;
>+        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>+    }
>+
>+    sps->vui.bitstream_restriction_flag    = 1;
>+    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>+    sps->vui.log2_max_mv_length_horizontal = 15;
>+    sps->vui.log2_max_mv_length_vertical   = 15;
>+    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>+    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>+
>+    pps->nal_unit_header.nal_ref_idc = 3;
>+    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>+
>+    pps->pic_parameter_set_id = 0;
>+    pps->seq_parameter_set_id = 0;
>+
>+    pps->entropy_coding_mode_flag =
>+        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>+          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>+          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>+    if (!opts->cabac && pps->entropy_coding_mode_flag)
>+        pps->entropy_coding_mode_flag = 0;
>+
>+    pps->num_ref_idx_l0_default_active_minus1 = 0;
>+    pps->num_ref_idx_l1_default_active_minus1 = 0;
>+
>+    pps->pic_init_qp_minus26 = opts->fixed_qp_idr - 26;
>+
>+    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>+        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>+        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>+        pps->more_rbsp_data = 0;
>+    } else {
>+        pps->more_rbsp_data = 1;
>+
>+        pps->transform_8x8_mode_flag = 1;
>+    }
>+
>+    return 0;
>+}
>diff --git a/libavcodec/hw_base_encode_h264.h
>b/libavcodec/hw_base_encode_h264.h
>new file mode 100644
>index 0000000000..d1bae8f36f
>--- /dev/null
>+++ b/libavcodec/hw_base_encode_h264.h
>@@ -0,0 +1,53 @@
>+/*
>+ * This file is part of FFmpeg.
>+ *
>+ * FFmpeg is free software; you can redistribute it and/or
>+ * modify it under the terms of the GNU Lesser General Public
>+ * License as published by the Free Software Foundation; either
>+ * version 2.1 of the License, or (at your option) any later version.
>+ *
>+ * FFmpeg is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>+ * Lesser General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>+ * License along with FFmpeg; if not, write to the Free Software
>+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>+02110-1301 USA  */
>+
>+#ifndef AVCODEC_HW_BASE_ENCODE_H264_H
>+#define AVCODEC_HW_BASE_ENCODE_H264_H
>+
>+#include "hw_base_encode.h"
>+#include "cbs_h264.h"
>+
>+typedef struct FFHWBaseEncodeH264 {
>+    H264RawSPS raw_sps;
>+    H264RawPPS raw_pps;
>+    H264RawAUD raw_aud;
>+
>+    H264RawSEIBufferingPeriod sei_buffering_period;
>+
>+    int dpb_frames;
>+    int mb_width;
>+    int mb_height;
>+} FFHWBaseEncodeH264;
>+
>+typedef struct FFHWBaseEncodeH264Opts {
>+    int flags;
>+#define FF_HW_H264_SEI_TIMING (1 << 0)
>+
>+    int64_t bit_rate;
>+    int cabac;
>+    int fixed_qp_idr;
>+    uint64_t hrd_buffer_size;
>+    uint64_t initial_buffer_fullness;
>+} FFHWBaseEncodeH264Opts;
>+
>+int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx,
>+                                       AVCodecContext *avctx,
>+                                       FFHWBaseEncodeH264 *common,
>+                                       FFHWBaseEncodeH264Opts *opts);
>+
>+#endif /* AVCODEC_HW_BASE_ENCODE_H264_H */
>diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
>index 35d3967766..443a569104 100644
>--- a/libavcodec/vaapi_encode_h264.c
>+++ b/libavcodec/vaapi_encode_h264.c
>@@ -33,6 +33,7 @@
> #include "cbs_h264.h"
> #include "codec_internal.h"
> #include "h264.h"
>+#include "hw_base_encode_h264.h"
> #include "h264_levels.h"
> #include "h2645data.h"
> #include "vaapi_encode.h"
>@@ -67,6 +68,7 @@ typedef struct VAAPIEncodeH264Picture {
>
> typedef struct VAAPIEncodeH264Context {
>     VAAPIEncodeContext common;
>+    FFHWBaseEncodeH264 units;
>
>     // User options.
>     int qp;
>@@ -85,15 +87,11 @@ typedef struct VAAPIEncodeH264Context {
>     int fixed_qp_p;
>     int fixed_qp_b;
>
>-    int dpb_frames;
>-
>     // Writer structures.
>     CodedBitstreamContext *cbc;
>     CodedBitstreamFragment current_access_unit;
>
>     H264RawAUD   raw_aud;
>-    H264RawSPS   raw_sps;
>-    H264RawPPS   raw_pps;
>     H264RawSlice raw_slice;
>
>     H264RawSEIBufferingPeriod      sei_buffering_period;
>@@ -168,11 +166,11 @@ static int
>vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx,
>         priv->aud_needed = 0;
>     }
>
>-    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_sps);
>+    err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_sps);
>     if (err < 0)
>         goto fail;
>
>-    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_pps);
>+    err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_pps);
>     if (err < 0)
>         goto fail;
>
>@@ -298,240 +296,24 @@ static int
>vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
>     FFHWBaseEncodeContext        *base_ctx = avctx->priv_data;
>     VAAPIEncodeContext                *ctx = avctx->priv_data;
>     VAAPIEncodeH264Context           *priv = avctx->priv_data;
>-    H264RawSPS                        *sps = &priv->raw_sps;
>-    H264RawPPS                        *pps = &priv->raw_pps;
>+    H264RawSPS                        *sps = &priv->units.raw_sps;
>+    H264RawPPS                        *pps = &priv->units.raw_pps;
>     VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params;
>     VAEncPictureParameterBufferH264  *vpic = ctx->codec_picture_params;
>-    const AVPixFmtDescriptor *desc;
>-    int bit_depth;
>-
>-    memset(sps, 0, sizeof(*sps));
>-    memset(pps, 0, sizeof(*pps));
>-
>-    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>-    av_assert0(desc);
>-    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc-
>>log2_chroma_h != 1) {
>-        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>-                "%s is not supported.\n", desc->name);
>-        return AVERROR(EINVAL);
>-    }
>-    bit_depth = desc->comp[0].depth;
>-
>-    sps->nal_unit_header.nal_ref_idc   = 3;
>-    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>-
>-    sps->profile_idc = avctx->profile & 0xff;
>-
>-    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>-        avctx->profile == AV_PROFILE_H264_MAIN)
>-        sps->constraint_set1_flag = 1;
>-
>-    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>AV_PROFILE_H264_HIGH_10)
>-        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>-
>-    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>-        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>AV_PROFILE_H264_HIGH_10) {
>-        sps->constraint_set4_flag = 1;
>-        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>-    }
>-
>-    if (base_ctx->gop_size == 1)
>-        priv->dpb_frames = 0;
>-    else
>-        priv->dpb_frames = 1 + base_ctx->max_b_depth;
>-
>-    if (avctx->level != AV_LEVEL_UNKNOWN) {
>-        sps->level_idc = avctx->level;
>-    } else {
>-        const H264LevelDescriptor *level;
>-        int framerate;
>-
>-        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>-            framerate = avctx->framerate.num / avctx->framerate.den;
>-        else
>-            framerate = 0;
>-
>-        level = ff_h264_guess_level(sps->profile_idc,
>-                                    avctx->bit_rate,
>-                                    framerate,
>-                                    priv->mb_width  * 16,
>-                                    priv->mb_height * 16,
>-                                    priv->dpb_frames);
>-        if (level) {
>-            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>-            if (level->constraint_set3_flag)
>-                sps->constraint_set3_flag = 1;
>-            sps->level_idc = level->level_idc;
>-        } else {
>-            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>-                   "to any level: using level 6.2.\n");
>-            sps->level_idc = 62;
>-        }
>-    }
>-
>-    sps->seq_parameter_set_id = 0;
>-    sps->chroma_format_idc    = 1;
>-    sps->bit_depth_luma_minus8 = bit_depth - 8;
>-    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>-
>-    sps->log2_max_frame_num_minus4 = 4;
>-    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>-    if (sps->pic_order_cnt_type == 0) {
>-        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>-    }
>-
>-    sps->max_num_ref_frames = priv->dpb_frames;
>-
>-    sps->pic_width_in_mbs_minus1        = priv->mb_width  - 1;
>-    sps->pic_height_in_map_units_minus1 = priv->mb_height - 1;
>-
>-    sps->frame_mbs_only_flag = 1;
>-    sps->direct_8x8_inference_flag = 1;
>-
>-    if (avctx->width  != 16 * priv->mb_width ||
>-        avctx->height != 16 * priv->mb_height) {
>-        sps->frame_cropping_flag = 1;
>-
>-        sps->frame_crop_left_offset   = 0;
>-        sps->frame_crop_right_offset  =
>-            (16 * priv->mb_width - avctx->width) / 2;
>-        sps->frame_crop_top_offset    = 0;
>-        sps->frame_crop_bottom_offset =
>-            (16 * priv->mb_height - avctx->height) / 2;
>-    } else {
>-        sps->frame_cropping_flag = 0;
>-    }
>-
>-    sps->vui_parameters_present_flag = 1;
>-
>-    if (avctx->sample_aspect_ratio.num != 0 &&
>-        avctx->sample_aspect_ratio.den != 0) {
>-        int num, den, i;
>-        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>-                  avctx->sample_aspect_ratio.den, 65535);
>-        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>-            if (num == ff_h2645_pixel_aspect[i].num &&
>-                den == ff_h2645_pixel_aspect[i].den) {
>-                sps->vui.aspect_ratio_idc = i;
>-                break;
>-            }
>-        }
>-        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>-            sps->vui.aspect_ratio_idc = 255;
>-            sps->vui.sar_width  = num;
>-            sps->vui.sar_height = den;
>-        }
>-        sps->vui.aspect_ratio_info_present_flag = 1;
>-    }
>-
>-    // Unspecified video format, from table E-2.
>-    sps->vui.video_format             = 5;
>-    sps->vui.video_full_range_flag    =
>-        avctx->color_range == AVCOL_RANGE_JPEG;
>-    sps->vui.colour_primaries         = avctx->color_primaries;
>-    sps->vui.transfer_characteristics = avctx->color_trc;
>-    sps->vui.matrix_coefficients      = avctx->colorspace;
>-    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>-        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>-        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>-        sps->vui.colour_description_present_flag = 1;
>-    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>-        sps->vui.colour_description_present_flag)
>-        sps->vui.video_signal_type_present_flag = 1;
>-
>-    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>-        sps->vui.chroma_loc_info_present_flag = 1;
>-        sps->vui.chroma_sample_loc_type_top_field    =
>-        sps->vui.chroma_sample_loc_type_bottom_field =
>-            avctx->chroma_sample_location - 1;
>-    }
>-
>-    sps->vui.timing_info_present_flag = 1;
>-    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>-        sps->vui.num_units_in_tick = avctx->framerate.den;
>-        sps->vui.time_scale        = 2 * avctx->framerate.num;
>-        sps->vui.fixed_frame_rate_flag = 1;
>-    } else {
>-        sps->vui.num_units_in_tick = avctx->time_base.num;
>-        sps->vui.time_scale        = 2 * avctx->time_base.den;
>-        sps->vui.fixed_frame_rate_flag = 0;
>-    }
>-
>-    if (priv->sei & SEI_TIMING) {
>-        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>-        H264RawSEIBufferingPeriod *bp = &priv->sei_buffering_period;
>-
>-        sps->vui.nal_hrd_parameters_present_flag = 1;
>-
>-        hrd->cpb_cnt_minus1 = 0;
>-
>-        // Try to scale these to a sensible range so that the
>-        // golomb encode of the value is not overlong.
>-        hrd->bit_rate_scale =
>-            av_clip_uintp2(av_log2(ctx->va_bit_rate) - 15 - 6, 4);
>-        hrd->bit_rate_value_minus1[0] =
>-            (ctx->va_bit_rate >> hrd->bit_rate_scale + 6) - 1;
>-
>-        hrd->cpb_size_scale =
>-            av_clip_uintp2(av_log2(ctx->hrd_params.buffer_size) - 15 - 4, 4);
>-        hrd->cpb_size_value_minus1[0] =
>-            (ctx->hrd_params.buffer_size >> hrd->cpb_size_scale + 4) - 1;
>-
>-        // CBR mode as defined for the HRD cannot be achieved without filler
>-        // data, so this flag cannot be set even with VAAPI CBR modes.
>-        hrd->cbr_flag[0] = 0;
>
>-        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>-        hrd->cpb_removal_delay_length_minus1         = 23;
>-        hrd->dpb_output_delay_length_minus1          = 7;
>-        hrd->time_offset_length                      = 0;
>-
>-        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>-
>-        // This calculation can easily overflow 32 bits.
>-        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>-            (uint64_t)ctx->hrd_params.initial_buffer_fullness /
>-            ctx->hrd_params.buffer_size;
>-        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>-    } else {
>-        sps->vui.nal_hrd_parameters_present_flag = 0;
>-        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>-    }
>-
>-    sps->vui.bitstream_restriction_flag    = 1;
>-    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>-    sps->vui.log2_max_mv_length_horizontal = 15;
>-    sps->vui.log2_max_mv_length_vertical   = 15;
>-    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>-    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>-
>-    pps->nal_unit_header.nal_ref_idc = 3;
>-    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>-
>-    pps->pic_parameter_set_id = 0;
>-    pps->seq_parameter_set_id = 0;
>-
>-    pps->entropy_coding_mode_flag =
>-        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>-          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>-          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>-    if (!priv->coder && pps->entropy_coding_mode_flag)
>-        pps->entropy_coding_mode_flag = 0;
>-
>-    pps->num_ref_idx_l0_default_active_minus1 = 0;
>-    pps->num_ref_idx_l1_default_active_minus1 = 0;
>-
>-    pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26;
>-
>-    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>-        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>-        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>-        pps->more_rbsp_data = 0;
>-    } else {
>-        pps->more_rbsp_data = 1;
>+    FFHWBaseEncodeH264Opts unit_opts = {
>+        .flags = (priv->sei & SEI_TIMING) ? FF_HW_H264_SEI_TIMING : 0,
>+        .cabac = priv->coder,
>+        .hrd_buffer_size = ctx->hrd_params.buffer_size,
>+        .fixed_qp_idr = priv->fixed_qp_idr,
>+        .initial_buffer_fullness = ctx->hrd_params.initial_buffer_fullness,
>+        .bit_rate = ctx->va_bit_rate,
>+    };
>
>-        pps->transform_8x8_mode_flag = 1;
>-    }
>+    int err = ff_hw_base_encode_init_params_h264(base_ctx, avctx,
>+                                                 &priv->units, &unit_opts);
>+    if (err < 0)
>+        return err;
>
>     *vseq = (VAEncSequenceParameterBufferH264) {
>         .seq_parameter_set_id = sps->seq_parameter_set_id, @@ -660,7 +442,7
>@@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
>         }
>     }
>     hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame;
>-    if (priv->raw_sps.pic_order_cnt_type == 2) {
>+    if (priv->units.raw_sps.pic_order_cnt_type == 2) {
>         hpic->pic_order_cnt *= 2;
>     }
>
>@@ -870,8 +652,8 @@ static int
>vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>     VAAPIEncodePicture         *vaapi_pic = pic->priv;
>     VAAPIEncodeH264Picture          *hpic = pic->codec_priv;
>     FFHWBaseEncodePicture           *prev = pic->prev;
>-    H264RawSPS                       *sps = &priv->raw_sps;
>-    H264RawPPS                       *pps = &priv->raw_pps;
>+    H264RawSPS                       *sps = &priv->units.raw_sps;
>+    H264RawPPS                       *pps = &priv->units.raw_pps;
>     H264RawSliceHeader                *sh = &priv->raw_slice.header;
>     VAEncPictureParameterBufferH264 *vpic = vaapi_pic->codec_picture_params;
>     VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; @@ -
>923,7 +705,7 @@ static int
>vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>                 ++keep;
>             }
>         }
>-        av_assert0(keep <= priv->dpb_frames);
>+        av_assert0(keep <= priv->units.dpb_frames);
>
>         if (discard == 0) {
>             sh->adaptive_ref_pic_marking_mode_flag = 0;
>--

Are you planning to move more codecs to shared file such as hevc? Since some flags are based on the query result of hardware specific API, d3d12 may not align with the constructors in shared file.
Lynne Sept. 4, 2024, 6:42 p.m. UTC | #2
On 04/09/2024 16:09, Tong Wu wrote:
> Lynne:
>> Subject: [FFmpeg-devel] [PATCH 02/10] hw_base_encode: move VAAPI SPS/PPS
>> constructors to a shared file
>>
>> ---
>> libavcodec/Makefile              |   2 +-
>> libavcodec/hw_base_encode_h264.c | 265
>> +++++++++++++++++++++++++++++++  libavcodec/hw_base_encode_h264.h |  53
>> +++++++
>> libavcodec/vaapi_encode_h264.c   | 262 +++---------------------------
>> 4 files changed, 341 insertions(+), 241 deletions(-)  create mode 100644
>> libavcodec/hw_base_encode_h264.c  create mode 100644
>> libavcodec/hw_base_encode_h264.h
>>
>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile index
>> 3b4b8681f5..2e53dd723a 100644
>> --- a/libavcodec/Makefile
>> +++ b/libavcodec/Makefile
>> @@ -166,7 +166,7 @@ OBJS-$(CONFIG_STARTCODE)               += startcode.o
>> OBJS-$(CONFIG_TEXTUREDSP)              += texturedsp.o
>> OBJS-$(CONFIG_TEXTUREDSPENC)           += texturedspenc.o
>> OBJS-$(CONFIG_TPELDSP)                 += tpeldsp.o
>> -OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o hw_base_encode.o
>> +OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o hw_base_encode.o
>> hw_base_encode_h264.o
>> OBJS-$(CONFIG_AV1_AMF_ENCODER)         += amfenc_av1.o
>> OBJS-$(CONFIG_VC1DSP)                  += vc1dsp.o
>> OBJS-$(CONFIG_VIDEODSP)                += videodsp.o
>> diff --git a/libavcodec/hw_base_encode_h264.c
>> b/libavcodec/hw_base_encode_h264.c
>> new file mode 100644
>> index 0000000000..5c3957cddb
>> --- /dev/null
>> +++ b/libavcodec/hw_base_encode_h264.c
>> @@ -0,0 +1,265 @@
>> +/*
>> + * This file is part of FFmpeg.
>> + *
>> + * FFmpeg is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * FFmpeg is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with FFmpeg; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>> +02110-1301 USA  */
>> +
>> +#include "hw_base_encode_h264.h"
>> +
>> +#include "h2645data.h"
>> +#include "h264_levels.h"
>> +
>> +#include "libavutil/pixdesc.h"
>> +
>> +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx,
>> +                                       AVCodecContext *avctx,
>> +                                       FFHWBaseEncodeH264 *common,
>> +                                       FFHWBaseEncodeH264Opts *opts) {
>> +    H264RawSPS *sps = &common->raw_sps;
>> +    H264RawPPS *pps = &common->raw_pps;
>> +    const AVPixFmtDescriptor *desc;
>> +    int bit_depth;
>> +
>> +    memset(sps, 0, sizeof(*sps));
>> +    memset(pps, 0, sizeof(*pps));
>> +
>> +    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>> +    av_assert0(desc);
>> +    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc-
>>> log2_chroma_h != 1) {
>> +        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>> +                "%s is not supported.\n", desc->name);
>> +        return AVERROR(EINVAL);
>> +    }
>> +    bit_depth = desc->comp[0].depth;
>> +
>> +    sps->nal_unit_header.nal_ref_idc   = 3;
>> +    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>> +
>> +    sps->profile_idc = avctx->profile & 0xff;
>> +
>> +    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>> +        avctx->profile == AV_PROFILE_H264_MAIN)
>> +        sps->constraint_set1_flag = 1;
>> +
>> +    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>> AV_PROFILE_H264_HIGH_10)
>> +        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>> +
>> +    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>> +        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>> AV_PROFILE_H264_HIGH_10) {
>> +        sps->constraint_set4_flag = 1;
>> +        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>> +    }
>> +
>> +    if (base_ctx->gop_size == 1)
>> +        common->dpb_frames = 0;
>> +    else
>> +        common->dpb_frames = 1 + base_ctx->max_b_depth;
>> +
>> +    if (avctx->level != AV_LEVEL_UNKNOWN) {
>> +        sps->level_idc = avctx->level;
>> +    } else {
>> +        const H264LevelDescriptor *level;
>> +        int framerate;
>> +
>> +        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>> +            framerate = avctx->framerate.num / avctx->framerate.den;
>> +        else
>> +            framerate = 0;
>> +
>> +        level = ff_h264_guess_level(sps->profile_idc,
>> +                                    opts->bit_rate,
>> +                                    framerate,
>> +                                    common->mb_width  * 16,
>> +                                    common->mb_height * 16,
>> +                                    common->dpb_frames);
>> +        if (level) {
>> +            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>> +            if (level->constraint_set3_flag)
>> +                sps->constraint_set3_flag = 1;
>> +            sps->level_idc = level->level_idc;
>> +        } else {
>> +            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>> +                   "to any level: using level 6.2.\n");
>> +            sps->level_idc = 62;
>> +        }
>> +    }
>> +
>> +    sps->seq_parameter_set_id = 0;
>> +    sps->chroma_format_idc    = 1;
>> +    sps->bit_depth_luma_minus8 = bit_depth - 8;
>> +    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>> +
>> +    sps->log2_max_frame_num_minus4 = 4;
>> +    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>> +    if (sps->pic_order_cnt_type == 0) {
>> +        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>> +    }
>> +
>> +    sps->max_num_ref_frames = common->dpb_frames;
>> +
>> +    sps->pic_width_in_mbs_minus1        = common->mb_width  - 1;
>> +    sps->pic_height_in_map_units_minus1 = common->mb_height - 1;
>> +
>> +    sps->frame_mbs_only_flag = 1;
>> +    sps->direct_8x8_inference_flag = 1;
>> +
>> +    if (avctx->width  != 16 * common->mb_width ||
>> +        avctx->height != 16 * common->mb_height) {
>> +        sps->frame_cropping_flag = 1;
>> +
>> +        sps->frame_crop_left_offset   = 0;
>> +        sps->frame_crop_right_offset  =
>> +            (16 * common->mb_width - avctx->width) / 2;
>> +        sps->frame_crop_top_offset    = 0;
>> +        sps->frame_crop_bottom_offset =
>> +            (16 * common->mb_height - avctx->height) / 2;
>> +    } else {
>> +        sps->frame_cropping_flag = 0;
>> +    }
>> +
>> +    sps->vui_parameters_present_flag = 1;
>> +
>> +    if (avctx->sample_aspect_ratio.num != 0 &&
>> +        avctx->sample_aspect_ratio.den != 0) {
>> +        int num, den, i;
>> +        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>> +                  avctx->sample_aspect_ratio.den, 65535);
>> +        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>> +            if (num == ff_h2645_pixel_aspect[i].num &&
>> +                den == ff_h2645_pixel_aspect[i].den) {
>> +                sps->vui.aspect_ratio_idc = i;
>> +                break;
>> +            }
>> +        }
>> +        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>> +            sps->vui.aspect_ratio_idc = 255;
>> +            sps->vui.sar_width  = num;
>> +            sps->vui.sar_height = den;
>> +        }
>> +        sps->vui.aspect_ratio_info_present_flag = 1;
>> +    }
>> +
>> +    // Unspecified video format, from table E-2.
>> +    sps->vui.video_format             = 5;
>> +    sps->vui.video_full_range_flag    =
>> +        avctx->color_range == AVCOL_RANGE_JPEG;
>> +    sps->vui.colour_primaries         = avctx->color_primaries;
>> +    sps->vui.transfer_characteristics = avctx->color_trc;
>> +    sps->vui.matrix_coefficients      = avctx->colorspace;
>> +    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>> +        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>> +        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>> +        sps->vui.colour_description_present_flag = 1;
>> +    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>> +        sps->vui.colour_description_present_flag)
>> +        sps->vui.video_signal_type_present_flag = 1;
>> +
>> +    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>> +        sps->vui.chroma_loc_info_present_flag = 1;
>> +        sps->vui.chroma_sample_loc_type_top_field    =
>> +        sps->vui.chroma_sample_loc_type_bottom_field =
>> +            avctx->chroma_sample_location - 1;
>> +    }
>> +
>> +    sps->vui.timing_info_present_flag = 1;
>> +    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>> +        sps->vui.num_units_in_tick = avctx->framerate.den;
>> +        sps->vui.time_scale        = 2 * avctx->framerate.num;
>> +        sps->vui.fixed_frame_rate_flag = 1;
>> +    } else {
>> +        sps->vui.num_units_in_tick = avctx->time_base.num;
>> +        sps->vui.time_scale        = 2 * avctx->time_base.den;
>> +        sps->vui.fixed_frame_rate_flag = 0;
>> +    }
>> +
>> +    if (opts->flags & FF_HW_H264_SEI_TIMING) {
>> +        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>> +        H264RawSEIBufferingPeriod *bp = &common->sei_buffering_period;
>> +
>> +        sps->vui.nal_hrd_parameters_present_flag = 1;
>> +
>> +        hrd->cpb_cnt_minus1 = 0;
>> +
>> +        // Try to scale these to a sensible range so that the
>> +        // golomb encode of the value is not overlong.
>> +        hrd->bit_rate_scale =
>> +            av_clip_uintp2(av_log2(opts->bit_rate) - 15 - 6, 4);
>> +        hrd->bit_rate_value_minus1[0] =
>> +            (opts->bit_rate >> hrd->bit_rate_scale + 6) - 1;
>> +
>> +        hrd->cpb_size_scale =
>> +            av_clip_uintp2(av_log2(opts->hrd_buffer_size) - 15 - 4, 4);
>> +        hrd->cpb_size_value_minus1[0] =
>> +            (opts->hrd_buffer_size >> hrd->cpb_size_scale + 4) - 1;
>> +
>> +        // CBR mode as defined for the HRD cannot be achieved without filler
>> +        // data, so this flag cannot be set even with VAAPI CBR modes.
>> +        hrd->cbr_flag[0] = 0;
>> +
>> +        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>> +        hrd->cpb_removal_delay_length_minus1         = 23;
>> +        hrd->dpb_output_delay_length_minus1          = 7;
>> +        hrd->time_offset_length                      = 0;
>> +
>> +        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>> +
>> +        // This calculation can easily overflow 32 bits.
>> +        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>> +            (uint64_t)opts->initial_buffer_fullness /
>> +            opts->hrd_buffer_size;
>> +        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>> +    } else {
>> +        sps->vui.nal_hrd_parameters_present_flag = 0;
>> +        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>> +    }
>> +
>> +    sps->vui.bitstream_restriction_flag    = 1;
>> +    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>> +    sps->vui.log2_max_mv_length_horizontal = 15;
>> +    sps->vui.log2_max_mv_length_vertical   = 15;
>> +    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>> +    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>> +
>> +    pps->nal_unit_header.nal_ref_idc = 3;
>> +    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>> +
>> +    pps->pic_parameter_set_id = 0;
>> +    pps->seq_parameter_set_id = 0;
>> +
>> +    pps->entropy_coding_mode_flag =
>> +        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>> +          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>> +          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>> +    if (!opts->cabac && pps->entropy_coding_mode_flag)
>> +        pps->entropy_coding_mode_flag = 0;
>> +
>> +    pps->num_ref_idx_l0_default_active_minus1 = 0;
>> +    pps->num_ref_idx_l1_default_active_minus1 = 0;
>> +
>> +    pps->pic_init_qp_minus26 = opts->fixed_qp_idr - 26;
>> +
>> +    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>> +        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>> +        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>> +        pps->more_rbsp_data = 0;
>> +    } else {
>> +        pps->more_rbsp_data = 1;
>> +
>> +        pps->transform_8x8_mode_flag = 1;
>> +    }
>> +
>> +    return 0;
>> +}
>> diff --git a/libavcodec/hw_base_encode_h264.h
>> b/libavcodec/hw_base_encode_h264.h
>> new file mode 100644
>> index 0000000000..d1bae8f36f
>> --- /dev/null
>> +++ b/libavcodec/hw_base_encode_h264.h
>> @@ -0,0 +1,53 @@
>> +/*
>> + * This file is part of FFmpeg.
>> + *
>> + * FFmpeg is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * FFmpeg is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with FFmpeg; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>> +02110-1301 USA  */
>> +
>> +#ifndef AVCODEC_HW_BASE_ENCODE_H264_H
>> +#define AVCODEC_HW_BASE_ENCODE_H264_H
>> +
>> +#include "hw_base_encode.h"
>> +#include "cbs_h264.h"
>> +
>> +typedef struct FFHWBaseEncodeH264 {
>> +    H264RawSPS raw_sps;
>> +    H264RawPPS raw_pps;
>> +    H264RawAUD raw_aud;
>> +
>> +    H264RawSEIBufferingPeriod sei_buffering_period;
>> +
>> +    int dpb_frames;
>> +    int mb_width;
>> +    int mb_height;
>> +} FFHWBaseEncodeH264;
>> +
>> +typedef struct FFHWBaseEncodeH264Opts {
>> +    int flags;
>> +#define FF_HW_H264_SEI_TIMING (1 << 0)
>> +
>> +    int64_t bit_rate;
>> +    int cabac;
>> +    int fixed_qp_idr;
>> +    uint64_t hrd_buffer_size;
>> +    uint64_t initial_buffer_fullness;
>> +} FFHWBaseEncodeH264Opts;
>> +
>> +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx,
>> +                                       AVCodecContext *avctx,
>> +                                       FFHWBaseEncodeH264 *common,
>> +                                       FFHWBaseEncodeH264Opts *opts);
>> +
>> +#endif /* AVCODEC_HW_BASE_ENCODE_H264_H */
>> diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
>> index 35d3967766..443a569104 100644
>> --- a/libavcodec/vaapi_encode_h264.c
>> +++ b/libavcodec/vaapi_encode_h264.c
>> @@ -33,6 +33,7 @@
>> #include "cbs_h264.h"
>> #include "codec_internal.h"
>> #include "h264.h"
>> +#include "hw_base_encode_h264.h"
>> #include "h264_levels.h"
>> #include "h2645data.h"
>> #include "vaapi_encode.h"
>> @@ -67,6 +68,7 @@ typedef struct VAAPIEncodeH264Picture {
>>
>> typedef struct VAAPIEncodeH264Context {
>>      VAAPIEncodeContext common;
>> +    FFHWBaseEncodeH264 units;
>>
>>      // User options.
>>      int qp;
>> @@ -85,15 +87,11 @@ typedef struct VAAPIEncodeH264Context {
>>      int fixed_qp_p;
>>      int fixed_qp_b;
>>
>> -    int dpb_frames;
>> -
>>      // Writer structures.
>>      CodedBitstreamContext *cbc;
>>      CodedBitstreamFragment current_access_unit;
>>
>>      H264RawAUD   raw_aud;
>> -    H264RawSPS   raw_sps;
>> -    H264RawPPS   raw_pps;
>>      H264RawSlice raw_slice;
>>
>>      H264RawSEIBufferingPeriod      sei_buffering_period;
>> @@ -168,11 +166,11 @@ static int
>> vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx,
>>          priv->aud_needed = 0;
>>      }
>>
>> -    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_sps);
>> +    err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_sps);
>>      if (err < 0)
>>          goto fail;
>>
>> -    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_pps);
>> +    err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_pps);
>>      if (err < 0)
>>          goto fail;
>>
>> @@ -298,240 +296,24 @@ static int
>> vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
>>      FFHWBaseEncodeContext        *base_ctx = avctx->priv_data;
>>      VAAPIEncodeContext                *ctx = avctx->priv_data;
>>      VAAPIEncodeH264Context           *priv = avctx->priv_data;
>> -    H264RawSPS                        *sps = &priv->raw_sps;
>> -    H264RawPPS                        *pps = &priv->raw_pps;
>> +    H264RawSPS                        *sps = &priv->units.raw_sps;
>> +    H264RawPPS                        *pps = &priv->units.raw_pps;
>>      VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params;
>>      VAEncPictureParameterBufferH264  *vpic = ctx->codec_picture_params;
>> -    const AVPixFmtDescriptor *desc;
>> -    int bit_depth;
>> -
>> -    memset(sps, 0, sizeof(*sps));
>> -    memset(pps, 0, sizeof(*pps));
>> -
>> -    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>> -    av_assert0(desc);
>> -    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc-
>>> log2_chroma_h != 1) {
>> -        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>> -                "%s is not supported.\n", desc->name);
>> -        return AVERROR(EINVAL);
>> -    }
>> -    bit_depth = desc->comp[0].depth;
>> -
>> -    sps->nal_unit_header.nal_ref_idc   = 3;
>> -    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>> -
>> -    sps->profile_idc = avctx->profile & 0xff;
>> -
>> -    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>> -        avctx->profile == AV_PROFILE_H264_MAIN)
>> -        sps->constraint_set1_flag = 1;
>> -
>> -    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>> AV_PROFILE_H264_HIGH_10)
>> -        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>> -
>> -    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>> -        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>> AV_PROFILE_H264_HIGH_10) {
>> -        sps->constraint_set4_flag = 1;
>> -        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>> -    }
>> -
>> -    if (base_ctx->gop_size == 1)
>> -        priv->dpb_frames = 0;
>> -    else
>> -        priv->dpb_frames = 1 + base_ctx->max_b_depth;
>> -
>> -    if (avctx->level != AV_LEVEL_UNKNOWN) {
>> -        sps->level_idc = avctx->level;
>> -    } else {
>> -        const H264LevelDescriptor *level;
>> -        int framerate;
>> -
>> -        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>> -            framerate = avctx->framerate.num / avctx->framerate.den;
>> -        else
>> -            framerate = 0;
>> -
>> -        level = ff_h264_guess_level(sps->profile_idc,
>> -                                    avctx->bit_rate,
>> -                                    framerate,
>> -                                    priv->mb_width  * 16,
>> -                                    priv->mb_height * 16,
>> -                                    priv->dpb_frames);
>> -        if (level) {
>> -            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>> -            if (level->constraint_set3_flag)
>> -                sps->constraint_set3_flag = 1;
>> -            sps->level_idc = level->level_idc;
>> -        } else {
>> -            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>> -                   "to any level: using level 6.2.\n");
>> -            sps->level_idc = 62;
>> -        }
>> -    }
>> -
>> -    sps->seq_parameter_set_id = 0;
>> -    sps->chroma_format_idc    = 1;
>> -    sps->bit_depth_luma_minus8 = bit_depth - 8;
>> -    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>> -
>> -    sps->log2_max_frame_num_minus4 = 4;
>> -    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>> -    if (sps->pic_order_cnt_type == 0) {
>> -        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>> -    }
>> -
>> -    sps->max_num_ref_frames = priv->dpb_frames;
>> -
>> -    sps->pic_width_in_mbs_minus1        = priv->mb_width  - 1;
>> -    sps->pic_height_in_map_units_minus1 = priv->mb_height - 1;
>> -
>> -    sps->frame_mbs_only_flag = 1;
>> -    sps->direct_8x8_inference_flag = 1;
>> -
>> -    if (avctx->width  != 16 * priv->mb_width ||
>> -        avctx->height != 16 * priv->mb_height) {
>> -        sps->frame_cropping_flag = 1;
>> -
>> -        sps->frame_crop_left_offset   = 0;
>> -        sps->frame_crop_right_offset  =
>> -            (16 * priv->mb_width - avctx->width) / 2;
>> -        sps->frame_crop_top_offset    = 0;
>> -        sps->frame_crop_bottom_offset =
>> -            (16 * priv->mb_height - avctx->height) / 2;
>> -    } else {
>> -        sps->frame_cropping_flag = 0;
>> -    }
>> -
>> -    sps->vui_parameters_present_flag = 1;
>> -
>> -    if (avctx->sample_aspect_ratio.num != 0 &&
>> -        avctx->sample_aspect_ratio.den != 0) {
>> -        int num, den, i;
>> -        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>> -                  avctx->sample_aspect_ratio.den, 65535);
>> -        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>> -            if (num == ff_h2645_pixel_aspect[i].num &&
>> -                den == ff_h2645_pixel_aspect[i].den) {
>> -                sps->vui.aspect_ratio_idc = i;
>> -                break;
>> -            }
>> -        }
>> -        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>> -            sps->vui.aspect_ratio_idc = 255;
>> -            sps->vui.sar_width  = num;
>> -            sps->vui.sar_height = den;
>> -        }
>> -        sps->vui.aspect_ratio_info_present_flag = 1;
>> -    }
>> -
>> -    // Unspecified video format, from table E-2.
>> -    sps->vui.video_format             = 5;
>> -    sps->vui.video_full_range_flag    =
>> -        avctx->color_range == AVCOL_RANGE_JPEG;
>> -    sps->vui.colour_primaries         = avctx->color_primaries;
>> -    sps->vui.transfer_characteristics = avctx->color_trc;
>> -    sps->vui.matrix_coefficients      = avctx->colorspace;
>> -    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>> -        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>> -        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>> -        sps->vui.colour_description_present_flag = 1;
>> -    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>> -        sps->vui.colour_description_present_flag)
>> -        sps->vui.video_signal_type_present_flag = 1;
>> -
>> -    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>> -        sps->vui.chroma_loc_info_present_flag = 1;
>> -        sps->vui.chroma_sample_loc_type_top_field    =
>> -        sps->vui.chroma_sample_loc_type_bottom_field =
>> -            avctx->chroma_sample_location - 1;
>> -    }
>> -
>> -    sps->vui.timing_info_present_flag = 1;
>> -    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>> -        sps->vui.num_units_in_tick = avctx->framerate.den;
>> -        sps->vui.time_scale        = 2 * avctx->framerate.num;
>> -        sps->vui.fixed_frame_rate_flag = 1;
>> -    } else {
>> -        sps->vui.num_units_in_tick = avctx->time_base.num;
>> -        sps->vui.time_scale        = 2 * avctx->time_base.den;
>> -        sps->vui.fixed_frame_rate_flag = 0;
>> -    }
>> -
>> -    if (priv->sei & SEI_TIMING) {
>> -        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>> -        H264RawSEIBufferingPeriod *bp = &priv->sei_buffering_period;
>> -
>> -        sps->vui.nal_hrd_parameters_present_flag = 1;
>> -
>> -        hrd->cpb_cnt_minus1 = 0;
>> -
>> -        // Try to scale these to a sensible range so that the
>> -        // golomb encode of the value is not overlong.
>> -        hrd->bit_rate_scale =
>> -            av_clip_uintp2(av_log2(ctx->va_bit_rate) - 15 - 6, 4);
>> -        hrd->bit_rate_value_minus1[0] =
>> -            (ctx->va_bit_rate >> hrd->bit_rate_scale + 6) - 1;
>> -
>> -        hrd->cpb_size_scale =
>> -            av_clip_uintp2(av_log2(ctx->hrd_params.buffer_size) - 15 - 4, 4);
>> -        hrd->cpb_size_value_minus1[0] =
>> -            (ctx->hrd_params.buffer_size >> hrd->cpb_size_scale + 4) - 1;
>> -
>> -        // CBR mode as defined for the HRD cannot be achieved without filler
>> -        // data, so this flag cannot be set even with VAAPI CBR modes.
>> -        hrd->cbr_flag[0] = 0;
>>
>> -        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>> -        hrd->cpb_removal_delay_length_minus1         = 23;
>> -        hrd->dpb_output_delay_length_minus1          = 7;
>> -        hrd->time_offset_length                      = 0;
>> -
>> -        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>> -
>> -        // This calculation can easily overflow 32 bits.
>> -        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>> -            (uint64_t)ctx->hrd_params.initial_buffer_fullness /
>> -            ctx->hrd_params.buffer_size;
>> -        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>> -    } else {
>> -        sps->vui.nal_hrd_parameters_present_flag = 0;
>> -        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>> -    }
>> -
>> -    sps->vui.bitstream_restriction_flag    = 1;
>> -    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>> -    sps->vui.log2_max_mv_length_horizontal = 15;
>> -    sps->vui.log2_max_mv_length_vertical   = 15;
>> -    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>> -    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>> -
>> -    pps->nal_unit_header.nal_ref_idc = 3;
>> -    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>> -
>> -    pps->pic_parameter_set_id = 0;
>> -    pps->seq_parameter_set_id = 0;
>> -
>> -    pps->entropy_coding_mode_flag =
>> -        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>> -          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>> -          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>> -    if (!priv->coder && pps->entropy_coding_mode_flag)
>> -        pps->entropy_coding_mode_flag = 0;
>> -
>> -    pps->num_ref_idx_l0_default_active_minus1 = 0;
>> -    pps->num_ref_idx_l1_default_active_minus1 = 0;
>> -
>> -    pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26;
>> -
>> -    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>> -        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>> -        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>> -        pps->more_rbsp_data = 0;
>> -    } else {
>> -        pps->more_rbsp_data = 1;
>> +    FFHWBaseEncodeH264Opts unit_opts = {
>> +        .flags = (priv->sei & SEI_TIMING) ? FF_HW_H264_SEI_TIMING : 0,
>> +        .cabac = priv->coder,
>> +        .hrd_buffer_size = ctx->hrd_params.buffer_size,
>> +        .fixed_qp_idr = priv->fixed_qp_idr,
>> +        .initial_buffer_fullness = ctx->hrd_params.initial_buffer_fullness,
>> +        .bit_rate = ctx->va_bit_rate,
>> +    };
>>
>> -        pps->transform_8x8_mode_flag = 1;
>> -    }
>> +    int err = ff_hw_base_encode_init_params_h264(base_ctx, avctx,
>> +                                                 &priv->units, &unit_opts);
>> +    if (err < 0)
>> +        return err;
>>
>>      *vseq = (VAEncSequenceParameterBufferH264) {
>>          .seq_parameter_set_id = sps->seq_parameter_set_id, @@ -660,7 +442,7
>> @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
>>          }
>>      }
>>      hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame;
>> -    if (priv->raw_sps.pic_order_cnt_type == 2) {
>> +    if (priv->units.raw_sps.pic_order_cnt_type == 2) {
>>          hpic->pic_order_cnt *= 2;
>>      }
>>
>> @@ -870,8 +652,8 @@ static int
>> vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>>      VAAPIEncodePicture         *vaapi_pic = pic->priv;
>>      VAAPIEncodeH264Picture          *hpic = pic->codec_priv;
>>      FFHWBaseEncodePicture           *prev = pic->prev;
>> -    H264RawSPS                       *sps = &priv->raw_sps;
>> -    H264RawPPS                       *pps = &priv->raw_pps;
>> +    H264RawSPS                       *sps = &priv->units.raw_sps;
>> +    H264RawPPS                       *pps = &priv->units.raw_pps;
>>      H264RawSliceHeader                *sh = &priv->raw_slice.header;
>>      VAEncPictureParameterBufferH264 *vpic = vaapi_pic->codec_picture_params;
>>      VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; @@ -
>> 923,7 +705,7 @@ static int
>> vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>>                  ++keep;
>>              }
>>          }
>> -        av_assert0(keep <= priv->dpb_frames);
>> +        av_assert0(keep <= priv->units.dpb_frames);
>>
>>          if (discard == 0) {
>>              sh->adaptive_ref_pic_marking_mode_flag = 0;
>> --
> 
> Are you planning to move more codecs to shared file such as hevc? Since some flags are based on the query result of hardware specific API, d3d12 may not align with the constructors in shared file.

Probably, for HEVC but later on. Not likely to do it for AV1 as its much 
shorter and easier to construct yourself.

Its the same story with Vulkan, where some unit features may be 
overridden. I solve this issue by running *this* common function to 
construct optimal units, converting them to Vulkan units, letting Vulkan 
write out its SPS/PPS unit bitstream, *decoding* the output units back 
to CBS native units, copying the overridden parts that matter (such as 
CABAC, loopfilter bits and so on) from the Vulkan units, and then using 
CBS to encode the final units.

Thankfully, the CBS framework makes this much easier than it sounds, and 
since all of this only occurs during initialization (you can append 
other units such as AUD during runthime), its essentially free.

You should really consider this for D3D12. I discovered issues in every 
single vulkan driver when writing out units, so you shouldn't trust them 
either and write your own.

Also, Vulkan requires you to use filler units to pad the unit bitstream 
to a specific alignment, which you cannot do with using the native 
Vulkan driver written units, as there's no syntax for fillers. This 
requires you to copy the written slices, which is IMO a hundred times 
worse than just writing out your own units.

We can discuss HEVC later on, for now what do you think of this patch?
Tong Wu Sept. 6, 2024, 9:48 a.m. UTC | #3
Lynne:
>To: Tong Wu <wutong1208@outlook.com>; FFmpeg development discussions and
>patches <ffmpeg-devel@ffmpeg.org>
>Subject: Re: [FFmpeg-devel] [PATCH 02/10] hw_base_encode: move VAAPI
>SPS/PPS constructors to a shared file
>
>On 04/09/2024 16:09, Tong Wu wrote:
>> Lynne:
>>> Subject: [FFmpeg-devel] [PATCH 02/10] hw_base_encode: move VAAPI
>>> SPS/PPS constructors to a shared file
>>>
>>> ---
>>> libavcodec/Makefile              |   2 +-
>>> libavcodec/hw_base_encode_h264.c | 265
>>> +++++++++++++++++++++++++++++++  libavcodec/hw_base_encode_h264.h |
>>> +++++++++++++++++++++++++++++++ 53
>>> +++++++
>>> libavcodec/vaapi_encode_h264.c   | 262 +++---------------------------
>>> 4 files changed, 341 insertions(+), 241 deletions(-)  create mode
>>> 100644 libavcodec/hw_base_encode_h264.c  create mode 100644
>>> libavcodec/hw_base_encode_h264.h
>>>
>>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile index
>>> 3b4b8681f5..2e53dd723a 100644
>>> --- a/libavcodec/Makefile
>>> +++ b/libavcodec/Makefile
>>> @@ -166,7 +166,7 @@ OBJS-$(CONFIG_STARTCODE)               += startcode.o
>>> OBJS-$(CONFIG_TEXTUREDSP)              += texturedsp.o
>>> OBJS-$(CONFIG_TEXTUREDSPENC)           += texturedspenc.o
>>> OBJS-$(CONFIG_TPELDSP)                 += tpeldsp.o
>>> -OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o
>hw_base_encode.o
>>> +OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o
>hw_base_encode.o
>>> hw_base_encode_h264.o
>>> OBJS-$(CONFIG_AV1_AMF_ENCODER)         += amfenc_av1.o
>>> OBJS-$(CONFIG_VC1DSP)                  += vc1dsp.o
>>> OBJS-$(CONFIG_VIDEODSP)                += videodsp.o
>>> diff --git a/libavcodec/hw_base_encode_h264.c
>>> b/libavcodec/hw_base_encode_h264.c
>>> new file mode 100644
>>> index 0000000000..5c3957cddb
>>> --- /dev/null
>>> +++ b/libavcodec/hw_base_encode_h264.c
>>> @@ -0,0 +1,265 @@
>>> +/*
>>> + * This file is part of FFmpeg.
>>> + *
>>> + * FFmpeg is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * FFmpeg is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with FFmpeg; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>>> +02110-1301 USA  */
>>> +
>>> +#include "hw_base_encode_h264.h"
>>> +
>>> +#include "h2645data.h"
>>> +#include "h264_levels.h"
>>> +
>>> +#include "libavutil/pixdesc.h"
>>> +
>>> +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext
>*base_ctx,
>>> +                                       AVCodecContext *avctx,
>>> +                                       FFHWBaseEncodeH264 *common,
>>> +                                       FFHWBaseEncodeH264Opts *opts) {
>>> +    H264RawSPS *sps = &common->raw_sps;
>>> +    H264RawPPS *pps = &common->raw_pps;
>>> +    const AVPixFmtDescriptor *desc;
>>> +    int bit_depth;
>>> +
>>> +    memset(sps, 0, sizeof(*sps));
>>> +    memset(pps, 0, sizeof(*pps));
>>> +
>>> +    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>>> +    av_assert0(desc);
>>> +    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 ||
>>> + desc-
>>>> log2_chroma_h != 1) {
>>> +        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>>> +                "%s is not supported.\n", desc->name);
>>> +        return AVERROR(EINVAL);
>>> +    }
>>> +    bit_depth = desc->comp[0].depth;
>>> +
>>> +    sps->nal_unit_header.nal_ref_idc   = 3;
>>> +    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>>> +
>>> +    sps->profile_idc = avctx->profile & 0xff;
>>> +
>>> +    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>>> +        avctx->profile == AV_PROFILE_H264_MAIN)
>>> +        sps->constraint_set1_flag = 1;
>>> +
>>> +    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>> AV_PROFILE_H264_HIGH_10)
>>> +        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>>> +
>>> +    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>>> +        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>> AV_PROFILE_H264_HIGH_10) {
>>> +        sps->constraint_set4_flag = 1;
>>> +        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>>> +    }
>>> +
>>> +    if (base_ctx->gop_size == 1)
>>> +        common->dpb_frames = 0;
>>> +    else
>>> +        common->dpb_frames = 1 + base_ctx->max_b_depth;
>>> +
>>> +    if (avctx->level != AV_LEVEL_UNKNOWN) {
>>> +        sps->level_idc = avctx->level;
>>> +    } else {
>>> +        const H264LevelDescriptor *level;
>>> +        int framerate;
>>> +
>>> +        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>>> +            framerate = avctx->framerate.num / avctx->framerate.den;
>>> +        else
>>> +            framerate = 0;
>>> +
>>> +        level = ff_h264_guess_level(sps->profile_idc,
>>> +                                    opts->bit_rate,
>>> +                                    framerate,
>>> +                                    common->mb_width  * 16,
>>> +                                    common->mb_height * 16,
>>> +                                    common->dpb_frames);
>>> +        if (level) {
>>> +            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>>> +            if (level->constraint_set3_flag)
>>> +                sps->constraint_set3_flag = 1;
>>> +            sps->level_idc = level->level_idc;
>>> +        } else {
>>> +            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>>> +                   "to any level: using level 6.2.\n");
>>> +            sps->level_idc = 62;
>>> +        }
>>> +    }
>>> +
>>> +    sps->seq_parameter_set_id = 0;
>>> +    sps->chroma_format_idc    = 1;
>>> +    sps->bit_depth_luma_minus8 = bit_depth - 8;
>>> +    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>>> +
>>> +    sps->log2_max_frame_num_minus4 = 4;
>>> +    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>>> +    if (sps->pic_order_cnt_type == 0) {
>>> +        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>>> +    }
>>> +
>>> +    sps->max_num_ref_frames = common->dpb_frames;
>>> +
>>> +    sps->pic_width_in_mbs_minus1        = common->mb_width  - 1;
>>> +    sps->pic_height_in_map_units_minus1 = common->mb_height - 1;
>>> +
>>> +    sps->frame_mbs_only_flag = 1;
>>> +    sps->direct_8x8_inference_flag = 1;
>>> +
>>> +    if (avctx->width  != 16 * common->mb_width ||
>>> +        avctx->height != 16 * common->mb_height) {
>>> +        sps->frame_cropping_flag = 1;
>>> +
>>> +        sps->frame_crop_left_offset   = 0;
>>> +        sps->frame_crop_right_offset  =
>>> +            (16 * common->mb_width - avctx->width) / 2;
>>> +        sps->frame_crop_top_offset    = 0;
>>> +        sps->frame_crop_bottom_offset =
>>> +            (16 * common->mb_height - avctx->height) / 2;
>>> +    } else {
>>> +        sps->frame_cropping_flag = 0;
>>> +    }
>>> +
>>> +    sps->vui_parameters_present_flag = 1;
>>> +
>>> +    if (avctx->sample_aspect_ratio.num != 0 &&
>>> +        avctx->sample_aspect_ratio.den != 0) {
>>> +        int num, den, i;
>>> +        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>>> +                  avctx->sample_aspect_ratio.den, 65535);
>>> +        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>>> +            if (num == ff_h2645_pixel_aspect[i].num &&
>>> +                den == ff_h2645_pixel_aspect[i].den) {
>>> +                sps->vui.aspect_ratio_idc = i;
>>> +                break;
>>> +            }
>>> +        }
>>> +        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>>> +            sps->vui.aspect_ratio_idc = 255;
>>> +            sps->vui.sar_width  = num;
>>> +            sps->vui.sar_height = den;
>>> +        }
>>> +        sps->vui.aspect_ratio_info_present_flag = 1;
>>> +    }
>>> +
>>> +    // Unspecified video format, from table E-2.
>>> +    sps->vui.video_format             = 5;
>>> +    sps->vui.video_full_range_flag    =
>>> +        avctx->color_range == AVCOL_RANGE_JPEG;
>>> +    sps->vui.colour_primaries         = avctx->color_primaries;
>>> +    sps->vui.transfer_characteristics = avctx->color_trc;
>>> +    sps->vui.matrix_coefficients      = avctx->colorspace;
>>> +    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>>> +        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>>> +        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>>> +        sps->vui.colour_description_present_flag = 1;
>>> +    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>>> +        sps->vui.colour_description_present_flag)
>>> +        sps->vui.video_signal_type_present_flag = 1;
>>> +
>>> +    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>>> +        sps->vui.chroma_loc_info_present_flag = 1;
>>> +        sps->vui.chroma_sample_loc_type_top_field    =
>>> +        sps->vui.chroma_sample_loc_type_bottom_field =
>>> +            avctx->chroma_sample_location - 1;
>>> +    }
>>> +
>>> +    sps->vui.timing_info_present_flag = 1;
>>> +    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>>> +        sps->vui.num_units_in_tick = avctx->framerate.den;
>>> +        sps->vui.time_scale        = 2 * avctx->framerate.num;
>>> +        sps->vui.fixed_frame_rate_flag = 1;
>>> +    } else {
>>> +        sps->vui.num_units_in_tick = avctx->time_base.num;
>>> +        sps->vui.time_scale        = 2 * avctx->time_base.den;
>>> +        sps->vui.fixed_frame_rate_flag = 0;
>>> +    }
>>> +
>>> +    if (opts->flags & FF_HW_H264_SEI_TIMING) {
>>> +        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>>> +        H264RawSEIBufferingPeriod *bp =
>>> + &common->sei_buffering_period;
>>> +
>>> +        sps->vui.nal_hrd_parameters_present_flag = 1;
>>> +
>>> +        hrd->cpb_cnt_minus1 = 0;
>>> +
>>> +        // Try to scale these to a sensible range so that the
>>> +        // golomb encode of the value is not overlong.
>>> +        hrd->bit_rate_scale =
>>> +            av_clip_uintp2(av_log2(opts->bit_rate) - 15 - 6, 4);
>>> +        hrd->bit_rate_value_minus1[0] =
>>> +            (opts->bit_rate >> hrd->bit_rate_scale + 6) - 1;
>>> +
>>> +        hrd->cpb_size_scale =
>>> +            av_clip_uintp2(av_log2(opts->hrd_buffer_size) - 15 - 4, 4);
>>> +        hrd->cpb_size_value_minus1[0] =
>>> +            (opts->hrd_buffer_size >> hrd->cpb_size_scale + 4) - 1;
>>> +
>>> +        // CBR mode as defined for the HRD cannot be achieved without filler
>>> +        // data, so this flag cannot be set even with VAAPI CBR modes.
>>> +        hrd->cbr_flag[0] = 0;
>>> +
>>> +        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>>> +        hrd->cpb_removal_delay_length_minus1         = 23;
>>> +        hrd->dpb_output_delay_length_minus1          = 7;
>>> +        hrd->time_offset_length                      = 0;
>>> +
>>> +        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>>> +
>>> +        // This calculation can easily overflow 32 bits.
>>> +        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>>> +            (uint64_t)opts->initial_buffer_fullness /
>>> +            opts->hrd_buffer_size;
>>> +        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>>> +    } else {
>>> +        sps->vui.nal_hrd_parameters_present_flag = 0;
>>> +        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>>> +    }
>>> +
>>> +    sps->vui.bitstream_restriction_flag    = 1;
>>> +    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>>> +    sps->vui.log2_max_mv_length_horizontal = 15;
>>> +    sps->vui.log2_max_mv_length_vertical   = 15;
>>> +    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>>> +    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>>> +
>>> +    pps->nal_unit_header.nal_ref_idc = 3;
>>> +    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>>> +
>>> +    pps->pic_parameter_set_id = 0;
>>> +    pps->seq_parameter_set_id = 0;
>>> +
>>> +    pps->entropy_coding_mode_flag =
>>> +        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>> +          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>> +          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>>> +    if (!opts->cabac && pps->entropy_coding_mode_flag)
>>> +        pps->entropy_coding_mode_flag = 0;
>>> +
>>> +    pps->num_ref_idx_l0_default_active_minus1 = 0;
>>> +    pps->num_ref_idx_l1_default_active_minus1 = 0;
>>> +
>>> +    pps->pic_init_qp_minus26 = opts->fixed_qp_idr - 26;
>>> +
>>> +    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>> +        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>> +        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>>> +        pps->more_rbsp_data = 0;
>>> +    } else {
>>> +        pps->more_rbsp_data = 1;
>>> +
>>> +        pps->transform_8x8_mode_flag = 1;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> diff --git a/libavcodec/hw_base_encode_h264.h
>>> b/libavcodec/hw_base_encode_h264.h
>>> new file mode 100644
>>> index 0000000000..d1bae8f36f
>>> --- /dev/null
>>> +++ b/libavcodec/hw_base_encode_h264.h
>>> @@ -0,0 +1,53 @@
>>> +/*
>>> + * This file is part of FFmpeg.
>>> + *
>>> + * FFmpeg is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * FFmpeg is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with FFmpeg; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>>> +02110-1301 USA  */
>>> +
>>> +#ifndef AVCODEC_HW_BASE_ENCODE_H264_H #define
>>> +AVCODEC_HW_BASE_ENCODE_H264_H
>>> +
>>> +#include "hw_base_encode.h"
>>> +#include "cbs_h264.h"
>>> +
>>> +typedef struct FFHWBaseEncodeH264 {
>>> +    H264RawSPS raw_sps;
>>> +    H264RawPPS raw_pps;
>>> +    H264RawAUD raw_aud;
>>> +
>>> +    H264RawSEIBufferingPeriod sei_buffering_period;
>>> +
>>> +    int dpb_frames;
>>> +    int mb_width;
>>> +    int mb_height;
>>> +} FFHWBaseEncodeH264;
>>> +
>>> +typedef struct FFHWBaseEncodeH264Opts {
>>> +    int flags;
>>> +#define FF_HW_H264_SEI_TIMING (1 << 0)
>>> +
>>> +    int64_t bit_rate;
>>> +    int cabac;
>>> +    int fixed_qp_idr;
>>> +    uint64_t hrd_buffer_size;
>>> +    uint64_t initial_buffer_fullness; } FFHWBaseEncodeH264Opts;
>>> +
>>> +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext
>*base_ctx,
>>> +                                       AVCodecContext *avctx,
>>> +                                       FFHWBaseEncodeH264 *common,
>>> +                                       FFHWBaseEncodeH264Opts
>>> +*opts);
>>> +
>>> +#endif /* AVCODEC_HW_BASE_ENCODE_H264_H */
>>> diff --git a/libavcodec/vaapi_encode_h264.c
>>> b/libavcodec/vaapi_encode_h264.c index 35d3967766..443a569104 100644
>>> --- a/libavcodec/vaapi_encode_h264.c
>>> +++ b/libavcodec/vaapi_encode_h264.c
>>> @@ -33,6 +33,7 @@
>>> #include "cbs_h264.h"
>>> #include "codec_internal.h"
>>> #include "h264.h"
>>> +#include "hw_base_encode_h264.h"
>>> #include "h264_levels.h"
>>> #include "h2645data.h"
>>> #include "vaapi_encode.h"
>>> @@ -67,6 +68,7 @@ typedef struct VAAPIEncodeH264Picture {
>>>
>>> typedef struct VAAPIEncodeH264Context {
>>>      VAAPIEncodeContext common;
>>> +    FFHWBaseEncodeH264 units;
>>>
>>>      // User options.
>>>      int qp;
>>> @@ -85,15 +87,11 @@ typedef struct VAAPIEncodeH264Context {
>>>      int fixed_qp_p;
>>>      int fixed_qp_b;
>>>
>>> -    int dpb_frames;
>>> -
>>>      // Writer structures.
>>>      CodedBitstreamContext *cbc;
>>>      CodedBitstreamFragment current_access_unit;
>>>
>>>      H264RawAUD   raw_aud;
>>> -    H264RawSPS   raw_sps;
>>> -    H264RawPPS   raw_pps;
>>>      H264RawSlice raw_slice;
>>>
>>>      H264RawSEIBufferingPeriod      sei_buffering_period;
>>> @@ -168,11 +166,11 @@ static int
>>> vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx,
>>>          priv->aud_needed = 0;
>>>      }
>>>
>>> -    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_sps);
>>> +    err = vaapi_encode_h264_add_nal(avctx, au,
>>> + &priv->units.raw_sps);
>>>      if (err < 0)
>>>          goto fail;
>>>
>>> -    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_pps);
>>> +    err = vaapi_encode_h264_add_nal(avctx, au,
>>> + &priv->units.raw_pps);
>>>      if (err < 0)
>>>          goto fail;
>>>
>>> @@ -298,240 +296,24 @@ static int
>>> vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
>>>      FFHWBaseEncodeContext        *base_ctx = avctx->priv_data;
>>>      VAAPIEncodeContext                *ctx = avctx->priv_data;
>>>      VAAPIEncodeH264Context           *priv = avctx->priv_data;
>>> -    H264RawSPS                        *sps = &priv->raw_sps;
>>> -    H264RawPPS                        *pps = &priv->raw_pps;
>>> +    H264RawSPS                        *sps = &priv->units.raw_sps;
>>> +    H264RawPPS                        *pps = &priv->units.raw_pps;
>>>      VAEncSequenceParameterBufferH264 *vseq = ctx-
>>codec_sequence_params;
>>>      VAEncPictureParameterBufferH264  *vpic = ctx->codec_picture_params;
>>> -    const AVPixFmtDescriptor *desc;
>>> -    int bit_depth;
>>> -
>>> -    memset(sps, 0, sizeof(*sps));
>>> -    memset(pps, 0, sizeof(*pps));
>>> -
>>> -    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>>> -    av_assert0(desc);
>>> -    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc-
>>>> log2_chroma_h != 1) {
>>> -        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>>> -                "%s is not supported.\n", desc->name);
>>> -        return AVERROR(EINVAL);
>>> -    }
>>> -    bit_depth = desc->comp[0].depth;
>>> -
>>> -    sps->nal_unit_header.nal_ref_idc   = 3;
>>> -    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>>> -
>>> -    sps->profile_idc = avctx->profile & 0xff;
>>> -
>>> -    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>>> -        avctx->profile == AV_PROFILE_H264_MAIN)
>>> -        sps->constraint_set1_flag = 1;
>>> -
>>> -    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>> AV_PROFILE_H264_HIGH_10)
>>> -        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>>> -
>>> -    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>>> -        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>> AV_PROFILE_H264_HIGH_10) {
>>> -        sps->constraint_set4_flag = 1;
>>> -        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>>> -    }
>>> -
>>> -    if (base_ctx->gop_size == 1)
>>> -        priv->dpb_frames = 0;
>>> -    else
>>> -        priv->dpb_frames = 1 + base_ctx->max_b_depth;
>>> -
>>> -    if (avctx->level != AV_LEVEL_UNKNOWN) {
>>> -        sps->level_idc = avctx->level;
>>> -    } else {
>>> -        const H264LevelDescriptor *level;
>>> -        int framerate;
>>> -
>>> -        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>>> -            framerate = avctx->framerate.num / avctx->framerate.den;
>>> -        else
>>> -            framerate = 0;
>>> -
>>> -        level = ff_h264_guess_level(sps->profile_idc,
>>> -                                    avctx->bit_rate,
>>> -                                    framerate,
>>> -                                    priv->mb_width  * 16,
>>> -                                    priv->mb_height * 16,
>>> -                                    priv->dpb_frames);
>>> -        if (level) {
>>> -            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>>> -            if (level->constraint_set3_flag)
>>> -                sps->constraint_set3_flag = 1;
>>> -            sps->level_idc = level->level_idc;
>>> -        } else {
>>> -            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>>> -                   "to any level: using level 6.2.\n");
>>> -            sps->level_idc = 62;
>>> -        }
>>> -    }
>>> -
>>> -    sps->seq_parameter_set_id = 0;
>>> -    sps->chroma_format_idc    = 1;
>>> -    sps->bit_depth_luma_minus8 = bit_depth - 8;
>>> -    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>>> -
>>> -    sps->log2_max_frame_num_minus4 = 4;
>>> -    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>>> -    if (sps->pic_order_cnt_type == 0) {
>>> -        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>>> -    }
>>> -
>>> -    sps->max_num_ref_frames = priv->dpb_frames;
>>> -
>>> -    sps->pic_width_in_mbs_minus1        = priv->mb_width  - 1;
>>> -    sps->pic_height_in_map_units_minus1 = priv->mb_height - 1;
>>> -
>>> -    sps->frame_mbs_only_flag = 1;
>>> -    sps->direct_8x8_inference_flag = 1;
>>> -
>>> -    if (avctx->width  != 16 * priv->mb_width ||
>>> -        avctx->height != 16 * priv->mb_height) {
>>> -        sps->frame_cropping_flag = 1;
>>> -
>>> -        sps->frame_crop_left_offset   = 0;
>>> -        sps->frame_crop_right_offset  =
>>> -            (16 * priv->mb_width - avctx->width) / 2;
>>> -        sps->frame_crop_top_offset    = 0;
>>> -        sps->frame_crop_bottom_offset =
>>> -            (16 * priv->mb_height - avctx->height) / 2;
>>> -    } else {
>>> -        sps->frame_cropping_flag = 0;
>>> -    }
>>> -
>>> -    sps->vui_parameters_present_flag = 1;
>>> -
>>> -    if (avctx->sample_aspect_ratio.num != 0 &&
>>> -        avctx->sample_aspect_ratio.den != 0) {
>>> -        int num, den, i;
>>> -        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>>> -                  avctx->sample_aspect_ratio.den, 65535);
>>> -        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>>> -            if (num == ff_h2645_pixel_aspect[i].num &&
>>> -                den == ff_h2645_pixel_aspect[i].den) {
>>> -                sps->vui.aspect_ratio_idc = i;
>>> -                break;
>>> -            }
>>> -        }
>>> -        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>>> -            sps->vui.aspect_ratio_idc = 255;
>>> -            sps->vui.sar_width  = num;
>>> -            sps->vui.sar_height = den;
>>> -        }
>>> -        sps->vui.aspect_ratio_info_present_flag = 1;
>>> -    }
>>> -
>>> -    // Unspecified video format, from table E-2.
>>> -    sps->vui.video_format             = 5;
>>> -    sps->vui.video_full_range_flag    =
>>> -        avctx->color_range == AVCOL_RANGE_JPEG;
>>> -    sps->vui.colour_primaries         = avctx->color_primaries;
>>> -    sps->vui.transfer_characteristics = avctx->color_trc;
>>> -    sps->vui.matrix_coefficients      = avctx->colorspace;
>>> -    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>>> -        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>>> -        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>>> -        sps->vui.colour_description_present_flag = 1;
>>> -    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>>> -        sps->vui.colour_description_present_flag)
>>> -        sps->vui.video_signal_type_present_flag = 1;
>>> -
>>> -    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>>> -        sps->vui.chroma_loc_info_present_flag = 1;
>>> -        sps->vui.chroma_sample_loc_type_top_field    =
>>> -        sps->vui.chroma_sample_loc_type_bottom_field =
>>> -            avctx->chroma_sample_location - 1;
>>> -    }
>>> -
>>> -    sps->vui.timing_info_present_flag = 1;
>>> -    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>>> -        sps->vui.num_units_in_tick = avctx->framerate.den;
>>> -        sps->vui.time_scale        = 2 * avctx->framerate.num;
>>> -        sps->vui.fixed_frame_rate_flag = 1;
>>> -    } else {
>>> -        sps->vui.num_units_in_tick = avctx->time_base.num;
>>> -        sps->vui.time_scale        = 2 * avctx->time_base.den;
>>> -        sps->vui.fixed_frame_rate_flag = 0;
>>> -    }
>>> -
>>> -    if (priv->sei & SEI_TIMING) {
>>> -        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>>> -        H264RawSEIBufferingPeriod *bp = &priv->sei_buffering_period;
>>> -
>>> -        sps->vui.nal_hrd_parameters_present_flag = 1;
>>> -
>>> -        hrd->cpb_cnt_minus1 = 0;
>>> -
>>> -        // Try to scale these to a sensible range so that the
>>> -        // golomb encode of the value is not overlong.
>>> -        hrd->bit_rate_scale =
>>> -            av_clip_uintp2(av_log2(ctx->va_bit_rate) - 15 - 6, 4);
>>> -        hrd->bit_rate_value_minus1[0] =
>>> -            (ctx->va_bit_rate >> hrd->bit_rate_scale + 6) - 1;
>>> -
>>> -        hrd->cpb_size_scale =
>>> -            av_clip_uintp2(av_log2(ctx->hrd_params.buffer_size) - 15 - 4, 4);
>>> -        hrd->cpb_size_value_minus1[0] =
>>> -            (ctx->hrd_params.buffer_size >> hrd->cpb_size_scale + 4) - 1;
>>> -
>>> -        // CBR mode as defined for the HRD cannot be achieved without filler
>>> -        // data, so this flag cannot be set even with VAAPI CBR modes.
>>> -        hrd->cbr_flag[0] = 0;
>>>
>>> -        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>>> -        hrd->cpb_removal_delay_length_minus1         = 23;
>>> -        hrd->dpb_output_delay_length_minus1          = 7;
>>> -        hrd->time_offset_length                      = 0;
>>> -
>>> -        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>>> -
>>> -        // This calculation can easily overflow 32 bits.
>>> -        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>>> -            (uint64_t)ctx->hrd_params.initial_buffer_fullness /
>>> -            ctx->hrd_params.buffer_size;
>>> -        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>>> -    } else {
>>> -        sps->vui.nal_hrd_parameters_present_flag = 0;
>>> -        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>>> -    }
>>> -
>>> -    sps->vui.bitstream_restriction_flag    = 1;
>>> -    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>>> -    sps->vui.log2_max_mv_length_horizontal = 15;
>>> -    sps->vui.log2_max_mv_length_vertical   = 15;
>>> -    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>>> -    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>>> -
>>> -    pps->nal_unit_header.nal_ref_idc = 3;
>>> -    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>>> -
>>> -    pps->pic_parameter_set_id = 0;
>>> -    pps->seq_parameter_set_id = 0;
>>> -
>>> -    pps->entropy_coding_mode_flag =
>>> -        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>> -          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>> -          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>>> -    if (!priv->coder && pps->entropy_coding_mode_flag)
>>> -        pps->entropy_coding_mode_flag = 0;
>>> -
>>> -    pps->num_ref_idx_l0_default_active_minus1 = 0;
>>> -    pps->num_ref_idx_l1_default_active_minus1 = 0;
>>> -
>>> -    pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26;
>>> -
>>> -    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>> -        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>> -        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>>> -        pps->more_rbsp_data = 0;
>>> -    } else {
>>> -        pps->more_rbsp_data = 1;
>>> +    FFHWBaseEncodeH264Opts unit_opts = {
>>> +        .flags = (priv->sei & SEI_TIMING) ? FF_HW_H264_SEI_TIMING : 0,
>>> +        .cabac = priv->coder,
>>> +        .hrd_buffer_size = ctx->hrd_params.buffer_size,
>>> +        .fixed_qp_idr = priv->fixed_qp_idr,
>>> +        .initial_buffer_fullness = ctx->hrd_params.initial_buffer_fullness,
>>> +        .bit_rate = ctx->va_bit_rate,
>>> +    };
>>>
>>> -        pps->transform_8x8_mode_flag = 1;
>>> -    }
>>> +    int err = ff_hw_base_encode_init_params_h264(base_ctx, avctx,
>>> +                                                 &priv->units, &unit_opts);
>>> +    if (err < 0)
>>> +        return err;
>>>
>>>      *vseq = (VAEncSequenceParameterBufferH264) {
>>>          .seq_parameter_set_id = sps->seq_parameter_set_id, @@ -660,7
>>> +442,7 @@ static int
>vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
>>>          }
>>>      }
>>>      hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame;
>>> -    if (priv->raw_sps.pic_order_cnt_type == 2) {
>>> +    if (priv->units.raw_sps.pic_order_cnt_type == 2) {
>>>          hpic->pic_order_cnt *= 2;
>>>      }
>>>
>>> @@ -870,8 +652,8 @@ static int
>>> vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>>>      VAAPIEncodePicture         *vaapi_pic = pic->priv;
>>>      VAAPIEncodeH264Picture          *hpic = pic->codec_priv;
>>>      FFHWBaseEncodePicture           *prev = pic->prev;
>>> -    H264RawSPS                       *sps = &priv->raw_sps;
>>> -    H264RawPPS                       *pps = &priv->raw_pps;
>>> +    H264RawSPS                       *sps = &priv->units.raw_sps;
>>> +    H264RawPPS                       *pps = &priv->units.raw_pps;
>>>      H264RawSliceHeader                *sh = &priv->raw_slice.header;
>>>      VAEncPictureParameterBufferH264 *vpic = vaapi_pic-
>>codec_picture_params;
>>>      VAEncSliceParameterBufferH264 *vslice =
>>> slice->codec_slice_params; @@ -
>>> 923,7 +705,7 @@ static int
>>> vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>>>                  ++keep;
>>>              }
>>>          }
>>> -        av_assert0(keep <= priv->dpb_frames);
>>> +        av_assert0(keep <= priv->units.dpb_frames);
>>>
>>>          if (discard == 0) {
>>>              sh->adaptive_ref_pic_marking_mode_flag = 0;
>>> --
>>
>> Are you planning to move more codecs to shared file such as hevc? Since some
>flags are based on the query result of hardware specific API, d3d12 may not align
>with the constructors in shared file.
>
>Probably, for HEVC but later on. Not likely to do it for AV1 as its much shorter and
>easier to construct yourself.
>
>Its the same story with Vulkan, where some unit features may be overridden. I
>solve this issue by running *this* common function to construct optimal units,
>converting them to Vulkan units, letting Vulkan write out its SPS/PPS unit
>bitstream, *decoding* the output units back to CBS native units, copying the
>overridden parts that matter (such as CABAC, loopfilter bits and so on) from the
>Vulkan units, and then using CBS to encode the final units.

For D3D12 HEVC and H264 (AV1 not included), it is fully user's responsibility to write out and generate the SPS/PPS coded units, which do not even go through driver. Driver only cares about the D3D12 structures which are filled out by users. That looks simpler than Vulkan.

>
>Thankfully, the CBS framework makes this much easier than it sounds, and since all
>of this only occurs during initialization (you can append other units such as AUD
>during runthime), its essentially free.
>
>You should really consider this for D3D12. I discovered issues in every single vulkan
>driver when writing out units, so you shouldn't trust them either and write your
>own.
>
>Also, Vulkan requires you to use filler units to pad the unit bitstream to a specific
>alignment, which you cannot do with using the native Vulkan driver written units,
>as there's no syntax for fillers. This requires you to copy the written slices, which is
>IMO a hundred times worse than just writing out your own units.
>
>We can discuss HEVC later on, for now what do you think of this patch?


What I meant was in both D3D12 HEVC and VAAPI HEVC we enabled some of the flags in PPS according to the D3D12/VAAPI specific structures queried from driver, which might be unique and hard to share. Anyways we could discuss later. I don't see we have such issue in h264 so I guess this patch is ok for me.
Lynne Sept. 6, 2024, 1:29 p.m. UTC | #4
On 06/09/2024 11:48, Tong Wu wrote:
> Lynne:
>> To: Tong Wu <wutong1208@outlook.com>; FFmpeg development discussions and
>> patches <ffmpeg-devel@ffmpeg.org>
>> Subject: Re: [FFmpeg-devel] [PATCH 02/10] hw_base_encode: move VAAPI
>> SPS/PPS constructors to a shared file
>>
>> On 04/09/2024 16:09, Tong Wu wrote:
>>> Lynne:
>>>> Subject: [FFmpeg-devel] [PATCH 02/10] hw_base_encode: move VAAPI
>>>> SPS/PPS constructors to a shared file
>>>>
>>>> ---
>>>> libavcodec/Makefile              |   2 +-
>>>> libavcodec/hw_base_encode_h264.c | 265
>>>> +++++++++++++++++++++++++++++++  libavcodec/hw_base_encode_h264.h |
>>>> +++++++++++++++++++++++++++++++ 53
>>>> +++++++
>>>> libavcodec/vaapi_encode_h264.c   | 262 +++---------------------------
>>>> 4 files changed, 341 insertions(+), 241 deletions(-)  create mode
>>>> 100644 libavcodec/hw_base_encode_h264.c  create mode 100644
>>>> libavcodec/hw_base_encode_h264.h
>>>>
>>>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile index
>>>> 3b4b8681f5..2e53dd723a 100644
>>>> --- a/libavcodec/Makefile
>>>> +++ b/libavcodec/Makefile
>>>> @@ -166,7 +166,7 @@ OBJS-$(CONFIG_STARTCODE)               += startcode.o
>>>> OBJS-$(CONFIG_TEXTUREDSP)              += texturedsp.o
>>>> OBJS-$(CONFIG_TEXTUREDSPENC)           += texturedspenc.o
>>>> OBJS-$(CONFIG_TPELDSP)                 += tpeldsp.o
>>>> -OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o
>> hw_base_encode.o
>>>> +OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o
>> hw_base_encode.o
>>>> hw_base_encode_h264.o
>>>> OBJS-$(CONFIG_AV1_AMF_ENCODER)         += amfenc_av1.o
>>>> OBJS-$(CONFIG_VC1DSP)                  += vc1dsp.o
>>>> OBJS-$(CONFIG_VIDEODSP)                += videodsp.o
>>>> diff --git a/libavcodec/hw_base_encode_h264.c
>>>> b/libavcodec/hw_base_encode_h264.c
>>>> new file mode 100644
>>>> index 0000000000..5c3957cddb
>>>> --- /dev/null
>>>> +++ b/libavcodec/hw_base_encode_h264.c
>>>> @@ -0,0 +1,265 @@
>>>> +/*
>>>> + * This file is part of FFmpeg.
>>>> + *
>>>> + * FFmpeg is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU Lesser General Public
>>>> + * License as published by the Free Software Foundation; either
>>>> + * version 2.1 of the License, or (at your option) any later version.
>>>> + *
>>>> + * FFmpeg is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> + * Lesser General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU Lesser General Public
>>>> + * License along with FFmpeg; if not, write to the Free Software
>>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>>>> +02110-1301 USA  */
>>>> +
>>>> +#include "hw_base_encode_h264.h"
>>>> +
>>>> +#include "h2645data.h"
>>>> +#include "h264_levels.h"
>>>> +
>>>> +#include "libavutil/pixdesc.h"
>>>> +
>>>> +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext
>> *base_ctx,
>>>> +                                       AVCodecContext *avctx,
>>>> +                                       FFHWBaseEncodeH264 *common,
>>>> +                                       FFHWBaseEncodeH264Opts *opts) {
>>>> +    H264RawSPS *sps = &common->raw_sps;
>>>> +    H264RawPPS *pps = &common->raw_pps;
>>>> +    const AVPixFmtDescriptor *desc;
>>>> +    int bit_depth;
>>>> +
>>>> +    memset(sps, 0, sizeof(*sps));
>>>> +    memset(pps, 0, sizeof(*pps));
>>>> +
>>>> +    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>>>> +    av_assert0(desc);
>>>> +    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 ||
>>>> + desc-
>>>>> log2_chroma_h != 1) {
>>>> +        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>>>> +                "%s is not supported.\n", desc->name);
>>>> +        return AVERROR(EINVAL);
>>>> +    }
>>>> +    bit_depth = desc->comp[0].depth;
>>>> +
>>>> +    sps->nal_unit_header.nal_ref_idc   = 3;
>>>> +    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>>>> +
>>>> +    sps->profile_idc = avctx->profile & 0xff;
>>>> +
>>>> +    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>>>> +        avctx->profile == AV_PROFILE_H264_MAIN)
>>>> +        sps->constraint_set1_flag = 1;
>>>> +
>>>> +    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>>> AV_PROFILE_H264_HIGH_10)
>>>> +        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>>>> +
>>>> +    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>>>> +        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>>> AV_PROFILE_H264_HIGH_10) {
>>>> +        sps->constraint_set4_flag = 1;
>>>> +        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>>>> +    }
>>>> +
>>>> +    if (base_ctx->gop_size == 1)
>>>> +        common->dpb_frames = 0;
>>>> +    else
>>>> +        common->dpb_frames = 1 + base_ctx->max_b_depth;
>>>> +
>>>> +    if (avctx->level != AV_LEVEL_UNKNOWN) {
>>>> +        sps->level_idc = avctx->level;
>>>> +    } else {
>>>> +        const H264LevelDescriptor *level;
>>>> +        int framerate;
>>>> +
>>>> +        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>>>> +            framerate = avctx->framerate.num / avctx->framerate.den;
>>>> +        else
>>>> +            framerate = 0;
>>>> +
>>>> +        level = ff_h264_guess_level(sps->profile_idc,
>>>> +                                    opts->bit_rate,
>>>> +                                    framerate,
>>>> +                                    common->mb_width  * 16,
>>>> +                                    common->mb_height * 16,
>>>> +                                    common->dpb_frames);
>>>> +        if (level) {
>>>> +            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>>>> +            if (level->constraint_set3_flag)
>>>> +                sps->constraint_set3_flag = 1;
>>>> +            sps->level_idc = level->level_idc;
>>>> +        } else {
>>>> +            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>>>> +                   "to any level: using level 6.2.\n");
>>>> +            sps->level_idc = 62;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    sps->seq_parameter_set_id = 0;
>>>> +    sps->chroma_format_idc    = 1;
>>>> +    sps->bit_depth_luma_minus8 = bit_depth - 8;
>>>> +    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>>>> +
>>>> +    sps->log2_max_frame_num_minus4 = 4;
>>>> +    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>>>> +    if (sps->pic_order_cnt_type == 0) {
>>>> +        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>>>> +    }
>>>> +
>>>> +    sps->max_num_ref_frames = common->dpb_frames;
>>>> +
>>>> +    sps->pic_width_in_mbs_minus1        = common->mb_width  - 1;
>>>> +    sps->pic_height_in_map_units_minus1 = common->mb_height - 1;
>>>> +
>>>> +    sps->frame_mbs_only_flag = 1;
>>>> +    sps->direct_8x8_inference_flag = 1;
>>>> +
>>>> +    if (avctx->width  != 16 * common->mb_width ||
>>>> +        avctx->height != 16 * common->mb_height) {
>>>> +        sps->frame_cropping_flag = 1;
>>>> +
>>>> +        sps->frame_crop_left_offset   = 0;
>>>> +        sps->frame_crop_right_offset  =
>>>> +            (16 * common->mb_width - avctx->width) / 2;
>>>> +        sps->frame_crop_top_offset    = 0;
>>>> +        sps->frame_crop_bottom_offset =
>>>> +            (16 * common->mb_height - avctx->height) / 2;
>>>> +    } else {
>>>> +        sps->frame_cropping_flag = 0;
>>>> +    }
>>>> +
>>>> +    sps->vui_parameters_present_flag = 1;
>>>> +
>>>> +    if (avctx->sample_aspect_ratio.num != 0 &&
>>>> +        avctx->sample_aspect_ratio.den != 0) {
>>>> +        int num, den, i;
>>>> +        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>>>> +                  avctx->sample_aspect_ratio.den, 65535);
>>>> +        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>>>> +            if (num == ff_h2645_pixel_aspect[i].num &&
>>>> +                den == ff_h2645_pixel_aspect[i].den) {
>>>> +                sps->vui.aspect_ratio_idc = i;
>>>> +                break;
>>>> +            }
>>>> +        }
>>>> +        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>>>> +            sps->vui.aspect_ratio_idc = 255;
>>>> +            sps->vui.sar_width  = num;
>>>> +            sps->vui.sar_height = den;
>>>> +        }
>>>> +        sps->vui.aspect_ratio_info_present_flag = 1;
>>>> +    }
>>>> +
>>>> +    // Unspecified video format, from table E-2.
>>>> +    sps->vui.video_format             = 5;
>>>> +    sps->vui.video_full_range_flag    =
>>>> +        avctx->color_range == AVCOL_RANGE_JPEG;
>>>> +    sps->vui.colour_primaries         = avctx->color_primaries;
>>>> +    sps->vui.transfer_characteristics = avctx->color_trc;
>>>> +    sps->vui.matrix_coefficients      = avctx->colorspace;
>>>> +    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>>>> +        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>>>> +        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>>>> +        sps->vui.colour_description_present_flag = 1;
>>>> +    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>>>> +        sps->vui.colour_description_present_flag)
>>>> +        sps->vui.video_signal_type_present_flag = 1;
>>>> +
>>>> +    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>>>> +        sps->vui.chroma_loc_info_present_flag = 1;
>>>> +        sps->vui.chroma_sample_loc_type_top_field    =
>>>> +        sps->vui.chroma_sample_loc_type_bottom_field =
>>>> +            avctx->chroma_sample_location - 1;
>>>> +    }
>>>> +
>>>> +    sps->vui.timing_info_present_flag = 1;
>>>> +    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>>>> +        sps->vui.num_units_in_tick = avctx->framerate.den;
>>>> +        sps->vui.time_scale        = 2 * avctx->framerate.num;
>>>> +        sps->vui.fixed_frame_rate_flag = 1;
>>>> +    } else {
>>>> +        sps->vui.num_units_in_tick = avctx->time_base.num;
>>>> +        sps->vui.time_scale        = 2 * avctx->time_base.den;
>>>> +        sps->vui.fixed_frame_rate_flag = 0;
>>>> +    }
>>>> +
>>>> +    if (opts->flags & FF_HW_H264_SEI_TIMING) {
>>>> +        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>>>> +        H264RawSEIBufferingPeriod *bp =
>>>> + &common->sei_buffering_period;
>>>> +
>>>> +        sps->vui.nal_hrd_parameters_present_flag = 1;
>>>> +
>>>> +        hrd->cpb_cnt_minus1 = 0;
>>>> +
>>>> +        // Try to scale these to a sensible range so that the
>>>> +        // golomb encode of the value is not overlong.
>>>> +        hrd->bit_rate_scale =
>>>> +            av_clip_uintp2(av_log2(opts->bit_rate) - 15 - 6, 4);
>>>> +        hrd->bit_rate_value_minus1[0] =
>>>> +            (opts->bit_rate >> hrd->bit_rate_scale + 6) - 1;
>>>> +
>>>> +        hrd->cpb_size_scale =
>>>> +            av_clip_uintp2(av_log2(opts->hrd_buffer_size) - 15 - 4, 4);
>>>> +        hrd->cpb_size_value_minus1[0] =
>>>> +            (opts->hrd_buffer_size >> hrd->cpb_size_scale + 4) - 1;
>>>> +
>>>> +        // CBR mode as defined for the HRD cannot be achieved without filler
>>>> +        // data, so this flag cannot be set even with VAAPI CBR modes.
>>>> +        hrd->cbr_flag[0] = 0;
>>>> +
>>>> +        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>>>> +        hrd->cpb_removal_delay_length_minus1         = 23;
>>>> +        hrd->dpb_output_delay_length_minus1          = 7;
>>>> +        hrd->time_offset_length                      = 0;
>>>> +
>>>> +        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>>>> +
>>>> +        // This calculation can easily overflow 32 bits.
>>>> +        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>>>> +            (uint64_t)opts->initial_buffer_fullness /
>>>> +            opts->hrd_buffer_size;
>>>> +        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>>>> +    } else {
>>>> +        sps->vui.nal_hrd_parameters_present_flag = 0;
>>>> +        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>>>> +    }
>>>> +
>>>> +    sps->vui.bitstream_restriction_flag    = 1;
>>>> +    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>>>> +    sps->vui.log2_max_mv_length_horizontal = 15;
>>>> +    sps->vui.log2_max_mv_length_vertical   = 15;
>>>> +    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>>>> +    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>>>> +
>>>> +    pps->nal_unit_header.nal_ref_idc = 3;
>>>> +    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>>>> +
>>>> +    pps->pic_parameter_set_id = 0;
>>>> +    pps->seq_parameter_set_id = 0;
>>>> +
>>>> +    pps->entropy_coding_mode_flag =
>>>> +        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>>> +          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>>> +          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>>>> +    if (!opts->cabac && pps->entropy_coding_mode_flag)
>>>> +        pps->entropy_coding_mode_flag = 0;
>>>> +
>>>> +    pps->num_ref_idx_l0_default_active_minus1 = 0;
>>>> +    pps->num_ref_idx_l1_default_active_minus1 = 0;
>>>> +
>>>> +    pps->pic_init_qp_minus26 = opts->fixed_qp_idr - 26;
>>>> +
>>>> +    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>>> +        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>>> +        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>>>> +        pps->more_rbsp_data = 0;
>>>> +    } else {
>>>> +        pps->more_rbsp_data = 1;
>>>> +
>>>> +        pps->transform_8x8_mode_flag = 1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> diff --git a/libavcodec/hw_base_encode_h264.h
>>>> b/libavcodec/hw_base_encode_h264.h
>>>> new file mode 100644
>>>> index 0000000000..d1bae8f36f
>>>> --- /dev/null
>>>> +++ b/libavcodec/hw_base_encode_h264.h
>>>> @@ -0,0 +1,53 @@
>>>> +/*
>>>> + * This file is part of FFmpeg.
>>>> + *
>>>> + * FFmpeg is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU Lesser General Public
>>>> + * License as published by the Free Software Foundation; either
>>>> + * version 2.1 of the License, or (at your option) any later version.
>>>> + *
>>>> + * FFmpeg is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> + * Lesser General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU Lesser General Public
>>>> + * License along with FFmpeg; if not, write to the Free Software
>>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>>>> +02110-1301 USA  */
>>>> +
>>>> +#ifndef AVCODEC_HW_BASE_ENCODE_H264_H #define
>>>> +AVCODEC_HW_BASE_ENCODE_H264_H
>>>> +
>>>> +#include "hw_base_encode.h"
>>>> +#include "cbs_h264.h"
>>>> +
>>>> +typedef struct FFHWBaseEncodeH264 {
>>>> +    H264RawSPS raw_sps;
>>>> +    H264RawPPS raw_pps;
>>>> +    H264RawAUD raw_aud;
>>>> +
>>>> +    H264RawSEIBufferingPeriod sei_buffering_period;
>>>> +
>>>> +    int dpb_frames;
>>>> +    int mb_width;
>>>> +    int mb_height;
>>>> +} FFHWBaseEncodeH264;
>>>> +
>>>> +typedef struct FFHWBaseEncodeH264Opts {
>>>> +    int flags;
>>>> +#define FF_HW_H264_SEI_TIMING (1 << 0)
>>>> +
>>>> +    int64_t bit_rate;
>>>> +    int cabac;
>>>> +    int fixed_qp_idr;
>>>> +    uint64_t hrd_buffer_size;
>>>> +    uint64_t initial_buffer_fullness; } FFHWBaseEncodeH264Opts;
>>>> +
>>>> +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext
>> *base_ctx,
>>>> +                                       AVCodecContext *avctx,
>>>> +                                       FFHWBaseEncodeH264 *common,
>>>> +                                       FFHWBaseEncodeH264Opts
>>>> +*opts);
>>>> +
>>>> +#endif /* AVCODEC_HW_BASE_ENCODE_H264_H */
>>>> diff --git a/libavcodec/vaapi_encode_h264.c
>>>> b/libavcodec/vaapi_encode_h264.c index 35d3967766..443a569104 100644
>>>> --- a/libavcodec/vaapi_encode_h264.c
>>>> +++ b/libavcodec/vaapi_encode_h264.c
>>>> @@ -33,6 +33,7 @@
>>>> #include "cbs_h264.h"
>>>> #include "codec_internal.h"
>>>> #include "h264.h"
>>>> +#include "hw_base_encode_h264.h"
>>>> #include "h264_levels.h"
>>>> #include "h2645data.h"
>>>> #include "vaapi_encode.h"
>>>> @@ -67,6 +68,7 @@ typedef struct VAAPIEncodeH264Picture {
>>>>
>>>> typedef struct VAAPIEncodeH264Context {
>>>>       VAAPIEncodeContext common;
>>>> +    FFHWBaseEncodeH264 units;
>>>>
>>>>       // User options.
>>>>       int qp;
>>>> @@ -85,15 +87,11 @@ typedef struct VAAPIEncodeH264Context {
>>>>       int fixed_qp_p;
>>>>       int fixed_qp_b;
>>>>
>>>> -    int dpb_frames;
>>>> -
>>>>       // Writer structures.
>>>>       CodedBitstreamContext *cbc;
>>>>       CodedBitstreamFragment current_access_unit;
>>>>
>>>>       H264RawAUD   raw_aud;
>>>> -    H264RawSPS   raw_sps;
>>>> -    H264RawPPS   raw_pps;
>>>>       H264RawSlice raw_slice;
>>>>
>>>>       H264RawSEIBufferingPeriod      sei_buffering_period;
>>>> @@ -168,11 +166,11 @@ static int
>>>> vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx,
>>>>           priv->aud_needed = 0;
>>>>       }
>>>>
>>>> -    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_sps);
>>>> +    err = vaapi_encode_h264_add_nal(avctx, au,
>>>> + &priv->units.raw_sps);
>>>>       if (err < 0)
>>>>           goto fail;
>>>>
>>>> -    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_pps);
>>>> +    err = vaapi_encode_h264_add_nal(avctx, au,
>>>> + &priv->units.raw_pps);
>>>>       if (err < 0)
>>>>           goto fail;
>>>>
>>>> @@ -298,240 +296,24 @@ static int
>>>> vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
>>>>       FFHWBaseEncodeContext        *base_ctx = avctx->priv_data;
>>>>       VAAPIEncodeContext                *ctx = avctx->priv_data;
>>>>       VAAPIEncodeH264Context           *priv = avctx->priv_data;
>>>> -    H264RawSPS                        *sps = &priv->raw_sps;
>>>> -    H264RawPPS                        *pps = &priv->raw_pps;
>>>> +    H264RawSPS                        *sps = &priv->units.raw_sps;
>>>> +    H264RawPPS                        *pps = &priv->units.raw_pps;
>>>>       VAEncSequenceParameterBufferH264 *vseq = ctx-
>>> codec_sequence_params;
>>>>       VAEncPictureParameterBufferH264  *vpic = ctx->codec_picture_params;
>>>> -    const AVPixFmtDescriptor *desc;
>>>> -    int bit_depth;
>>>> -
>>>> -    memset(sps, 0, sizeof(*sps));
>>>> -    memset(pps, 0, sizeof(*pps));
>>>> -
>>>> -    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
>>>> -    av_assert0(desc);
>>>> -    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc-
>>>>> log2_chroma_h != 1) {
>>>> -        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
>>>> -                "%s is not supported.\n", desc->name);
>>>> -        return AVERROR(EINVAL);
>>>> -    }
>>>> -    bit_depth = desc->comp[0].depth;
>>>> -
>>>> -    sps->nal_unit_header.nal_ref_idc   = 3;
>>>> -    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
>>>> -
>>>> -    sps->profile_idc = avctx->profile & 0xff;
>>>> -
>>>> -    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
>>>> -        avctx->profile == AV_PROFILE_H264_MAIN)
>>>> -        sps->constraint_set1_flag = 1;
>>>> -
>>>> -    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>>> AV_PROFILE_H264_HIGH_10)
>>>> -        sps->constraint_set3_flag = base_ctx->gop_size == 1;
>>>> -
>>>> -    if (avctx->profile == AV_PROFILE_H264_MAIN ||
>>>> -        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile ==
>>>> AV_PROFILE_H264_HIGH_10) {
>>>> -        sps->constraint_set4_flag = 1;
>>>> -        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
>>>> -    }
>>>> -
>>>> -    if (base_ctx->gop_size == 1)
>>>> -        priv->dpb_frames = 0;
>>>> -    else
>>>> -        priv->dpb_frames = 1 + base_ctx->max_b_depth;
>>>> -
>>>> -    if (avctx->level != AV_LEVEL_UNKNOWN) {
>>>> -        sps->level_idc = avctx->level;
>>>> -    } else {
>>>> -        const H264LevelDescriptor *level;
>>>> -        int framerate;
>>>> -
>>>> -        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
>>>> -            framerate = avctx->framerate.num / avctx->framerate.den;
>>>> -        else
>>>> -            framerate = 0;
>>>> -
>>>> -        level = ff_h264_guess_level(sps->profile_idc,
>>>> -                                    avctx->bit_rate,
>>>> -                                    framerate,
>>>> -                                    priv->mb_width  * 16,
>>>> -                                    priv->mb_height * 16,
>>>> -                                    priv->dpb_frames);
>>>> -        if (level) {
>>>> -            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
>>>> -            if (level->constraint_set3_flag)
>>>> -                sps->constraint_set3_flag = 1;
>>>> -            sps->level_idc = level->level_idc;
>>>> -        } else {
>>>> -            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
>>>> -                   "to any level: using level 6.2.\n");
>>>> -            sps->level_idc = 62;
>>>> -        }
>>>> -    }
>>>> -
>>>> -    sps->seq_parameter_set_id = 0;
>>>> -    sps->chroma_format_idc    = 1;
>>>> -    sps->bit_depth_luma_minus8 = bit_depth - 8;
>>>> -    sps->bit_depth_chroma_minus8 = bit_depth - 8;
>>>> -
>>>> -    sps->log2_max_frame_num_minus4 = 4;
>>>> -    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
>>>> -    if (sps->pic_order_cnt_type == 0) {
>>>> -        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
>>>> -    }
>>>> -
>>>> -    sps->max_num_ref_frames = priv->dpb_frames;
>>>> -
>>>> -    sps->pic_width_in_mbs_minus1        = priv->mb_width  - 1;
>>>> -    sps->pic_height_in_map_units_minus1 = priv->mb_height - 1;
>>>> -
>>>> -    sps->frame_mbs_only_flag = 1;
>>>> -    sps->direct_8x8_inference_flag = 1;
>>>> -
>>>> -    if (avctx->width  != 16 * priv->mb_width ||
>>>> -        avctx->height != 16 * priv->mb_height) {
>>>> -        sps->frame_cropping_flag = 1;
>>>> -
>>>> -        sps->frame_crop_left_offset   = 0;
>>>> -        sps->frame_crop_right_offset  =
>>>> -            (16 * priv->mb_width - avctx->width) / 2;
>>>> -        sps->frame_crop_top_offset    = 0;
>>>> -        sps->frame_crop_bottom_offset =
>>>> -            (16 * priv->mb_height - avctx->height) / 2;
>>>> -    } else {
>>>> -        sps->frame_cropping_flag = 0;
>>>> -    }
>>>> -
>>>> -    sps->vui_parameters_present_flag = 1;
>>>> -
>>>> -    if (avctx->sample_aspect_ratio.num != 0 &&
>>>> -        avctx->sample_aspect_ratio.den != 0) {
>>>> -        int num, den, i;
>>>> -        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
>>>> -                  avctx->sample_aspect_ratio.den, 65535);
>>>> -        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
>>>> -            if (num == ff_h2645_pixel_aspect[i].num &&
>>>> -                den == ff_h2645_pixel_aspect[i].den) {
>>>> -                sps->vui.aspect_ratio_idc = i;
>>>> -                break;
>>>> -            }
>>>> -        }
>>>> -        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
>>>> -            sps->vui.aspect_ratio_idc = 255;
>>>> -            sps->vui.sar_width  = num;
>>>> -            sps->vui.sar_height = den;
>>>> -        }
>>>> -        sps->vui.aspect_ratio_info_present_flag = 1;
>>>> -    }
>>>> -
>>>> -    // Unspecified video format, from table E-2.
>>>> -    sps->vui.video_format             = 5;
>>>> -    sps->vui.video_full_range_flag    =
>>>> -        avctx->color_range == AVCOL_RANGE_JPEG;
>>>> -    sps->vui.colour_primaries         = avctx->color_primaries;
>>>> -    sps->vui.transfer_characteristics = avctx->color_trc;
>>>> -    sps->vui.matrix_coefficients      = avctx->colorspace;
>>>> -    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
>>>> -        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
>>>> -        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
>>>> -        sps->vui.colour_description_present_flag = 1;
>>>> -    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
>>>> -        sps->vui.colour_description_present_flag)
>>>> -        sps->vui.video_signal_type_present_flag = 1;
>>>> -
>>>> -    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
>>>> -        sps->vui.chroma_loc_info_present_flag = 1;
>>>> -        sps->vui.chroma_sample_loc_type_top_field    =
>>>> -        sps->vui.chroma_sample_loc_type_bottom_field =
>>>> -            avctx->chroma_sample_location - 1;
>>>> -    }
>>>> -
>>>> -    sps->vui.timing_info_present_flag = 1;
>>>> -    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
>>>> -        sps->vui.num_units_in_tick = avctx->framerate.den;
>>>> -        sps->vui.time_scale        = 2 * avctx->framerate.num;
>>>> -        sps->vui.fixed_frame_rate_flag = 1;
>>>> -    } else {
>>>> -        sps->vui.num_units_in_tick = avctx->time_base.num;
>>>> -        sps->vui.time_scale        = 2 * avctx->time_base.den;
>>>> -        sps->vui.fixed_frame_rate_flag = 0;
>>>> -    }
>>>> -
>>>> -    if (priv->sei & SEI_TIMING) {
>>>> -        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
>>>> -        H264RawSEIBufferingPeriod *bp = &priv->sei_buffering_period;
>>>> -
>>>> -        sps->vui.nal_hrd_parameters_present_flag = 1;
>>>> -
>>>> -        hrd->cpb_cnt_minus1 = 0;
>>>> -
>>>> -        // Try to scale these to a sensible range so that the
>>>> -        // golomb encode of the value is not overlong.
>>>> -        hrd->bit_rate_scale =
>>>> -            av_clip_uintp2(av_log2(ctx->va_bit_rate) - 15 - 6, 4);
>>>> -        hrd->bit_rate_value_minus1[0] =
>>>> -            (ctx->va_bit_rate >> hrd->bit_rate_scale + 6) - 1;
>>>> -
>>>> -        hrd->cpb_size_scale =
>>>> -            av_clip_uintp2(av_log2(ctx->hrd_params.buffer_size) - 15 - 4, 4);
>>>> -        hrd->cpb_size_value_minus1[0] =
>>>> -            (ctx->hrd_params.buffer_size >> hrd->cpb_size_scale + 4) - 1;
>>>> -
>>>> -        // CBR mode as defined for the HRD cannot be achieved without filler
>>>> -        // data, so this flag cannot be set even with VAAPI CBR modes.
>>>> -        hrd->cbr_flag[0] = 0;
>>>>
>>>> -        hrd->initial_cpb_removal_delay_length_minus1 = 23;
>>>> -        hrd->cpb_removal_delay_length_minus1         = 23;
>>>> -        hrd->dpb_output_delay_length_minus1          = 7;
>>>> -        hrd->time_offset_length                      = 0;
>>>> -
>>>> -        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
>>>> -
>>>> -        // This calculation can easily overflow 32 bits.
>>>> -        bp->nal.initial_cpb_removal_delay[0] = 90000 *
>>>> -            (uint64_t)ctx->hrd_params.initial_buffer_fullness /
>>>> -            ctx->hrd_params.buffer_size;
>>>> -        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
>>>> -    } else {
>>>> -        sps->vui.nal_hrd_parameters_present_flag = 0;
>>>> -        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
>>>> -    }
>>>> -
>>>> -    sps->vui.bitstream_restriction_flag    = 1;
>>>> -    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
>>>> -    sps->vui.log2_max_mv_length_horizontal = 15;
>>>> -    sps->vui.log2_max_mv_length_vertical   = 15;
>>>> -    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
>>>> -    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
>>>> -
>>>> -    pps->nal_unit_header.nal_ref_idc = 3;
>>>> -    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
>>>> -
>>>> -    pps->pic_parameter_set_id = 0;
>>>> -    pps->seq_parameter_set_id = 0;
>>>> -
>>>> -    pps->entropy_coding_mode_flag =
>>>> -        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>>> -          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>>> -          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
>>>> -    if (!priv->coder && pps->entropy_coding_mode_flag)
>>>> -        pps->entropy_coding_mode_flag = 0;
>>>> -
>>>> -    pps->num_ref_idx_l0_default_active_minus1 = 0;
>>>> -    pps->num_ref_idx_l1_default_active_minus1 = 0;
>>>> -
>>>> -    pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26;
>>>> -
>>>> -    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
>>>> -        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
>>>> -        sps->profile_idc == AV_PROFILE_H264_MAIN) {
>>>> -        pps->more_rbsp_data = 0;
>>>> -    } else {
>>>> -        pps->more_rbsp_data = 1;
>>>> +    FFHWBaseEncodeH264Opts unit_opts = {
>>>> +        .flags = (priv->sei & SEI_TIMING) ? FF_HW_H264_SEI_TIMING : 0,
>>>> +        .cabac = priv->coder,
>>>> +        .hrd_buffer_size = ctx->hrd_params.buffer_size,
>>>> +        .fixed_qp_idr = priv->fixed_qp_idr,
>>>> +        .initial_buffer_fullness = ctx->hrd_params.initial_buffer_fullness,
>>>> +        .bit_rate = ctx->va_bit_rate,
>>>> +    };
>>>>
>>>> -        pps->transform_8x8_mode_flag = 1;
>>>> -    }
>>>> +    int err = ff_hw_base_encode_init_params_h264(base_ctx, avctx,
>>>> +                                                 &priv->units, &unit_opts);
>>>> +    if (err < 0)
>>>> +        return err;
>>>>
>>>>       *vseq = (VAEncSequenceParameterBufferH264) {
>>>>           .seq_parameter_set_id = sps->seq_parameter_set_id, @@ -660,7
>>>> +442,7 @@ static int
>> vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
>>>>           }
>>>>       }
>>>>       hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame;
>>>> -    if (priv->raw_sps.pic_order_cnt_type == 2) {
>>>> +    if (priv->units.raw_sps.pic_order_cnt_type == 2) {
>>>>           hpic->pic_order_cnt *= 2;
>>>>       }
>>>>
>>>> @@ -870,8 +652,8 @@ static int
>>>> vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>>>>       VAAPIEncodePicture         *vaapi_pic = pic->priv;
>>>>       VAAPIEncodeH264Picture          *hpic = pic->codec_priv;
>>>>       FFHWBaseEncodePicture           *prev = pic->prev;
>>>> -    H264RawSPS                       *sps = &priv->raw_sps;
>>>> -    H264RawPPS                       *pps = &priv->raw_pps;
>>>> +    H264RawSPS                       *sps = &priv->units.raw_sps;
>>>> +    H264RawPPS                       *pps = &priv->units.raw_pps;
>>>>       H264RawSliceHeader                *sh = &priv->raw_slice.header;
>>>>       VAEncPictureParameterBufferH264 *vpic = vaapi_pic-
>>> codec_picture_params;
>>>>       VAEncSliceParameterBufferH264 *vslice =
>>>> slice->codec_slice_params; @@ -
>>>> 923,7 +705,7 @@ static int
>>>> vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
>>>>                   ++keep;
>>>>               }
>>>>           }
>>>> -        av_assert0(keep <= priv->dpb_frames);
>>>> +        av_assert0(keep <= priv->units.dpb_frames);
>>>>
>>>>           if (discard == 0) {
>>>>               sh->adaptive_ref_pic_marking_mode_flag = 0;
>>>> --
>>>
>>> Are you planning to move more codecs to shared file such as hevc? Since some
>> flags are based on the query result of hardware specific API, d3d12 may not align
>> with the constructors in shared file.
>>
>> Probably, for HEVC but later on. Not likely to do it for AV1 as its much shorter and
>> easier to construct yourself.
>>
>> Its the same story with Vulkan, where some unit features may be overridden. I
>> solve this issue by running *this* common function to construct optimal units,
>> converting them to Vulkan units, letting Vulkan write out its SPS/PPS unit
>> bitstream, *decoding* the output units back to CBS native units, copying the
>> overridden parts that matter (such as CABAC, loopfilter bits and so on) from the
>> Vulkan units, and then using CBS to encode the final units.
> 
> For D3D12 HEVC and H264 (AV1 not included), it is fully user's responsibility to write out and generate the SPS/PPS coded units, which do not even go through driver. Driver only cares about the D3D12 structures which are filled out by users. That looks simpler than Vulkan.
> 
>>
>> Thankfully, the CBS framework makes this much easier than it sounds, and since all
>> of this only occurs during initialization (you can append other units such as AUD
>> during runthime), its essentially free.
>>
>> You should really consider this for D3D12. I discovered issues in every single vulkan
>> driver when writing out units, so you shouldn't trust them either and write your
>> own.
>>
>> Also, Vulkan requires you to use filler units to pad the unit bitstream to a specific
>> alignment, which you cannot do with using the native Vulkan driver written units,
>> as there's no syntax for fillers. This requires you to copy the written slices, which is
>> IMO a hundred times worse than just writing out your own units.
>>
>> We can discuss HEVC later on, for now what do you think of this patch?
> 
> 
> What I meant was in both D3D12 HEVC and VAAPI HEVC we enabled some of the flags in PPS according to the D3D12/VAAPI specific structures queried from driver, which might be unique and hard to share. Anyways we could discuss later. I don't see we have such issue in h264 so I guess this patch is ok for me.

You can always override them individually, if you want to. This merely 
fills out a structure.

RE: Patch getting lost, its my fault. Patch 1 is indeed identical to the 
previously sent patch.

Thanks for reviewing, I'll push the patchset tomorrow.
diff mbox series

Patch

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3b4b8681f5..2e53dd723a 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -166,7 +166,7 @@  OBJS-$(CONFIG_STARTCODE)               += startcode.o
 OBJS-$(CONFIG_TEXTUREDSP)              += texturedsp.o
 OBJS-$(CONFIG_TEXTUREDSPENC)           += texturedspenc.o
 OBJS-$(CONFIG_TPELDSP)                 += tpeldsp.o
-OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o hw_base_encode.o
+OBJS-$(CONFIG_VAAPI_ENCODE)            += vaapi_encode.o hw_base_encode.o hw_base_encode_h264.o
 OBJS-$(CONFIG_AV1_AMF_ENCODER)         += amfenc_av1.o
 OBJS-$(CONFIG_VC1DSP)                  += vc1dsp.o
 OBJS-$(CONFIG_VIDEODSP)                += videodsp.o
diff --git a/libavcodec/hw_base_encode_h264.c b/libavcodec/hw_base_encode_h264.c
new file mode 100644
index 0000000000..5c3957cddb
--- /dev/null
+++ b/libavcodec/hw_base_encode_h264.c
@@ -0,0 +1,265 @@ 
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "hw_base_encode_h264.h"
+
+#include "h2645data.h"
+#include "h264_levels.h"
+
+#include "libavutil/pixdesc.h"
+
+int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx,
+                                       AVCodecContext *avctx,
+                                       FFHWBaseEncodeH264 *common,
+                                       FFHWBaseEncodeH264Opts *opts)
+{
+    H264RawSPS *sps = &common->raw_sps;
+    H264RawPPS *pps = &common->raw_pps;
+    const AVPixFmtDescriptor *desc;
+    int bit_depth;
+
+    memset(sps, 0, sizeof(*sps));
+    memset(pps, 0, sizeof(*pps));
+
+    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
+    av_assert0(desc);
+    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc->log2_chroma_h != 1) {
+        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
+                "%s is not supported.\n", desc->name);
+        return AVERROR(EINVAL);
+    }
+    bit_depth = desc->comp[0].depth;
+
+    sps->nal_unit_header.nal_ref_idc   = 3;
+    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
+
+    sps->profile_idc = avctx->profile & 0xff;
+
+    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
+        avctx->profile == AV_PROFILE_H264_MAIN)
+        sps->constraint_set1_flag = 1;
+
+    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10)
+        sps->constraint_set3_flag = base_ctx->gop_size == 1;
+
+    if (avctx->profile == AV_PROFILE_H264_MAIN ||
+        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10) {
+        sps->constraint_set4_flag = 1;
+        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
+    }
+
+    if (base_ctx->gop_size == 1)
+        common->dpb_frames = 0;
+    else
+        common->dpb_frames = 1 + base_ctx->max_b_depth;
+
+    if (avctx->level != AV_LEVEL_UNKNOWN) {
+        sps->level_idc = avctx->level;
+    } else {
+        const H264LevelDescriptor *level;
+        int framerate;
+
+        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
+            framerate = avctx->framerate.num / avctx->framerate.den;
+        else
+            framerate = 0;
+
+        level = ff_h264_guess_level(sps->profile_idc,
+                                    opts->bit_rate,
+                                    framerate,
+                                    common->mb_width  * 16,
+                                    common->mb_height * 16,
+                                    common->dpb_frames);
+        if (level) {
+            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
+            if (level->constraint_set3_flag)
+                sps->constraint_set3_flag = 1;
+            sps->level_idc = level->level_idc;
+        } else {
+            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
+                   "to any level: using level 6.2.\n");
+            sps->level_idc = 62;
+        }
+    }
+
+    sps->seq_parameter_set_id = 0;
+    sps->chroma_format_idc    = 1;
+    sps->bit_depth_luma_minus8 = bit_depth - 8;
+    sps->bit_depth_chroma_minus8 = bit_depth - 8;
+
+    sps->log2_max_frame_num_minus4 = 4;
+    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
+    if (sps->pic_order_cnt_type == 0) {
+        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
+    }
+
+    sps->max_num_ref_frames = common->dpb_frames;
+
+    sps->pic_width_in_mbs_minus1        = common->mb_width  - 1;
+    sps->pic_height_in_map_units_minus1 = common->mb_height - 1;
+
+    sps->frame_mbs_only_flag = 1;
+    sps->direct_8x8_inference_flag = 1;
+
+    if (avctx->width  != 16 * common->mb_width ||
+        avctx->height != 16 * common->mb_height) {
+        sps->frame_cropping_flag = 1;
+
+        sps->frame_crop_left_offset   = 0;
+        sps->frame_crop_right_offset  =
+            (16 * common->mb_width - avctx->width) / 2;
+        sps->frame_crop_top_offset    = 0;
+        sps->frame_crop_bottom_offset =
+            (16 * common->mb_height - avctx->height) / 2;
+    } else {
+        sps->frame_cropping_flag = 0;
+    }
+
+    sps->vui_parameters_present_flag = 1;
+
+    if (avctx->sample_aspect_ratio.num != 0 &&
+        avctx->sample_aspect_ratio.den != 0) {
+        int num, den, i;
+        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
+                  avctx->sample_aspect_ratio.den, 65535);
+        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
+            if (num == ff_h2645_pixel_aspect[i].num &&
+                den == ff_h2645_pixel_aspect[i].den) {
+                sps->vui.aspect_ratio_idc = i;
+                break;
+            }
+        }
+        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
+            sps->vui.aspect_ratio_idc = 255;
+            sps->vui.sar_width  = num;
+            sps->vui.sar_height = den;
+        }
+        sps->vui.aspect_ratio_info_present_flag = 1;
+    }
+
+    // Unspecified video format, from table E-2.
+    sps->vui.video_format             = 5;
+    sps->vui.video_full_range_flag    =
+        avctx->color_range == AVCOL_RANGE_JPEG;
+    sps->vui.colour_primaries         = avctx->color_primaries;
+    sps->vui.transfer_characteristics = avctx->color_trc;
+    sps->vui.matrix_coefficients      = avctx->colorspace;
+    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
+        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
+        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
+        sps->vui.colour_description_present_flag = 1;
+    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
+        sps->vui.colour_description_present_flag)
+        sps->vui.video_signal_type_present_flag = 1;
+
+    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
+        sps->vui.chroma_loc_info_present_flag = 1;
+        sps->vui.chroma_sample_loc_type_top_field    =
+        sps->vui.chroma_sample_loc_type_bottom_field =
+            avctx->chroma_sample_location - 1;
+    }
+
+    sps->vui.timing_info_present_flag = 1;
+    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
+        sps->vui.num_units_in_tick = avctx->framerate.den;
+        sps->vui.time_scale        = 2 * avctx->framerate.num;
+        sps->vui.fixed_frame_rate_flag = 1;
+    } else {
+        sps->vui.num_units_in_tick = avctx->time_base.num;
+        sps->vui.time_scale        = 2 * avctx->time_base.den;
+        sps->vui.fixed_frame_rate_flag = 0;
+    }
+
+    if (opts->flags & FF_HW_H264_SEI_TIMING) {
+        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
+        H264RawSEIBufferingPeriod *bp = &common->sei_buffering_period;
+
+        sps->vui.nal_hrd_parameters_present_flag = 1;
+
+        hrd->cpb_cnt_minus1 = 0;
+
+        // Try to scale these to a sensible range so that the
+        // golomb encode of the value is not overlong.
+        hrd->bit_rate_scale =
+            av_clip_uintp2(av_log2(opts->bit_rate) - 15 - 6, 4);
+        hrd->bit_rate_value_minus1[0] =
+            (opts->bit_rate >> hrd->bit_rate_scale + 6) - 1;
+
+        hrd->cpb_size_scale =
+            av_clip_uintp2(av_log2(opts->hrd_buffer_size) - 15 - 4, 4);
+        hrd->cpb_size_value_minus1[0] =
+            (opts->hrd_buffer_size >> hrd->cpb_size_scale + 4) - 1;
+
+        // CBR mode as defined for the HRD cannot be achieved without filler
+        // data, so this flag cannot be set even with VAAPI CBR modes.
+        hrd->cbr_flag[0] = 0;
+
+        hrd->initial_cpb_removal_delay_length_minus1 = 23;
+        hrd->cpb_removal_delay_length_minus1         = 23;
+        hrd->dpb_output_delay_length_minus1          = 7;
+        hrd->time_offset_length                      = 0;
+
+        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
+
+        // This calculation can easily overflow 32 bits.
+        bp->nal.initial_cpb_removal_delay[0] = 90000 *
+            (uint64_t)opts->initial_buffer_fullness /
+            opts->hrd_buffer_size;
+        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
+    } else {
+        sps->vui.nal_hrd_parameters_present_flag = 0;
+        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
+    }
+
+    sps->vui.bitstream_restriction_flag    = 1;
+    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
+    sps->vui.log2_max_mv_length_horizontal = 15;
+    sps->vui.log2_max_mv_length_vertical   = 15;
+    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
+    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
+
+    pps->nal_unit_header.nal_ref_idc = 3;
+    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
+
+    pps->pic_parameter_set_id = 0;
+    pps->seq_parameter_set_id = 0;
+
+    pps->entropy_coding_mode_flag =
+        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
+          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
+          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
+    if (!opts->cabac && pps->entropy_coding_mode_flag)
+        pps->entropy_coding_mode_flag = 0;
+
+    pps->num_ref_idx_l0_default_active_minus1 = 0;
+    pps->num_ref_idx_l1_default_active_minus1 = 0;
+
+    pps->pic_init_qp_minus26 = opts->fixed_qp_idr - 26;
+
+    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
+        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
+        sps->profile_idc == AV_PROFILE_H264_MAIN) {
+        pps->more_rbsp_data = 0;
+    } else {
+        pps->more_rbsp_data = 1;
+
+        pps->transform_8x8_mode_flag = 1;
+    }
+
+    return 0;
+}
diff --git a/libavcodec/hw_base_encode_h264.h b/libavcodec/hw_base_encode_h264.h
new file mode 100644
index 0000000000..d1bae8f36f
--- /dev/null
+++ b/libavcodec/hw_base_encode_h264.h
@@ -0,0 +1,53 @@ 
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_HW_BASE_ENCODE_H264_H
+#define AVCODEC_HW_BASE_ENCODE_H264_H
+
+#include "hw_base_encode.h"
+#include "cbs_h264.h"
+
+typedef struct FFHWBaseEncodeH264 {
+    H264RawSPS raw_sps;
+    H264RawPPS raw_pps;
+    H264RawAUD raw_aud;
+
+    H264RawSEIBufferingPeriod sei_buffering_period;
+
+    int dpb_frames;
+    int mb_width;
+    int mb_height;
+} FFHWBaseEncodeH264;
+
+typedef struct FFHWBaseEncodeH264Opts {
+    int flags;
+#define FF_HW_H264_SEI_TIMING (1 << 0)
+
+    int64_t bit_rate;
+    int cabac;
+    int fixed_qp_idr;
+    uint64_t hrd_buffer_size;
+    uint64_t initial_buffer_fullness;
+} FFHWBaseEncodeH264Opts;
+
+int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx,
+                                       AVCodecContext *avctx,
+                                       FFHWBaseEncodeH264 *common,
+                                       FFHWBaseEncodeH264Opts *opts);
+
+#endif /* AVCODEC_HW_BASE_ENCODE_H264_H */
diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
index 35d3967766..443a569104 100644
--- a/libavcodec/vaapi_encode_h264.c
+++ b/libavcodec/vaapi_encode_h264.c
@@ -33,6 +33,7 @@ 
 #include "cbs_h264.h"
 #include "codec_internal.h"
 #include "h264.h"
+#include "hw_base_encode_h264.h"
 #include "h264_levels.h"
 #include "h2645data.h"
 #include "vaapi_encode.h"
@@ -67,6 +68,7 @@  typedef struct VAAPIEncodeH264Picture {
 
 typedef struct VAAPIEncodeH264Context {
     VAAPIEncodeContext common;
+    FFHWBaseEncodeH264 units;
 
     // User options.
     int qp;
@@ -85,15 +87,11 @@  typedef struct VAAPIEncodeH264Context {
     int fixed_qp_p;
     int fixed_qp_b;
 
-    int dpb_frames;
-
     // Writer structures.
     CodedBitstreamContext *cbc;
     CodedBitstreamFragment current_access_unit;
 
     H264RawAUD   raw_aud;
-    H264RawSPS   raw_sps;
-    H264RawPPS   raw_pps;
     H264RawSlice raw_slice;
 
     H264RawSEIBufferingPeriod      sei_buffering_period;
@@ -168,11 +166,11 @@  static int vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx,
         priv->aud_needed = 0;
     }
 
-    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_sps);
+    err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_sps);
     if (err < 0)
         goto fail;
 
-    err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_pps);
+    err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_pps);
     if (err < 0)
         goto fail;
 
@@ -298,240 +296,24 @@  static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
     FFHWBaseEncodeContext        *base_ctx = avctx->priv_data;
     VAAPIEncodeContext                *ctx = avctx->priv_data;
     VAAPIEncodeH264Context           *priv = avctx->priv_data;
-    H264RawSPS                        *sps = &priv->raw_sps;
-    H264RawPPS                        *pps = &priv->raw_pps;
+    H264RawSPS                        *sps = &priv->units.raw_sps;
+    H264RawPPS                        *pps = &priv->units.raw_pps;
     VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params;
     VAEncPictureParameterBufferH264  *vpic = ctx->codec_picture_params;
-    const AVPixFmtDescriptor *desc;
-    int bit_depth;
-
-    memset(sps, 0, sizeof(*sps));
-    memset(pps, 0, sizeof(*pps));
-
-    desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
-    av_assert0(desc);
-    if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc->log2_chroma_h != 1) {
-        av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "
-                "%s is not supported.\n", desc->name);
-        return AVERROR(EINVAL);
-    }
-    bit_depth = desc->comp[0].depth;
-
-    sps->nal_unit_header.nal_ref_idc   = 3;
-    sps->nal_unit_header.nal_unit_type = H264_NAL_SPS;
-
-    sps->profile_idc = avctx->profile & 0xff;
-
-    if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE ||
-        avctx->profile == AV_PROFILE_H264_MAIN)
-        sps->constraint_set1_flag = 1;
-
-    if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10)
-        sps->constraint_set3_flag = base_ctx->gop_size == 1;
-
-    if (avctx->profile == AV_PROFILE_H264_MAIN ||
-        avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10) {
-        sps->constraint_set4_flag = 1;
-        sps->constraint_set5_flag = base_ctx->b_per_p == 0;
-    }
-
-    if (base_ctx->gop_size == 1)
-        priv->dpb_frames = 0;
-    else
-        priv->dpb_frames = 1 + base_ctx->max_b_depth;
-
-    if (avctx->level != AV_LEVEL_UNKNOWN) {
-        sps->level_idc = avctx->level;
-    } else {
-        const H264LevelDescriptor *level;
-        int framerate;
-
-        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
-            framerate = avctx->framerate.num / avctx->framerate.den;
-        else
-            framerate = 0;
-
-        level = ff_h264_guess_level(sps->profile_idc,
-                                    avctx->bit_rate,
-                                    framerate,
-                                    priv->mb_width  * 16,
-                                    priv->mb_height * 16,
-                                    priv->dpb_frames);
-        if (level) {
-            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
-            if (level->constraint_set3_flag)
-                sps->constraint_set3_flag = 1;
-            sps->level_idc = level->level_idc;
-        } else {
-            av_log(avctx, AV_LOG_WARNING, "Stream will not conform "
-                   "to any level: using level 6.2.\n");
-            sps->level_idc = 62;
-        }
-    }
-
-    sps->seq_parameter_set_id = 0;
-    sps->chroma_format_idc    = 1;
-    sps->bit_depth_luma_minus8 = bit_depth - 8;
-    sps->bit_depth_chroma_minus8 = bit_depth - 8;
-
-    sps->log2_max_frame_num_minus4 = 4;
-    sps->pic_order_cnt_type        = base_ctx->max_b_depth ? 0 : 2;
-    if (sps->pic_order_cnt_type == 0) {
-        sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
-    }
-
-    sps->max_num_ref_frames = priv->dpb_frames;
-
-    sps->pic_width_in_mbs_minus1        = priv->mb_width  - 1;
-    sps->pic_height_in_map_units_minus1 = priv->mb_height - 1;
-
-    sps->frame_mbs_only_flag = 1;
-    sps->direct_8x8_inference_flag = 1;
-
-    if (avctx->width  != 16 * priv->mb_width ||
-        avctx->height != 16 * priv->mb_height) {
-        sps->frame_cropping_flag = 1;
-
-        sps->frame_crop_left_offset   = 0;
-        sps->frame_crop_right_offset  =
-            (16 * priv->mb_width - avctx->width) / 2;
-        sps->frame_crop_top_offset    = 0;
-        sps->frame_crop_bottom_offset =
-            (16 * priv->mb_height - avctx->height) / 2;
-    } else {
-        sps->frame_cropping_flag = 0;
-    }
-
-    sps->vui_parameters_present_flag = 1;
-
-    if (avctx->sample_aspect_ratio.num != 0 &&
-        avctx->sample_aspect_ratio.den != 0) {
-        int num, den, i;
-        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,
-                  avctx->sample_aspect_ratio.den, 65535);
-        for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) {
-            if (num == ff_h2645_pixel_aspect[i].num &&
-                den == ff_h2645_pixel_aspect[i].den) {
-                sps->vui.aspect_ratio_idc = i;
-                break;
-            }
-        }
-        if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) {
-            sps->vui.aspect_ratio_idc = 255;
-            sps->vui.sar_width  = num;
-            sps->vui.sar_height = den;
-        }
-        sps->vui.aspect_ratio_info_present_flag = 1;
-    }
-
-    // Unspecified video format, from table E-2.
-    sps->vui.video_format             = 5;
-    sps->vui.video_full_range_flag    =
-        avctx->color_range == AVCOL_RANGE_JPEG;
-    sps->vui.colour_primaries         = avctx->color_primaries;
-    sps->vui.transfer_characteristics = avctx->color_trc;
-    sps->vui.matrix_coefficients      = avctx->colorspace;
-    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
-        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
-        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)
-        sps->vui.colour_description_present_flag = 1;
-    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||
-        sps->vui.colour_description_present_flag)
-        sps->vui.video_signal_type_present_flag = 1;
-
-    if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
-        sps->vui.chroma_loc_info_present_flag = 1;
-        sps->vui.chroma_sample_loc_type_top_field    =
-        sps->vui.chroma_sample_loc_type_bottom_field =
-            avctx->chroma_sample_location - 1;
-    }
-
-    sps->vui.timing_info_present_flag = 1;
-    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
-        sps->vui.num_units_in_tick = avctx->framerate.den;
-        sps->vui.time_scale        = 2 * avctx->framerate.num;
-        sps->vui.fixed_frame_rate_flag = 1;
-    } else {
-        sps->vui.num_units_in_tick = avctx->time_base.num;
-        sps->vui.time_scale        = 2 * avctx->time_base.den;
-        sps->vui.fixed_frame_rate_flag = 0;
-    }
-
-    if (priv->sei & SEI_TIMING) {
-        H264RawHRD *hrd = &sps->vui.nal_hrd_parameters;
-        H264RawSEIBufferingPeriod *bp = &priv->sei_buffering_period;
-
-        sps->vui.nal_hrd_parameters_present_flag = 1;
-
-        hrd->cpb_cnt_minus1 = 0;
-
-        // Try to scale these to a sensible range so that the
-        // golomb encode of the value is not overlong.
-        hrd->bit_rate_scale =
-            av_clip_uintp2(av_log2(ctx->va_bit_rate) - 15 - 6, 4);
-        hrd->bit_rate_value_minus1[0] =
-            (ctx->va_bit_rate >> hrd->bit_rate_scale + 6) - 1;
-
-        hrd->cpb_size_scale =
-            av_clip_uintp2(av_log2(ctx->hrd_params.buffer_size) - 15 - 4, 4);
-        hrd->cpb_size_value_minus1[0] =
-            (ctx->hrd_params.buffer_size >> hrd->cpb_size_scale + 4) - 1;
-
-        // CBR mode as defined for the HRD cannot be achieved without filler
-        // data, so this flag cannot be set even with VAAPI CBR modes.
-        hrd->cbr_flag[0] = 0;
 
-        hrd->initial_cpb_removal_delay_length_minus1 = 23;
-        hrd->cpb_removal_delay_length_minus1         = 23;
-        hrd->dpb_output_delay_length_minus1          = 7;
-        hrd->time_offset_length                      = 0;
-
-        bp->seq_parameter_set_id = sps->seq_parameter_set_id;
-
-        // This calculation can easily overflow 32 bits.
-        bp->nal.initial_cpb_removal_delay[0] = 90000 *
-            (uint64_t)ctx->hrd_params.initial_buffer_fullness /
-            ctx->hrd_params.buffer_size;
-        bp->nal.initial_cpb_removal_delay_offset[0] = 0;
-    } else {
-        sps->vui.nal_hrd_parameters_present_flag = 0;
-        sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag;
-    }
-
-    sps->vui.bitstream_restriction_flag    = 1;
-    sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
-    sps->vui.log2_max_mv_length_horizontal = 15;
-    sps->vui.log2_max_mv_length_vertical   = 15;
-    sps->vui.max_num_reorder_frames        = base_ctx->max_b_depth;
-    sps->vui.max_dec_frame_buffering       = base_ctx->max_b_depth + 1;
-
-    pps->nal_unit_header.nal_ref_idc = 3;
-    pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
-
-    pps->pic_parameter_set_id = 0;
-    pps->seq_parameter_set_id = 0;
-
-    pps->entropy_coding_mode_flag =
-        !(sps->profile_idc == AV_PROFILE_H264_BASELINE ||
-          sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
-          sps->profile_idc == AV_PROFILE_H264_CAVLC_444);
-    if (!priv->coder && pps->entropy_coding_mode_flag)
-        pps->entropy_coding_mode_flag = 0;
-
-    pps->num_ref_idx_l0_default_active_minus1 = 0;
-    pps->num_ref_idx_l1_default_active_minus1 = 0;
-
-    pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26;
-
-    if (sps->profile_idc == AV_PROFILE_H264_BASELINE ||
-        sps->profile_idc == AV_PROFILE_H264_EXTENDED ||
-        sps->profile_idc == AV_PROFILE_H264_MAIN) {
-        pps->more_rbsp_data = 0;
-    } else {
-        pps->more_rbsp_data = 1;
+    FFHWBaseEncodeH264Opts unit_opts = {
+        .flags = (priv->sei & SEI_TIMING) ? FF_HW_H264_SEI_TIMING : 0,
+        .cabac = priv->coder,
+        .hrd_buffer_size = ctx->hrd_params.buffer_size,
+        .fixed_qp_idr = priv->fixed_qp_idr,
+        .initial_buffer_fullness = ctx->hrd_params.initial_buffer_fullness,
+        .bit_rate = ctx->va_bit_rate,
+    };
 
-        pps->transform_8x8_mode_flag = 1;
-    }
+    int err = ff_hw_base_encode_init_params_h264(base_ctx, avctx,
+                                                 &priv->units, &unit_opts);
+    if (err < 0)
+        return err;
 
     *vseq = (VAEncSequenceParameterBufferH264) {
         .seq_parameter_set_id = sps->seq_parameter_set_id,
@@ -660,7 +442,7 @@  static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
         }
     }
     hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame;
-    if (priv->raw_sps.pic_order_cnt_type == 2) {
+    if (priv->units.raw_sps.pic_order_cnt_type == 2) {
         hpic->pic_order_cnt *= 2;
     }
 
@@ -870,8 +652,8 @@  static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
     VAAPIEncodePicture         *vaapi_pic = pic->priv;
     VAAPIEncodeH264Picture          *hpic = pic->codec_priv;
     FFHWBaseEncodePicture           *prev = pic->prev;
-    H264RawSPS                       *sps = &priv->raw_sps;
-    H264RawPPS                       *pps = &priv->raw_pps;
+    H264RawSPS                       *sps = &priv->units.raw_sps;
+    H264RawPPS                       *pps = &priv->units.raw_pps;
     H264RawSliceHeader                *sh = &priv->raw_slice.header;
     VAEncPictureParameterBufferH264 *vpic = vaapi_pic->codec_picture_params;
     VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params;
@@ -923,7 +705,7 @@  static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
                 ++keep;
             }
         }
-        av_assert0(keep <= priv->dpb_frames);
+        av_assert0(keep <= priv->units.dpb_frames);
 
         if (discard == 0) {
             sh->adaptive_ref_pic_marking_mode_flag = 0;