From patchwork Tue Sep 12 23:44:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 5125 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.36.26 with SMTP id f26csp297588jaa; Tue, 12 Sep 2017 16:47:14 -0700 (PDT) X-Received: by 10.28.39.71 with SMTP id n68mr998528wmn.114.1505260034434; Tue, 12 Sep 2017 16:47:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1505260034; cv=none; d=google.com; s=arc-20160816; b=Hw7QJ87eqhXm1c5flkOi5CudxOAKcFGALb+Wsfmgpm8Upv+svVBUC00TFMWVBduq/m Lp7e97erb10gKztHBhGIDyhQ92fOkMKjj0nbW0DfHklQvICFWolUoA8BmsPuNeVbH4OD 8sN6kiyFzev/LlO+f6oqRg5axEuVp11gFI4Pt4ZOEmY6WMPpGNhJYZK/2OdiKWtKlmYB ixa2Tp30WA/c/1N6KStmUqJBZkfTUhkKBF2S680z5VGusmmxdXNNmniDp6VMWvdN3Hqw iPGeUMHP6Pj9Wo0EPw2iLjMBiD3j5FOzFBUhMPYVNiVATYrPDWNEDUSlZbcLBeqApiQ5 +yYw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=hXzvkNn3XUvAaO3Y3Qpke8ZtIfqp4ccpjGSJRbyih4g=; b=nknLRyQIugP0iVpon2i8RDvRO5Nk1XmmJzYAekS3gzKkGbvOsztwr9Cnh5TUkvkqh2 pL0it1Yw/ci+yToCVFyCPSNRbF1UwVtx3UEguQ5OQjM6qslcEcg4dDkBeSTbksqDDOkJ 3NHQ1sGlykcWrnK7V6NOsXFe+sQ1aHkHcEPitU1z8j+36zqY+jjALHTxNCnUZLIkHGfY 86VTyQBt1crkAgw2NwPWjE58lr27yRYLonp386OiGE/rnS+a6QrZVx17N3nLemPMt9PP w3ySJjyBn8lBsEgwP0flltC12otJSVeU2ZbU8XQebAkmyg2mgzfrz7CEMAcfrFnEgFnn L8/Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@jkqxz-net.20150623.gappssmtp.com header.s=20150623 header.b=qb9yobRl; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id p7si8828818wma.116.2017.09.12.16.47.14; Tue, 12 Sep 2017 16:47:14 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@jkqxz-net.20150623.gappssmtp.com header.s=20150623 header.b=qb9yobRl; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 846E1689EA2; Wed, 13 Sep 2017 02:44:29 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f47.google.com (mail-wm0-f47.google.com [74.125.82.47]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 7CB7C689E31 for ; Wed, 13 Sep 2017 02:44:26 +0300 (EEST) Received: by mail-wm0-f47.google.com with SMTP id a137so3564789wma.0 for ; Tue, 12 Sep 2017 16:44:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references; bh=FkCIA7HjTlN4f3pH8jjNy4MrdfZMcGKBI7O7BFbiFEY=; b=qb9yobRl2uMoTv/hUVH3MdmhsYpouq+RPW+3IMz/0Yh+Tq3XW4IJBkF0LwN6NJbi7U 6W6s9JsexCpU6qZGnLm/fZwG1GljgCMC2T05szxz1u57E35h2s+nJUttFqsmvIkxQLHm x9S27+a4SLnYr7ejETz9GtWG4h1TO73+hcQXIEGdBYmx1FgMImdMZmPP9OtfsP0+LoQ0 Sn43MJiJJ6e5qDh3Sps4XZ7wmtVvF5Ri64n1PPXBWS4jQYipg47CFFmWC9cEr5L662yO /05TxupUCO284aflVwG//6+b33dG0cPHBa34MDdH2zsg6J+wjUJszzXXLSRSo5UC0Ssm EDxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=FkCIA7HjTlN4f3pH8jjNy4MrdfZMcGKBI7O7BFbiFEY=; b=RMgHvpnr+WprL0b4uOnNwTWOJTxm75df9jm1qKxwsPPDEtN/0Sv0H9LJHGMn01ZdVB N2Jvk27uHoLaYVaio+c1LHEhCshuWCfU40HbNHYqBczKp1r2tSuutr1h+MPlMkEJ1uKI 5tHSv+OOjw9rmhlYxc3pXUnIUVAtXa+ZOUV+erIr2s4ZJNU1DXigjMf5VydDGMJdGXLx sGd/mLJsczoE9/afMVAzQq/h3wUun9WLhd45LJKJVZeGg7du0PPTBGTgPFJrWkM4ul9a GAlDCUHAHmvJ58lL5gs++cdHTHLmtTrHGCeTSZgZfBDuue+Yfv+3RiKXKh9zejNw4alW Gf0g== X-Gm-Message-State: AHPjjUirdna9WGVENJ9m207XTVB1sn4A95/btMBRbXCmiI4ua4tF2j2F TLTR88zvTEAXWraDWls= X-Google-Smtp-Source: AOwi7QAYuF7uMRactJ+Gzq2vnlItRPaMtvSdnZ0gk1WhgjRowpKU2Dg5QOQRE/cViooH+9HDDoUZeg== X-Received: by 10.28.230.3 with SMTP id d3mr802642wmh.54.1505259871007; Tue, 12 Sep 2017 16:44:31 -0700 (PDT) Received: from rywe.jkqxz.net (cpc91242-cmbg18-2-0-cust650.5-4.cable.virginm.net. [82.8.130.139]) by smtp.gmail.com with ESMTPSA id p193sm4378138wmg.37.2017.09.12.16.44.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 12 Sep 2017 16:44:30 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Wed, 13 Sep 2017 00:44:06 +0100 Message-Id: <20170912234410.14093-17-sw@jkqxz.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170912234410.14093-1-sw@jkqxz.net> References: <20170912234410.14093-1-sw@jkqxz.net> Subject: [FFmpeg-devel] [PATCH 16/20] vaapi_h265: Convert to use coded bitstream infrastructure X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Also improves the metadata and generally makes the configuration a bit cleaner. (cherry picked from commit ac12486714b48f9bd5d9167f90b77c936751d6ef) --- configure | 2 +- libavcodec/Makefile | 2 +- libavcodec/vaapi_encode_h265.c | 1536 +++++++++++++++------------------------- libavcodec/vaapi_encode_h26x.c | 68 -- libavcodec/vaapi_encode_h26x.h | 45 -- 5 files changed, 585 insertions(+), 1068 deletions(-) delete mode 100644 libavcodec/vaapi_encode_h26x.c delete mode 100644 libavcodec/vaapi_encode_h26x.h diff --git a/configure b/configure index 2f0488617e..2e617aedb9 100755 --- a/configure +++ b/configure @@ -2795,7 +2795,7 @@ hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser qsvdec hevc_qsv_hwacce hevc_qsv_encoder_deps="libmfx" hevc_qsv_encoder_select="hevcparse qsvenc" hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" -hevc_vaapi_encoder_select="vaapi_encode golomb" +hevc_vaapi_encoder_select="cbs_h265 vaapi_encode" mjpeg_cuvid_decoder_deps="cuda cuvid" mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG" mjpeg_vaapi_encoder_select="vaapi_encode jpegtables" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index a0247c490e..135eb1751f 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -356,7 +356,7 @@ OBJS-$(CONFIG_NVENC_HEVC_ENCODER) += nvenc_hevc.o OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ hevc_data.o -OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o vaapi_encode_h26x.o +OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \ canopus.o diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 971458db87..fd3edbb553 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -16,163 +16,25 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include #include #include "libavutil/avassert.h" -#include "libavutil/internal.h" +#include "libavutil/common.h" #include "libavutil/opt.h" -#include "libavutil/pixfmt.h" #include "avcodec.h" +#include "cbs.h" +#include "cbs_h265.h" #include "hevc.h" #include "internal.h" #include "put_bits.h" #include "vaapi_encode.h" -#include "vaapi_encode_h26x.h" - - -#define MAX_ST_REF_PIC_SETS 32 -#define MAX_DPB_PICS 16 -#define MAX_LAYERS 1 - - -typedef struct VAAPIEncodeH265STRPS { - char inter_ref_pic_set_prediction_flag; - - unsigned int num_negative_pics; - unsigned int num_positive_pics; - - unsigned int delta_poc_s0_minus1[MAX_DPB_PICS]; - char used_by_curr_pic_s0_flag[MAX_DPB_PICS]; - - unsigned int delta_poc_s1_minus1[MAX_DPB_PICS]; - char used_by_curr_pic_s1_flag[MAX_DPB_PICS]; -} VAAPIEncodeH265STRPS; - -// This structure contains all possibly-useful per-sequence syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH265MiscSequenceParams { - - // Parameter set IDs. - unsigned int video_parameter_set_id; - unsigned int seq_parameter_set_id; - - // Layering. - unsigned int vps_max_layers_minus1; - unsigned int vps_max_sub_layers_minus1; - char vps_temporal_id_nesting_flag; - unsigned int vps_max_layer_id; - unsigned int vps_num_layer_sets_minus1; - unsigned int sps_max_sub_layers_minus1; - char sps_temporal_id_nesting_flag; - char layer_id_included_flag[MAX_LAYERS][64]; - - // Profile/tier/level parameters. - char general_profile_compatibility_flag[32]; - char general_progressive_source_flag; - char general_interlaced_source_flag; - char general_non_packed_constraint_flag; - char general_frame_only_constraint_flag; - char general_inbld_flag; - - // Decode/display ordering parameters. - unsigned int log2_max_pic_order_cnt_lsb_minus4; - char vps_sub_layer_ordering_info_present_flag; - unsigned int vps_max_dec_pic_buffering_minus1[MAX_LAYERS]; - unsigned int vps_max_num_reorder_pics[MAX_LAYERS]; - unsigned int vps_max_latency_increase_plus1[MAX_LAYERS]; - char sps_sub_layer_ordering_info_present_flag; - unsigned int sps_max_dec_pic_buffering_minus1[MAX_LAYERS]; - unsigned int sps_max_num_reorder_pics[MAX_LAYERS]; - unsigned int sps_max_latency_increase_plus1[MAX_LAYERS]; - - // Timing information. - char vps_timing_info_present_flag; - unsigned int vps_num_units_in_tick; - unsigned int vps_time_scale; - char vps_poc_proportional_to_timing_flag; - unsigned int vps_num_ticks_poc_diff_minus1; - - // Cropping information. - char conformance_window_flag; - unsigned int conf_win_left_offset; - unsigned int conf_win_right_offset; - unsigned int conf_win_top_offset; - unsigned int conf_win_bottom_offset; - - // Short-term reference picture sets. - unsigned int num_short_term_ref_pic_sets; - VAAPIEncodeH265STRPS st_ref_pic_set[MAX_ST_REF_PIC_SETS]; - - // Long-term reference pictures. - char long_term_ref_pics_present_flag; - unsigned int num_long_term_ref_pics_sps; - struct { - unsigned int lt_ref_pic_poc_lsb_sps; - char used_by_curr_pic_lt_sps_flag; - } lt_ref_pic; - - // Deblocking filter control. - char deblocking_filter_control_present_flag; - char deblocking_filter_override_enabled_flag; - char pps_deblocking_filter_disabled_flag; - int pps_beta_offset_div2; - int pps_tc_offset_div2; - - // Video Usability Information. - char vui_parameters_present_flag; - char aspect_ratio_info_present_flag; - unsigned int aspect_ratio_idc; - unsigned int sar_width; - unsigned int sar_height; - char video_signal_type_present_flag; - unsigned int video_format; - char video_full_range_flag; - char colour_description_present_flag; - unsigned int colour_primaries; - unsigned int transfer_characteristics; - unsigned int matrix_coeffs; - - // Oddments. - char uniform_spacing_flag; - char output_flag_present_flag; - char cabac_init_present_flag; - unsigned int num_extra_slice_header_bits; - char lists_modification_present_flag; - char pps_slice_chroma_qp_offsets_present_flag; - char pps_slice_chroma_offset_list_enabled_flag; -} VAAPIEncodeH265MiscSequenceParams; - -// This structure contains all possibly-useful per-slice syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH265MiscSliceParams { - // Slice segments. - char first_slice_segment_in_pic_flag; - - // Short-term reference picture sets. - char short_term_ref_pic_set_sps_flag; - unsigned int short_term_ref_pic_idx; - VAAPIEncodeH265STRPS st_ref_pic_set; - - // Deblocking filter. - char deblocking_filter_override_flag; - - // Oddments. - char slice_reserved_flag[8]; - char no_output_of_prior_pics_flag; - char pic_output_flag; -} VAAPIEncodeH265MiscSliceParams; - -typedef struct VAAPIEncodeH265Slice { - VAAPIEncodeH265MiscSliceParams misc_slice_params; - - int64_t pic_order_cnt; -} VAAPIEncodeH265Slice; -typedef struct VAAPIEncodeH265Context { - VAAPIEncodeH265MiscSequenceParams misc_sequence_params; +typedef struct VAAPIEncodeH265Context { unsigned int ctu_width; unsigned int ctu_height; @@ -180,17 +42,19 @@ typedef struct VAAPIEncodeH265Context { int fixed_qp_p; int fixed_qp_b; + H265RawVPS vps; + H265RawSPS sps; + H265RawPPS pps; + H265RawSlice slice; + int64_t last_idr_frame; + int pic_order_cnt; - // Rate control configuration. - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterRateControl rc; - } rc_params; - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterHRD hrd; - } hrd_params; + int slice_nal_unit; + int slice_type; + + CodedBitstreamContext cbc; + CodedBitstreamFragment current_access_unit; } VAAPIEncodeH265Context; typedef struct VAAPIEncodeH265Options { @@ -198,564 +62,77 @@ typedef struct VAAPIEncodeH265Options { } VAAPIEncodeH265Options; -#define vseq_var(name) vseq->name, name -#define vseq_field(name) vseq->seq_fields.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpic_field(name) vpic->pic_fields.bits.name, name -#define vslice_var(name) vslice->name, name -#define vslice_field(name) vslice->slice_fields.bits.name, name -#define mseq_var(name) mseq->name, name -#define mslice_var(name) mslice->name, name -#define mstrps_var(name) mstrps->name, name - -static void vaapi_encode_h265_write_nal_unit_header(PutBitContext *pbc, - int nal_unit_type) -{ - u(1, 0, forbidden_zero_bit); - u(6, nal_unit_type, nal_unit_type); - u(6, 0, nuh_layer_id); - u(3, 1, nuh_temporal_id_plus1); -} - -static void vaapi_encode_h265_write_rbsp_trailing_bits(PutBitContext *pbc) -{ - u(1, 1, rbsp_stop_one_bit); - while (put_bits_count(pbc) & 7) - u(1, 0, rbsp_alignment_zero_bit); -} - -static void vaapi_encode_h265_write_profile_tier_level(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int j; - - if (1) { - u(2, 0, general_profile_space); - u(1, vseq_var(general_tier_flag)); - u(5, vseq_var(general_profile_idc)); - - for (j = 0; j < 32; j++) { - u(1, mseq_var(general_profile_compatibility_flag[j])); - } - - u(1, mseq_var(general_progressive_source_flag)); - u(1, mseq_var(general_interlaced_source_flag)); - u(1, mseq_var(general_non_packed_constraint_flag)); - u(1, mseq_var(general_frame_only_constraint_flag)); - - if (0) { - // Not main profile. - // Lots of extra constraint flags. - } else { - // put_bits only handles up to 31 bits. - u(23, 0, general_reserved_zero_43bits); - u(20, 0, general_reserved_zero_43bits); - } - - if (vseq->general_profile_idc >= 1 && vseq->general_profile_idc <= 5) { - u(1, mseq_var(general_inbld_flag)); - } else { - u(1, 0, general_reserved_zero_bit); - } - } - - u(8, vseq_var(general_level_idc)); - - // No sublayers. -} - -static void vaapi_encode_h265_write_vps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i, j; - - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_VPS); - - u(4, mseq->video_parameter_set_id, vps_video_parameter_set_id); - - u(1, 1, vps_base_layer_internal_flag); - u(1, 1, vps_base_layer_available_flag); - u(6, mseq_var(vps_max_layers_minus1)); - u(3, mseq_var(vps_max_sub_layers_minus1)); - u(1, mseq_var(vps_temporal_id_nesting_flag)); - - u(16, 0xffff, vps_reserved_0xffff_16bits); - - vaapi_encode_h265_write_profile_tier_level(pbc, ctx); - - u(1, mseq_var(vps_sub_layer_ordering_info_present_flag)); - for (i = (mseq->vps_sub_layer_ordering_info_present_flag ? - 0 : mseq->vps_max_sub_layers_minus1); - i <= mseq->vps_max_sub_layers_minus1; i++) { - ue(mseq_var(vps_max_dec_pic_buffering_minus1[i])); - ue(mseq_var(vps_max_num_reorder_pics[i])); - ue(mseq_var(vps_max_latency_increase_plus1[i])); - } - - u(6, mseq_var(vps_max_layer_id)); - ue(mseq_var(vps_num_layer_sets_minus1)); - for (i = 1; i <= mseq->vps_num_layer_sets_minus1; i++) { - for (j = 0; j < mseq->vps_max_layer_id; j++) - u(1, mseq_var(layer_id_included_flag[i][j])); - } - - u(1, mseq_var(vps_timing_info_present_flag)); - if (mseq->vps_timing_info_present_flag) { - u(1, 0, put_bits_hack_zero_bit); - u(31, mseq_var(vps_num_units_in_tick)); - u(1, 0, put_bits_hack_zero_bit); - u(31, mseq_var(vps_time_scale)); - u(1, mseq_var(vps_poc_proportional_to_timing_flag)); - if (mseq->vps_poc_proportional_to_timing_flag) { - ue(mseq_var(vps_num_ticks_poc_diff_minus1)); - } - ue(0, vps_num_hrd_parameters); - } - - u(1, 0, vps_extension_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); -} - -static void vaapi_encode_h265_write_st_ref_pic_set(PutBitContext *pbc, - int st_rps_idx, - VAAPIEncodeH265STRPS *mstrps) -{ - int i; - - if (st_rps_idx != 0) - u(1, mstrps_var(inter_ref_pic_set_prediction_flag)); - - if (mstrps->inter_ref_pic_set_prediction_flag) { - av_assert0(0 && "inter ref pic set prediction not supported"); - } else { - ue(mstrps_var(num_negative_pics)); - ue(mstrps_var(num_positive_pics)); - - for (i = 0; i < mstrps->num_negative_pics; i++) { - ue(mstrps_var(delta_poc_s0_minus1[i])); - u(1, mstrps_var(used_by_curr_pic_s0_flag[i])); - } - for (i = 0; i < mstrps->num_positive_pics; i++) { - ue(mstrps_var(delta_poc_s1_minus1[i])); - u(1, mstrps_var(used_by_curr_pic_s1_flag[i])); - } - } -} - -static void vaapi_encode_h265_write_vui_parameters(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - - u(1, mseq_var(aspect_ratio_info_present_flag)); - if (mseq->aspect_ratio_info_present_flag) { - u(8, mseq_var(aspect_ratio_idc)); - if (mseq->aspect_ratio_idc == 255) { - u(16, mseq_var(sar_width)); - u(16, mseq_var(sar_height)); - } - } - - u(1, 0, overscan_info_present_flag); - - u(1, mseq_var(video_signal_type_present_flag)); - if (mseq->video_signal_type_present_flag) { - u(3, mseq_var(video_format)); - u(1, mseq_var(video_full_range_flag)); - u(1, mseq_var(colour_description_present_flag)); - if (mseq->colour_description_present_flag) { - u(8, mseq_var(colour_primaries)); - u(8, mseq_var(transfer_characteristics)); - u(8, mseq_var(matrix_coeffs)); - } - } - - u(1, 0, chroma_loc_info_present_flag); - u(1, 0, neutral_chroma_indication_flag); - u(1, 0, field_seq_flag); - u(1, 0, frame_field_info_present_flag); - u(1, 0, default_display_window_flag); - u(1, 0, vui_timing_info_present_flag); - u(1, 0, bitstream_restriction_flag_flag); -} - -static void vaapi_encode_h265_write_sps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_SPS); - - u(4, mseq->video_parameter_set_id, sps_video_parameter_set_id); - - u(3, mseq_var(sps_max_sub_layers_minus1)); - u(1, mseq_var(sps_temporal_id_nesting_flag)); - - vaapi_encode_h265_write_profile_tier_level(pbc, ctx); - - ue(mseq->seq_parameter_set_id, sps_seq_parameter_set_id); - ue(vseq_field(chroma_format_idc)); - if (vseq->seq_fields.bits.chroma_format_idc == 3) - u(1, 0, separate_colour_plane_flag); - - ue(vseq_var(pic_width_in_luma_samples)); - ue(vseq_var(pic_height_in_luma_samples)); - - u(1, mseq_var(conformance_window_flag)); - if (mseq->conformance_window_flag) { - ue(mseq_var(conf_win_left_offset)); - ue(mseq_var(conf_win_right_offset)); - ue(mseq_var(conf_win_top_offset)); - ue(mseq_var(conf_win_bottom_offset)); - } - - ue(vseq_field(bit_depth_luma_minus8)); - ue(vseq_field(bit_depth_chroma_minus8)); - - ue(mseq_var(log2_max_pic_order_cnt_lsb_minus4)); - - u(1, mseq_var(sps_sub_layer_ordering_info_present_flag)); - for (i = (mseq->sps_sub_layer_ordering_info_present_flag ? - 0 : mseq->sps_max_sub_layers_minus1); - i <= mseq->sps_max_sub_layers_minus1; i++) { - ue(mseq_var(sps_max_dec_pic_buffering_minus1[i])); - ue(mseq_var(sps_max_num_reorder_pics[i])); - ue(mseq_var(sps_max_latency_increase_plus1[i])); - } - - ue(vseq_var(log2_min_luma_coding_block_size_minus3)); - ue(vseq_var(log2_diff_max_min_luma_coding_block_size)); - ue(vseq_var(log2_min_transform_block_size_minus2)); - ue(vseq_var(log2_diff_max_min_transform_block_size)); - ue(vseq_var(max_transform_hierarchy_depth_inter)); - ue(vseq_var(max_transform_hierarchy_depth_intra)); - - u(1, vseq_field(scaling_list_enabled_flag)); - if (vseq->seq_fields.bits.scaling_list_enabled_flag) { - u(1, 0, sps_scaling_list_data_present_flag); - } - - u(1, vseq_field(amp_enabled_flag)); - u(1, vseq_field(sample_adaptive_offset_enabled_flag)); - - u(1, vseq_field(pcm_enabled_flag)); - if (vseq->seq_fields.bits.pcm_enabled_flag) { - u(4, vseq_var(pcm_sample_bit_depth_luma_minus1)); - u(4, vseq_var(pcm_sample_bit_depth_chroma_minus1)); - ue(vseq_var(log2_min_pcm_luma_coding_block_size_minus3)); - ue(vseq->log2_max_pcm_luma_coding_block_size_minus3 - - vseq->log2_min_pcm_luma_coding_block_size_minus3, - log2_diff_max_min_pcm_luma_coding_block_size); - u(1, vseq_field(pcm_loop_filter_disabled_flag)); - } - - ue(mseq_var(num_short_term_ref_pic_sets)); - for (i = 0; i < mseq->num_short_term_ref_pic_sets; i++) - vaapi_encode_h265_write_st_ref_pic_set(pbc, i, - &mseq->st_ref_pic_set[i]); - - u(1, mseq_var(long_term_ref_pics_present_flag)); - if (mseq->long_term_ref_pics_present_flag) { - ue(0, num_long_term_ref_pics_sps); - } - - u(1, vseq_field(sps_temporal_mvp_enabled_flag)); - u(1, vseq_field(strong_intra_smoothing_enabled_flag)); - - u(1, mseq_var(vui_parameters_present_flag)); - if (mseq->vui_parameters_present_flag) { - vaapi_encode_h265_write_vui_parameters(pbc, ctx); - } - - u(1, 0, sps_extension_present_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); -} - -static void vaapi_encode_h265_write_pps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) +static int vaapi_encode_h265_write_access_unit(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *au) { - VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_PPS); - - ue(vpic->slice_pic_parameter_set_id, pps_pic_parameter_set_id); - ue(mseq->seq_parameter_set_id, pps_seq_parameter_set_id); - - u(1, vpic_field(dependent_slice_segments_enabled_flag)); - u(1, mseq_var(output_flag_present_flag)); - u(3, mseq_var(num_extra_slice_header_bits)); - u(1, vpic_field(sign_data_hiding_enabled_flag)); - u(1, mseq_var(cabac_init_present_flag)); - - ue(vpic_var(num_ref_idx_l0_default_active_minus1)); - ue(vpic_var(num_ref_idx_l1_default_active_minus1)); - - se(vpic->pic_init_qp - 26, init_qp_minus26); - - u(1, vpic_field(constrained_intra_pred_flag)); - u(1, vpic_field(transform_skip_enabled_flag)); - - u(1, vpic_field(cu_qp_delta_enabled_flag)); - if (vpic->pic_fields.bits.cu_qp_delta_enabled_flag) - ue(vpic_var(diff_cu_qp_delta_depth)); - - se(vpic_var(pps_cb_qp_offset)); - se(vpic_var(pps_cr_qp_offset)); - - u(1, mseq_var(pps_slice_chroma_qp_offsets_present_flag)); - u(1, vpic_field(weighted_pred_flag)); - u(1, vpic_field(weighted_bipred_flag)); - u(1, vpic_field(transquant_bypass_enabled_flag)); - u(1, vpic_field(tiles_enabled_flag)); - u(1, vpic_field(entropy_coding_sync_enabled_flag)); + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + int err; - if (vpic->pic_fields.bits.tiles_enabled_flag) { - ue(vpic_var(num_tile_columns_minus1)); - ue(vpic_var(num_tile_rows_minus1)); - u(1, mseq_var(uniform_spacing_flag)); - if (!mseq->uniform_spacing_flag) { - for (i = 0; i < vpic->num_tile_columns_minus1; i++) - ue(vpic_var(column_width_minus1[i])); - for (i = 0; i < vpic->num_tile_rows_minus1; i++) - ue(vpic_var(row_height_minus1[i])); - } - u(1, vpic_field(loop_filter_across_tiles_enabled_flag)); + err = ff_cbs_write_fragment_data(&priv->cbc, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; } - u(1, vpic_field(pps_loop_filter_across_slices_enabled_flag)); - u(1, mseq_var(deblocking_filter_control_present_flag)); - if (mseq->deblocking_filter_control_present_flag) { - u(1, mseq_var(deblocking_filter_override_enabled_flag)); - u(1, mseq_var(pps_deblocking_filter_disabled_flag)); - if (!mseq->pps_deblocking_filter_disabled_flag) { - se(mseq_var(pps_beta_offset_div2)); - se(mseq_var(pps_tc_offset_div2)); - } + if (*data_len < 8 * au->data_size - au->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * au->data_size - au->data_bit_padding); + return AVERROR(ENOSPC); } - u(1, 0, pps_scaling_list_data_present_flag); - // No scaling list data. + memcpy(data, au->data, au->data_size); + *data_len = 8 * au->data_size - au->data_bit_padding; - u(1, mseq_var(lists_modification_present_flag)); - ue(vpic_var(log2_parallel_merge_level_minus2)); - u(1, 0, slice_segment_header_extension_present_flag); - u(1, 0, pps_extension_present_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); + return 0; } -static void vaapi_encode_h265_write_slice_header2(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice) +static int vaapi_encode_h265_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) { - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAAPIEncodeH265Slice *pslice = slice->priv_data; - VAAPIEncodeH265MiscSliceParams *mslice = &pslice->misc_slice_params; - int i; - - vaapi_encode_h265_write_nal_unit_header(pbc, vpic->nal_unit_type); - - u(1, mslice_var(first_slice_segment_in_pic_flag)); - if (vpic->nal_unit_type >= HEVC_NAL_BLA_W_LP && - vpic->nal_unit_type <= 23) - u(1, mslice_var(no_output_of_prior_pics_flag)); - - ue(vslice_var(slice_pic_parameter_set_id)); - - if (!mslice->first_slice_segment_in_pic_flag) { - if (vpic->pic_fields.bits.dependent_slice_segments_enabled_flag) - u(1, vslice_field(dependent_slice_segment_flag)); - u(av_log2((priv->ctu_width * priv->ctu_height) - 1) + 1, - vslice_var(slice_segment_address)); - } - if (!vslice->slice_fields.bits.dependent_slice_segment_flag) { - for (i = 0; i < mseq->num_extra_slice_header_bits; i++) - u(1, mslice_var(slice_reserved_flag[i])); - - ue(vslice_var(slice_type)); - if (mseq->output_flag_present_flag) - u(1, 1, pic_output_flag); - if (vseq->seq_fields.bits.separate_colour_plane_flag) - u(2, vslice_field(colour_plane_id)); - if (vpic->nal_unit_type != HEVC_NAL_IDR_W_RADL && - vpic->nal_unit_type != HEVC_NAL_IDR_N_LP) { - u(4 + mseq->log2_max_pic_order_cnt_lsb_minus4, - (pslice->pic_order_cnt & - ((1 << (mseq->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1)), - slice_pic_order_cnt_lsb); - - u(1, mslice_var(short_term_ref_pic_set_sps_flag)); - if (!mslice->short_term_ref_pic_set_sps_flag) { - vaapi_encode_h265_write_st_ref_pic_set(pbc, mseq->num_short_term_ref_pic_sets, - &mslice->st_ref_pic_set); - } else if (mseq->num_short_term_ref_pic_sets > 1) { - u(av_log2(mseq->num_short_term_ref_pic_sets - 1) + 1, - mslice_var(short_term_ref_pic_idx)); - } - - if (mseq->long_term_ref_pics_present_flag) { - av_assert0(0); - } - } - - if (vseq->seq_fields.bits.sps_temporal_mvp_enabled_flag) { - u(1, vslice_field(slice_temporal_mvp_enabled_flag)); - } - - if (vseq->seq_fields.bits.sample_adaptive_offset_enabled_flag) { - u(1, vslice_field(slice_sao_luma_flag)); - if (!vseq->seq_fields.bits.separate_colour_plane_flag && - vseq->seq_fields.bits.chroma_format_idc != 0) { - u(1, vslice_field(slice_sao_chroma_flag)); - } - } - - if (vslice->slice_type == HEVC_SLICE_P || vslice->slice_type == HEVC_SLICE_B) { - u(1, vslice_field(num_ref_idx_active_override_flag)); - if (vslice->slice_fields.bits.num_ref_idx_active_override_flag) { - ue(vslice_var(num_ref_idx_l0_active_minus1)); - if (vslice->slice_type == HEVC_SLICE_B) { - ue(vslice_var(num_ref_idx_l1_active_minus1)); - } - } - - if (mseq->lists_modification_present_flag) { - av_assert0(0); - // ref_pic_lists_modification() - } - if (vslice->slice_type == HEVC_SLICE_B) { - u(1, vslice_field(mvd_l1_zero_flag)); - } - if (mseq->cabac_init_present_flag) { - u(1, vslice_field(cabac_init_flag)); - } - if (vslice->slice_fields.bits.slice_temporal_mvp_enabled_flag) { - if (vslice->slice_type == HEVC_SLICE_B) - u(1, vslice_field(collocated_from_l0_flag)); - ue(vpic->collocated_ref_pic_index, collocated_ref_idx); - } - if ((vpic->pic_fields.bits.weighted_pred_flag && - vslice->slice_type == HEVC_SLICE_P) || - (vpic->pic_fields.bits.weighted_bipred_flag && - vslice->slice_type == HEVC_SLICE_B)) { - av_assert0(0); - // pred_weight_table() - } - ue(5 - vslice->max_num_merge_cand, five_minus_max_num_merge_cand); - } - - se(vslice_var(slice_qp_delta)); - if (mseq->pps_slice_chroma_qp_offsets_present_flag) { - se(vslice_var(slice_cb_qp_offset)); - se(vslice_var(slice_cr_qp_offset)); - } - if (mseq->pps_slice_chroma_offset_list_enabled_flag) { - u(1, 0, cu_chroma_qp_offset_enabled_flag); - } - if (mseq->deblocking_filter_override_enabled_flag) { - u(1, mslice_var(deblocking_filter_override_flag)); - } - if (mslice->deblocking_filter_override_flag) { - u(1, vslice_field(slice_deblocking_filter_disabled_flag)); - if (!vslice->slice_fields.bits.slice_deblocking_filter_disabled_flag) { - se(vslice_var(slice_beta_offset_div2)); - se(vslice_var(slice_tc_offset_div2)); - } - } - if (vpic->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag && - (vslice->slice_fields.bits.slice_sao_luma_flag || - vslice->slice_fields.bits.slice_sao_chroma_flag || - vslice->slice_fields.bits.slice_deblocking_filter_disabled_flag)) { - u(1, vslice_field(slice_loop_filter_across_slices_enabled_flag)); - } - - if (vpic->pic_fields.bits.tiles_enabled_flag || - vpic->pic_fields.bits.entropy_coding_sync_enabled_flag) { - // num_entry_point_offsets - } + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + H265RawNALUnitHeader *header = nal_unit; + int err; - if (0) { - // slice_segment_header_extension_length - } + err = ff_cbs_insert_unit_content(&priv->cbc, au, -1, + header->nal_unit_type, nal_unit); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add NAL unit: " + "type = %d.\n", header->nal_unit_type); + return err; } - u(1, 1, alignment_bit_equal_to_one); - while (put_bits_count(pbc) & 7) - u(1, 0, alignment_bit_equal_to_zero); + return 0; } static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; int err; - size_t nal_len, bit_len, bit_pos, next_len; - - bit_len = *data_len; - bit_pos = 0; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_vps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->vps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_sps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->sps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_pps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->pps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - *data_len = bit_pos; - return 0; + err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(&priv->cbc, au); + return err; } static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, @@ -763,195 +140,377 @@ static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, VAAPIEncodeSlice *slice, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - size_t header_len; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_slice_header2(&pbc, ctx, pic, slice); - header_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->slice); + if (err < 0) + goto fail; - return ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data, data_len, - tmp, header_len); + err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(&priv->cbc, au); + return err; } static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + H265RawVPS *vps = &priv->vps; + H265RawSPS *sps = &priv->sps; + H265RawPPS *pps = &priv->pps; + H265RawVUI *vui = &sps->vui; + VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; + VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; int i; - { - // general_profile_space == 0. - vseq->general_profile_idc = 1; // Main profile (ctx->codec_profile?) - vseq->general_tier_flag = 0; - - vseq->general_level_idc = avctx->level * 3; - - vseq->intra_period = 0; - vseq->intra_idr_period = 0; - vseq->ip_period = 0; - - vseq->pic_width_in_luma_samples = ctx->surface_width; - vseq->pic_height_in_luma_samples = ctx->surface_height; - - vseq->seq_fields.bits.chroma_format_idc = 1; // 4:2:0. - vseq->seq_fields.bits.separate_colour_plane_flag = 0; - vseq->seq_fields.bits.bit_depth_luma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - vseq->seq_fields.bits.bit_depth_chroma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - // Other misc flags all zero. - - // These have to come from the capabilities of the encoder. We have - // no way to query it, so just hardcode ones which worked for me... - // CTB size from 8x8 to 32x32. - vseq->log2_min_luma_coding_block_size_minus3 = 0; - vseq->log2_diff_max_min_luma_coding_block_size = 2; - // Transform size from 4x4 to 32x32. - vseq->log2_min_transform_block_size_minus2 = 0; - vseq->log2_diff_max_min_transform_block_size = 3; - // Full transform hierarchy allowed (2-5). - vseq->max_transform_hierarchy_depth_inter = 3; - vseq->max_transform_hierarchy_depth_intra = 3; - - vseq->vui_parameters_present_flag = 0; - - vseq->bits_per_second = avctx->bit_rate; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - vseq->vui_num_units_in_tick = avctx->framerate.den; - vseq->vui_time_scale = avctx->framerate.num; - } else { - vseq->vui_num_units_in_tick = avctx->time_base.num; - vseq->vui_time_scale = avctx->time_base.den; - } + memset(&priv->current_access_unit, 0, + sizeof(priv->current_access_unit)); - vseq->intra_period = avctx->gop_size; - vseq->intra_idr_period = avctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; - } + memset(vps, 0, sizeof(*vps)); + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); - { - vpic->decoded_curr_pic.picture_id = VA_INVALID_ID; - vpic->decoded_curr_pic.flags = VA_PICTURE_HEVC_INVALID; - for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) { - vpic->reference_frames[i].picture_id = VA_INVALID_ID; - vpic->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; - } + // VPS - vpic->collocated_ref_pic_index = 0xff; + vps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_VPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; - vpic->last_picture = 0; + vps->vps_video_parameter_set_id = 0; - vpic->pic_init_qp = priv->fixed_qp_idr; + vps->vps_base_layer_internal_flag = 1; + vps->vps_base_layer_available_flag = 1; + vps->vps_max_layers_minus1 = 0; + vps->vps_max_sub_layers_minus1 = 0; + vps->vps_temporal_id_nesting_flag = 1; - vpic->diff_cu_qp_delta_depth = 0; - vpic->pps_cb_qp_offset = 0; - vpic->pps_cr_qp_offset = 0; + vps->profile_tier_level = (H265RawProfileTierLevel) { + .general_profile_space = 0, + .general_profile_idc = avctx->profile, + .general_tier_flag = 0, - // tiles_enabled_flag == 0, so ignore num_tile_(rows|columns)_minus1. + .general_progressive_source_flag = 1, + .general_interlaced_source_flag = 0, + .general_non_packed_constraint_flag = 1, + .general_frame_only_constraint_flag = 1, - vpic->log2_parallel_merge_level_minus2 = 0; + .general_level_idc = avctx->level, + }; + vps->profile_tier_level.general_profile_compatibility_flag[avctx->profile & 31] = 1; - // No limit on size. - vpic->ctu_max_bitsize_allowed = 0; + vps->vps_sub_layer_ordering_info_present_flag = 0; + vps->vps_max_dec_pic_buffering_minus1[0] = (ctx->b_per_p > 0) + 1; + vps->vps_max_num_reorder_pics[0] = (ctx->b_per_p > 0); + vps->vps_max_latency_increase_plus1[0] = 0; - vpic->num_ref_idx_l0_default_active_minus1 = 0; - vpic->num_ref_idx_l1_default_active_minus1 = 0; + vps->vps_max_layer_id = 0; + vps->vps_num_layer_sets_minus1 = 0; + vps->layer_id_included_flag[0][0] = 1; - vpic->slice_pic_parameter_set_id = 0; + vps->vps_timing_info_present_flag = 1; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + vps->vps_num_units_in_tick = avctx->framerate.den; + vps->vps_time_scale = avctx->framerate.num; + vps->vps_poc_proportional_to_timing_flag = 1; + vps->vps_num_ticks_poc_diff_one_minus1 = 0; + } else { + vps->vps_num_units_in_tick = avctx->time_base.num; + vps->vps_time_scale = avctx->time_base.den; + vps->vps_poc_proportional_to_timing_flag = 0; + } + vps->vps_num_hrd_parameters = 0; - vpic->pic_fields.bits.screen_content_flag = 0; - vpic->pic_fields.bits.enable_gpu_weighted_prediction = 0; - // Per-CU QP changes are required for non-constant-QP modes. - vpic->pic_fields.bits.cu_qp_delta_enabled_flag = - ctx->va_rc_mode != VA_RC_CQP; - } + // SPS - { - mseq->video_parameter_set_id = 5; - mseq->seq_parameter_set_id = 5; + sps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_SPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; - mseq->vps_max_layers_minus1 = 0; - mseq->vps_max_sub_layers_minus1 = 0; - mseq->vps_temporal_id_nesting_flag = 1; - mseq->sps_max_sub_layers_minus1 = 0; - mseq->sps_temporal_id_nesting_flag = 1; + sps->sps_video_parameter_set_id = vps->vps_video_parameter_set_id; - for (i = 0; i < 32; i++) { - mseq->general_profile_compatibility_flag[i] = - (i == vseq->general_profile_idc); - } + sps->sps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1; + sps->sps_temporal_id_nesting_flag = vps->vps_temporal_id_nesting_flag; - mseq->general_progressive_source_flag = 1; - mseq->general_interlaced_source_flag = 0; - mseq->general_non_packed_constraint_flag = 0; - mseq->general_frame_only_constraint_flag = 1; - mseq->general_inbld_flag = 0; - - mseq->log2_max_pic_order_cnt_lsb_minus4 = 8; - mseq->vps_sub_layer_ordering_info_present_flag = 0; - mseq->vps_max_dec_pic_buffering_minus1[0] = (avctx->max_b_frames > 0) + 1; - mseq->vps_max_num_reorder_pics[0] = (avctx->max_b_frames > 0); - mseq->vps_max_latency_increase_plus1[0] = 0; - mseq->sps_sub_layer_ordering_info_present_flag = 0; - mseq->sps_max_dec_pic_buffering_minus1[0] = (avctx->max_b_frames > 0) + 1; - mseq->sps_max_num_reorder_pics[0] = (avctx->max_b_frames > 0); - mseq->sps_max_latency_increase_plus1[0] = 0; - - mseq->vps_timing_info_present_flag = 1; - mseq->vps_num_units_in_tick = avctx->time_base.num; - mseq->vps_time_scale = avctx->time_base.den; - mseq->vps_poc_proportional_to_timing_flag = 1; - mseq->vps_num_ticks_poc_diff_minus1 = 0; - - if (avctx->width != ctx->surface_width || - avctx->height != ctx->surface_height) { - mseq->conformance_window_flag = 1; - mseq->conf_win_left_offset = 0; - mseq->conf_win_right_offset = - (ctx->surface_width - avctx->width) / 2; - mseq->conf_win_top_offset = 0; - mseq->conf_win_bottom_offset = - (ctx->surface_height - avctx->height) / 2; - } else { - mseq->conformance_window_flag = 0; - } + sps->profile_tier_level = vps->profile_tier_level; - mseq->num_short_term_ref_pic_sets = 0; - // STRPSs should ideally be here rather than repeated in each slice. + sps->sps_seq_parameter_set_id = 0; - mseq->vui_parameters_present_flag = 1; - if (avctx->sample_aspect_ratio.num != 0) { - mseq->aspect_ratio_info_present_flag = 1; - if (avctx->sample_aspect_ratio.num == - avctx->sample_aspect_ratio.den) { - mseq->aspect_ratio_idc = 1; - } else { - mseq->aspect_ratio_idc = 255; // Extended SAR. - mseq->sar_width = avctx->sample_aspect_ratio.num; - mseq->sar_height = avctx->sample_aspect_ratio.den; + sps->chroma_format_idc = 1; // YUV 4:2:0. + sps->separate_colour_plane_flag = 0; + + sps->pic_width_in_luma_samples = ctx->surface_width; + sps->pic_height_in_luma_samples = ctx->surface_height; + + if (avctx->width != ctx->surface_width || + avctx->height != ctx->surface_height) { + sps->conformance_window_flag = 1; + sps->conf_win_left_offset = 0; + sps->conf_win_right_offset = + (ctx->surface_width - avctx->width) / 2; + sps->conf_win_top_offset = 0; + sps->conf_win_bottom_offset = + (ctx->surface_height - avctx->height) / 2; + } else { + sps->conformance_window_flag = 0; + } + + sps->bit_depth_luma_minus8 = + avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; + sps->bit_depth_chroma_minus8 = sps->bit_depth_luma_minus8; + + sps->log2_max_pic_order_cnt_lsb_minus4 = 8; + + sps->sps_sub_layer_ordering_info_present_flag = + vps->vps_sub_layer_ordering_info_present_flag; + for (i = 0; i <= sps->sps_max_sub_layers_minus1; i++) { + sps->sps_max_dec_pic_buffering_minus1[i] = + vps->vps_max_dec_pic_buffering_minus1[i]; + sps->sps_max_num_reorder_pics[i] = + vps->vps_max_num_reorder_pics[i]; + sps->sps_max_latency_increase_plus1[i] = + vps->vps_max_latency_increase_plus1[i]; + } + + // These have to come from the capabilities of the encoder. We have no + // way to query them, so just hardcode parameters which work on the Intel + // driver. + // CTB size from 8x8 to 32x32. + sps->log2_min_luma_coding_block_size_minus3 = 0; + sps->log2_diff_max_min_luma_coding_block_size = 2; + // Transform size from 4x4 to 32x32. + sps->log2_min_luma_transform_block_size_minus2 = 0; + sps->log2_diff_max_min_luma_transform_block_size = 3; + // Full transform hierarchy allowed (2-5). + sps->max_transform_hierarchy_depth_inter = 3; + sps->max_transform_hierarchy_depth_intra = 3; + // AMP works. + sps->amp_enabled_flag = 1; + // SAO and temporal MVP do not work. + sps->sample_adaptive_offset_enabled_flag = 0; + sps->sps_temporal_mvp_enabled_flag = 0; + + sps->pcm_enabled_flag = 0; + + // STRPSs should ideally be here rather than defined individually in + // each slice, but the structure isn't completely fixed so for now + // don't bother. + sps->num_short_term_ref_pic_sets = 0; + sps->long_term_ref_pics_present_flag = 0; + + sps->vui_parameters_present_flag = 1; + + if (avctx->sample_aspect_ratio.num != 0 && + avctx->sample_aspect_ratio.den != 0) { + static const AVRational sar_idc[] = { + { 0, 0 }, + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int i; + for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (avctx->sample_aspect_ratio.num == sar_idc[i].num && + avctx->sample_aspect_ratio.den == sar_idc[i].den) { + vui->aspect_ratio_idc = i; + break; } } - if (1) { - // Should this be conditional on some of these being set? - mseq->video_signal_type_present_flag = 1; - mseq->video_format = 5; // Unspecified. - mseq->video_full_range_flag = 0; - mseq->colour_description_present_flag = 1; - mseq->colour_primaries = avctx->color_primaries; - mseq->transfer_characteristics = avctx->color_trc; - mseq->matrix_coeffs = avctx->colorspace; + if (i >= FF_ARRAY_ELEMS(sar_idc)) { + vui->aspect_ratio_idc = 255; + vui->sar_width = avctx->sample_aspect_ratio.num; + vui->sar_height = avctx->sample_aspect_ratio.den; + } + vui->aspect_ratio_info_present_flag = 1; + } + + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || + avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + vui->video_signal_type_present_flag = 1; + vui->video_format = 5; // Unspecified. + vui->video_full_range_flag = + avctx->color_range == AVCOL_RANGE_JPEG; + + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + vui->colour_description_present_flag = 1; + vui->colour_primaries = avctx->color_primaries; + vui->transfer_characteristics = avctx->color_trc; + vui->matrix_coefficients = avctx->colorspace; } + } else { + vui->video_format = 5; + vui->video_full_range_flag = 0; + vui->colour_primaries = avctx->color_primaries; + vui->transfer_characteristics = avctx->color_trc; + vui->matrix_coefficients = avctx->colorspace; + } + + if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { + vui->chroma_loc_info_present_flag = 1; + vui->chroma_sample_loc_type_top_field = + vui->chroma_sample_loc_type_bottom_field = + avctx->chroma_sample_location - 1; } + vui->vui_timing_info_present_flag = 1; + vui->vui_num_units_in_tick = vps->vps_num_units_in_tick; + vui->vui_time_scale = vps->vps_time_scale; + vui->vui_poc_proportional_to_timing_flag = vps->vps_poc_proportional_to_timing_flag; + vui->vui_num_ticks_poc_diff_one_minus1 = vps->vps_num_ticks_poc_diff_one_minus1; + vui->vui_hrd_parameters_present_flag = 0; + + vui->bitstream_restriction_flag = 1; + vui->motion_vectors_over_pic_boundaries_flag = 1; + vui->restricted_ref_pic_lists_flag = 1; + vui->max_bytes_per_pic_denom = 0; + vui->max_bits_per_min_cu_denom = 0; + vui->log2_max_mv_length_horizontal = 15; + vui->log2_max_mv_length_vertical = 15; + + + // PPS + + pps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_PPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + + pps->pps_pic_parameter_set_id = 0; + pps->pps_seq_parameter_set_id = sps->sps_seq_parameter_set_id; + + pps->num_ref_idx_l0_default_active_minus1 = 0; + pps->num_ref_idx_l1_default_active_minus1 = 0; + + pps->init_qp_minus26 = priv->fixed_qp_idr - 26; + + pps->cu_qp_delta_enabled_flag = (ctx->va_rc_mode != VA_RC_CQP); + pps->diff_cu_qp_delta_depth = 0; + + pps->pps_loop_filter_across_slices_enabled_flag = 1; + + + // Fill VAAPI parameter buffers. + + *vseq = (VAEncSequenceParameterBufferHEVC) { + .general_profile_idc = vps->profile_tier_level.general_profile_idc, + .general_level_idc = vps->profile_tier_level.general_level_idc, + .general_tier_flag = vps->profile_tier_level.general_tier_flag, + + .intra_period = avctx->gop_size, + .intra_idr_period = avctx->gop_size, + .ip_period = ctx->b_per_p + 1, + .bits_per_second = avctx->bit_rate, + + .pic_width_in_luma_samples = sps->pic_width_in_luma_samples, + .pic_height_in_luma_samples = sps->pic_height_in_luma_samples, + + .seq_fields.bits = { + .chroma_format_idc = sps->chroma_format_idc, + .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8, + .scaling_list_enabled_flag = sps->scaling_list_enabled_flag, + .strong_intra_smoothing_enabled_flag = + sps->strong_intra_smoothing_enabled_flag, + .amp_enabled_flag = sps->amp_enabled_flag, + .sample_adaptive_offset_enabled_flag = + sps->sample_adaptive_offset_enabled_flag, + .pcm_enabled_flag = sps->pcm_enabled_flag, + .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag, + .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + }, + + .log2_min_luma_coding_block_size_minus3 = + sps->log2_min_luma_coding_block_size_minus3, + .log2_diff_max_min_luma_coding_block_size = + sps->log2_diff_max_min_luma_coding_block_size, + .log2_min_transform_block_size_minus2 = + sps->log2_min_luma_transform_block_size_minus2, + .log2_diff_max_min_transform_block_size = + sps->log2_diff_max_min_luma_transform_block_size, + .max_transform_hierarchy_depth_inter = + sps->max_transform_hierarchy_depth_inter, + .max_transform_hierarchy_depth_intra = + sps->max_transform_hierarchy_depth_intra, + + .pcm_sample_bit_depth_luma_minus1 = + sps->pcm_sample_bit_depth_luma_minus1, + .pcm_sample_bit_depth_chroma_minus1 = + sps->pcm_sample_bit_depth_chroma_minus1, + .log2_min_pcm_luma_coding_block_size_minus3 = + sps->log2_min_pcm_luma_coding_block_size_minus3, + .log2_max_pcm_luma_coding_block_size_minus3 = + sps->log2_min_pcm_luma_coding_block_size_minus3 + + sps->log2_diff_max_min_pcm_luma_coding_block_size, + + .vui_parameters_present_flag = 0, + }; + + *vpic = (VAEncPictureParameterBufferHEVC) { + .decoded_curr_pic = { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_HEVC_INVALID, + }, + + .coded_buf = VA_INVALID_ID, + + .collocated_ref_pic_index = 0xff, + + .last_picture = 0, + + .pic_init_qp = pps->init_qp_minus26 + 26, + .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, + .pps_cb_qp_offset = pps->pps_cb_qp_offset, + .pps_cr_qp_offset = pps->pps_cr_qp_offset, + + .num_tile_columns_minus1 = pps->num_tile_columns_minus1, + .num_tile_rows_minus1 = pps->num_tile_rows_minus1, + + .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2, + .ctu_max_bitsize_allowed = 0, + + .num_ref_idx_l0_default_active_minus1 = + pps->num_ref_idx_l0_default_active_minus1, + .num_ref_idx_l1_default_active_minus1 = + pps->num_ref_idx_l1_default_active_minus1, + + .slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id, + + .pic_fields.bits = { + .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .transform_skip_enabled_flag = pps->transform_skip_enabled_flag, + .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_flag = pps->weighted_bipred_flag, + .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag, + .tiles_enabled_flag = pps->tiles_enabled_flag, + .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag, + .loop_filter_across_tiles_enabled_flag = + pps->loop_filter_across_tiles_enabled_flag, + .scaling_list_data_present_flag = (sps->sps_scaling_list_data_present_flag | + pps->pps_scaling_list_data_present_flag), + .screen_content_flag = 0, + .enable_gpu_weighted_prediction = 0, + .no_output_of_prior_pics_flag = 0, + }, + }; + return 0; } @@ -959,65 +518,87 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; VAAPIEncodeH265Context *priv = ctx->priv_data; + VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; int i; if (pic->type == PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); + priv->last_idr_frame = pic->display_order; + + priv->slice_nal_unit = HEVC_NAL_IDR_W_RADL; + priv->slice_type = HEVC_SLICE_I; } else { av_assert0(pic->encode_order > priv->last_idr_frame); - // Display order need not be if we have RA[SD]L pictures, though. + + if (pic->type == PICTURE_TYPE_I) { + priv->slice_nal_unit = HEVC_NAL_CRA_NUT; + priv->slice_type = HEVC_SLICE_I; + } else if (pic->type == PICTURE_TYPE_P) { + av_assert0(pic->refs[0]); + priv->slice_nal_unit = HEVC_NAL_TRAIL_R; + priv->slice_type = HEVC_SLICE_P; + } else { + av_assert0(pic->refs[0] && pic->refs[1]); + if (pic->refs[1]->type == PICTURE_TYPE_I) + priv->slice_nal_unit = HEVC_NAL_RASL_N; + else + priv->slice_nal_unit = HEVC_NAL_TRAIL_N; + priv->slice_type = HEVC_SLICE_B; + } } + priv->pic_order_cnt = pic->display_order - priv->last_idr_frame; - vpic->decoded_curr_pic.picture_id = pic->recon_surface; - vpic->decoded_curr_pic.pic_order_cnt = - pic->display_order - priv->last_idr_frame; - vpic->decoded_curr_pic.flags = 0; + vpic->decoded_curr_pic = (VAPictureHEVC) { + .picture_id = pic->recon_surface, + .pic_order_cnt = priv->pic_order_cnt, + .flags = 0, + }; for (i = 0; i < pic->nb_refs; i++) { VAAPIEncodePicture *ref = pic->refs[i]; - av_assert0(ref); - vpic->reference_frames[i].picture_id = ref->recon_surface; - vpic->reference_frames[i].pic_order_cnt = - ref->display_order - priv->last_idr_frame; - vpic->reference_frames[i].flags = - (ref->display_order < pic->display_order ? - VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | - (ref->display_order > pic->display_order ? - VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0); + av_assert0(ref && ref->encode_order < pic->encode_order); + + vpic->reference_frames[i] = (VAPictureHEVC) { + .picture_id = ref->recon_surface, + .pic_order_cnt = ref->display_order - priv->last_idr_frame, + .flags = (ref->display_order < pic->display_order ? + VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | + (ref->display_order > pic->display_order ? + VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0), + }; } for (; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) { - vpic->reference_frames[i].picture_id = VA_INVALID_ID; - vpic->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; + vpic->reference_frames[i] = (VAPictureHEVC) { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_HEVC_INVALID, + }; } vpic->coded_buf = pic->output_buffer; + vpic->nal_unit_type = priv->slice_nal_unit; + switch (pic->type) { case PICTURE_TYPE_IDR: - vpic->nal_unit_type = HEVC_NAL_IDR_W_RADL; - vpic->pic_fields.bits.idr_pic_flag = 1; - vpic->pic_fields.bits.coding_type = 1; + vpic->pic_fields.bits.idr_pic_flag = 1; + vpic->pic_fields.bits.coding_type = 1; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_I: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 1; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 1; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_P: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 2; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 2; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_B: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 3; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 3; vpic->pic_fields.bits.reference_pic_flag = 0; break; default: @@ -1034,90 +615,40 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, VAAPIEncodeSlice *slice) { VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + const H265RawSPS *sps = &priv->sps; + const H265RawPPS *pps = &priv->pps; + H265RawSliceHeader *sh = &priv->slice.header; VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265Slice *pslice; - VAAPIEncodeH265MiscSliceParams *mslice; int i; - slice->priv_data = av_mallocz(sizeof(*pslice)); - if (!slice->priv_data) - return AVERROR(ENOMEM); - pslice = slice->priv_data; - mslice = &pslice->misc_slice_params; - - // Currently we only support one slice per frame. - vslice->slice_segment_address = 0; - vslice->num_ctu_in_slice = priv->ctu_width * priv->ctu_height; - - switch (pic->type) { - case PICTURE_TYPE_IDR: - case PICTURE_TYPE_I: - vslice->slice_type = HEVC_SLICE_I; - break; - case PICTURE_TYPE_P: - vslice->slice_type = HEVC_SLICE_P; - break; - case PICTURE_TYPE_B: - vslice->slice_type = HEVC_SLICE_B; - break; - default: - av_assert0(0 && "invalid picture type"); - } - - vslice->slice_pic_parameter_set_id = vpic->slice_pic_parameter_set_id; - - pslice->pic_order_cnt = pic->display_order - priv->last_idr_frame; - - for (i = 0; i < FF_ARRAY_ELEMS(vslice->ref_pic_list0); i++) { - vslice->ref_pic_list0[i].picture_id = VA_INVALID_ID; - vslice->ref_pic_list0[i].flags = VA_PICTURE_HEVC_INVALID; - vslice->ref_pic_list1[i].picture_id = VA_INVALID_ID; - vslice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID; - } - - av_assert0(pic->nb_refs <= 2); - if (pic->nb_refs >= 1) { - // Backward reference for P- or B-frame. - av_assert0(pic->type == PICTURE_TYPE_P || - pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l0_active_minus1 = 0; - vslice->ref_pic_list0[0] = vpic->reference_frames[0]; - } - if (pic->nb_refs >= 2) { - // Forward reference for B-frame. - av_assert0(pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l1_active_minus1 = 0; - vslice->ref_pic_list1[0] = vpic->reference_frames[1]; - } + sh->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = priv->slice_nal_unit, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; - vslice->max_num_merge_cand = 5; + sh->slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id; - if (pic->type == PICTURE_TYPE_B) - vslice->slice_qp_delta = priv->fixed_qp_b - vpic->pic_init_qp; - else if (pic->type == PICTURE_TYPE_P) - vslice->slice_qp_delta = priv->fixed_qp_p - vpic->pic_init_qp; - else - vslice->slice_qp_delta = priv->fixed_qp_idr - vpic->pic_init_qp; + // Currently we only support one slice per frame. + sh->first_slice_segment_in_pic_flag = 1; + sh->slice_segment_address = 0; - vslice->slice_fields.bits.last_slice_of_pic_flag = 1; + sh->slice_type = priv->slice_type; - mslice->first_slice_segment_in_pic_flag = 1; + sh->slice_pic_order_cnt_lsb = priv->pic_order_cnt & + (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1; - if (pic->type == PICTURE_TYPE_IDR) { - // No reference pictures. - } else if (0) { - mslice->short_term_ref_pic_set_sps_flag = 1; - mslice->short_term_ref_pic_idx = 0; - } else { + if (pic->type != PICTURE_TYPE_IDR) { + H265RawSTRefPicSet *rps; VAAPIEncodePicture *st; int used; - mslice->short_term_ref_pic_set_sps_flag = 0; - mslice->st_ref_pic_set.inter_ref_pic_set_prediction_flag = 0; + sh->short_term_ref_pic_set_sps_flag = 0; + + rps = &sh->short_term_ref_pic_set; + memset(rps, 0, sizeof(*rps)); for (st = ctx->pic_start; st; st = st->next) { if (st->encode_order >= pic->encode_order) { @@ -1130,28 +661,111 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, used = 1; } if (!used) { - // Currently true, but need not be. - continue; + // Usually each picture always uses all of the others in the + // DPB as references. The one case we have to treat here is + // a non-IDR IRAP picture, which may need to hold unused + // references across itself to be used for the decoding of + // following RASL pictures. This looks for such an RASL + // picture, and keeps the reference if there is one. + VAAPIEncodePicture *rp; + for (rp = ctx->pic_start; rp; rp = rp->next) { + if (rp->encode_order < pic->encode_order) + continue; + if (rp->type != PICTURE_TYPE_B) + continue; + if (rp->refs[0] == st && rp->refs[1] == pic) + break; + } + if (!rp) + continue; } // This only works for one instance of each (delta_poc_sN_minus1 // is relative to the previous frame in the list, not relative to // the current frame directly). if (st->display_order < pic->display_order) { - i = mslice->st_ref_pic_set.num_negative_pics; - mslice->st_ref_pic_set.delta_poc_s0_minus1[i] = + rps->delta_poc_s0_minus1[rps->num_negative_pics] = pic->display_order - st->display_order - 1; - mslice->st_ref_pic_set.used_by_curr_pic_s0_flag[i] = used; - ++mslice->st_ref_pic_set.num_negative_pics; + rps->used_by_curr_pic_s0_flag[rps->num_negative_pics] = used; + ++rps->num_negative_pics; } else { - i = mslice->st_ref_pic_set.num_positive_pics; - mslice->st_ref_pic_set.delta_poc_s1_minus1[i] = + rps->delta_poc_s1_minus1[rps->num_positive_pics] = st->display_order - pic->display_order - 1; - mslice->st_ref_pic_set.used_by_curr_pic_s1_flag[i] = used; - ++mslice->st_ref_pic_set.num_positive_pics; + rps->used_by_curr_pic_s1_flag[rps->num_positive_pics] = used; + ++rps->num_positive_pics; } } + + sh->num_long_term_sps = 0; + sh->num_long_term_pics = 0; + + sh->slice_temporal_mvp_enabled_flag = + sps->sps_temporal_mvp_enabled_flag; + if (sh->slice_temporal_mvp_enabled_flag) { + sh->collocated_from_l0_flag = sh->slice_type == HEVC_SLICE_B; + sh->collocated_ref_idx = 0; + } + + sh->num_ref_idx_active_override_flag = 0; + sh->num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1; + sh->num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1; } + sh->slice_sao_luma_flag = sh->slice_sao_chroma_flag = + sps->sample_adaptive_offset_enabled_flag; + + if (pic->type == PICTURE_TYPE_B) + sh->slice_qp_delta = priv->fixed_qp_b - (pps->init_qp_minus26 + 26); + else if (pic->type == PICTURE_TYPE_P) + sh->slice_qp_delta = priv->fixed_qp_p - (pps->init_qp_minus26 + 26); + else + sh->slice_qp_delta = priv->fixed_qp_idr - (pps->init_qp_minus26 + 26); + + + *vslice = (VAEncSliceParameterBufferHEVC) { + .slice_segment_address = sh->slice_segment_address, + .num_ctu_in_slice = priv->ctu_width * priv->ctu_height, + + .slice_type = sh->slice_type, + .slice_pic_parameter_set_id = sh->slice_pic_parameter_set_id, + + .num_ref_idx_l0_active_minus1 = sh->num_ref_idx_l0_active_minus1, + .num_ref_idx_l1_active_minus1 = sh->num_ref_idx_l1_active_minus1, + .ref_pic_list0[0] = vpic->reference_frames[0], + .ref_pic_list1[0] = vpic->reference_frames[1], + + .luma_log2_weight_denom = sh->luma_log2_weight_denom, + .delta_chroma_log2_weight_denom = sh->delta_chroma_log2_weight_denom, + + .max_num_merge_cand = 5 - sh->five_minus_max_num_merge_cand, + + .slice_qp_delta = sh->slice_qp_delta, + .slice_cb_qp_offset = sh->slice_cb_qp_offset, + .slice_cr_qp_offset = sh->slice_cr_qp_offset, + + .slice_beta_offset_div2 = sh->slice_beta_offset_div2, + .slice_tc_offset_div2 = sh->slice_tc_offset_div2, + + .slice_fields.bits = { + .last_slice_of_pic_flag = 1, + .dependent_slice_segment_flag = sh->dependent_slice_segment_flag, + .colour_plane_id = sh->colour_plane_id, + .slice_temporal_mvp_enabled_flag = + sh->slice_temporal_mvp_enabled_flag, + .slice_sao_luma_flag = sh->slice_sao_luma_flag, + .slice_sao_chroma_flag = sh->slice_sao_chroma_flag, + .num_ref_idx_active_override_flag = + sh->num_ref_idx_active_override_flag, + .mvd_l1_zero_flag = sh->mvd_l1_zero_flag, + .cabac_init_flag = sh->cabac_init_flag, + .slice_deblocking_filter_disabled_flag = + sh->slice_deblocking_filter_disabled_flag, + .slice_loop_filter_across_slices_enabled_flag = + sh->slice_loop_filter_across_slices_enabled_flag, + .collocated_from_l0_flag = sh->collocated_from_l0_flag, + }, + }; + + return 0; } @@ -1160,6 +774,11 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = ctx->priv_data; VAAPIEncodeH265Options *opt = ctx->codec_options; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_HEVC, avctx); + if (err < 0) + return err; priv->ctu_width = FFALIGN(ctx->surface_width, 32) / 32; priv->ctu_height = FFALIGN(ctx->surface_height, 32) / 32; @@ -1271,6 +890,17 @@ static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_h265_close(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + + if (priv) + ff_cbs_close(&priv->cbc); + + return ff_vaapi_encode_close(avctx); +} + #define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ offsetof(VAAPIEncodeH265Options, x)) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) @@ -1309,7 +939,7 @@ AVCodec ff_hevc_vaapi_encoder = { sizeof(VAAPIEncodeH265Options)), .init = &vaapi_encode_h265_init, .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, + .close = &vaapi_encode_h265_close, .priv_class = &vaapi_encode_h265_class, .capabilities = AV_CODEC_CAP_DELAY, .defaults = vaapi_encode_h265_defaults, diff --git a/libavcodec/vaapi_encode_h26x.c b/libavcodec/vaapi_encode_h26x.c deleted file mode 100644 index d806f9b52b..0000000000 --- a/libavcodec/vaapi_encode_h26x.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 - -#include "vaapi_encode_h26x.h" - -int ff_vaapi_encode_h26x_nal_unit_to_byte_stream(uint8_t *dst, size_t *dst_bit_len, - uint8_t *src, size_t src_bit_len) -{ - size_t dp, sp; - int zero_run = 0; - size_t dst_len = *dst_bit_len / 8; - size_t src_len = (src_bit_len + 7) / 8; - int trailing_zeroes = src_len * 8 - src_bit_len; - - if (dst_len < src_len + 4) { - // Definitely doesn't fit. - goto fail; - } - - // Start code. - dst[0] = dst[1] = dst[2] = 0; - dst[3] = 1; - dp = 4; - - for (sp = 0; sp < src_len; sp++) { - if (dp >= dst_len) - goto fail; - if (zero_run < 2) { - if (src[sp] == 0) - ++zero_run; - else - zero_run = 0; - } else { - if ((src[sp] & ~3) == 0) { - // emulation_prevention_three_byte - dst[dp++] = 3; - if (dp >= dst_len) - goto fail; - } - zero_run = src[sp] == 0; - } - dst[dp++] = src[sp]; - } - - *dst_bit_len = 8 * dp - trailing_zeroes; - return 0; - -fail: - *dst_bit_len = 0; - return AVERROR(ENOSPC); -} diff --git a/libavcodec/vaapi_encode_h26x.h b/libavcodec/vaapi_encode_h26x.h deleted file mode 100644 index f8c6e13adb..0000000000 --- a/libavcodec/vaapi_encode_h26x.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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_VAAPI_ENCODE_H26X_H -#define AVCODEC_VAAPI_ENCODE_H26X_H - -#include -#include - -#include "golomb.h" -#include "put_bits.h" - - -// Debug code may be interested in the name of the syntax element being -// for tracing purposes. Here, it is just discarded. - -#define write_u(pbc, width, value, name) put_bits(pbc, width, value) -#define write_ue(pbc, value, name) set_ue_golomb(pbc, value) -#define write_se(pbc, value, name) set_se_golomb(pbc, value) - -#define u(width, ...) write_u(pbc, width, __VA_ARGS__) -#define ue(...) write_ue(pbc, __VA_ARGS__) -#define se(...) write_se(pbc, __VA_ARGS__) - - -// Copy from src to dst, applying emulation prevention. -int ff_vaapi_encode_h26x_nal_unit_to_byte_stream(uint8_t *dst, size_t *dst_len, - uint8_t *src, size_t src_len); - -#endif /* AVCODEC_VAAPI_ENCODE_H26X_H */