diff --git a/.indent_cpp_list b/.indent_cpp_list index 45d57cd500..d591601048 100644 --- a/.indent_cpp_list +++ b/.indent_cpp_list @@ -1,6 +1,7 @@ subprojects/gst-plugins-bad/ext/qt6d3d11 subprojects/gst-plugins-bad/gst-libs/gst/cuda subprojects/gst-plugins-bad/gst-libs/gst/d3d11 +subprojects/gst-plugins-bad/gst-libs/gst/dxva subprojects/gst-plugins-bad/gst-libs/gst/va subprojects/gst-plugins-bad/gst-libs/gst/winrt subprojects/gst-plugins-bad/sys/amfcodec diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/dxva-prelude.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/dxva-prelude.h new file mode 100644 index 0000000000..0bbdc66823 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/dxva-prelude.h @@ -0,0 +1,31 @@ +/* GStreamer + * Copyright (C) 2023 GStreamer developers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include + +#ifndef GST_DXVA_API +# ifdef BUILDING_GST_DXVA +# define GST_DXVA_API GST_API_EXPORT /* from config.h */ +# else +# define GST_DXVA_API GST_API_IMPORT +# endif +#endif + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxva.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxva.h new file mode 100644 index 0000000000..6498050940 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxva.h @@ -0,0 +1,30 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#ifndef GST_USE_UNSTABLE_API +#pragma message ("The dxva library from gst-plugins-bad is unstable API and may change in future.") +#pragma message ("You can define GST_USE_UNSTABLE_API to avoid this warning.") +#endif + +#include +#include +#include +#include diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1.h new file mode 100644 index 0000000000..c5e9fa0a0c --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1.h @@ -0,0 +1,339 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +/* Might not be defined in dxva.h, copied from DXVA AV1 spec available at + * https://www.microsoft.com/en-us/download/confirmation.aspx?id=101577 + * and modified with "GST_" prefix + */ +#pragma pack(push, 1) + +/* AV1 picture entry data structure */ +typedef struct _GST_DXVA_PicEntry_AV1 +{ + UINT width; + UINT height; + + // Global motion parameters + INT wmmat[6]; + union + { + struct + { + UCHAR wminvalid:1; + UCHAR wmtype:2; + UCHAR Reserved:5; + }; + UCHAR GlobalMotionFlags; + } DUMMYUNIONNAME; + + UCHAR Index; + UINT16 Reserved16Bits; + +} GST_DXVA_PicEntry_AV1; + +/* AV1 picture parameters structure */ +typedef struct _GST_DXVA_PicParams_AV1 +{ + UINT width; + UINT height; + + UINT max_width; + UINT max_height; + + UCHAR CurrPicTextureIndex; + UCHAR superres_denom; + UCHAR bitdepth; + UCHAR seq_profile; + + // Tiles: + struct + { + UCHAR cols; + UCHAR rows; + USHORT context_update_id; + USHORT widths[64]; + USHORT heights[64]; + } tiles; + + // Coding Tools + union + { + struct + { + UINT use_128x128_superblock:1; + UINT intra_edge_filter:1; + UINT interintra_compound:1; + UINT masked_compound:1; + UINT warped_motion:1; + UINT dual_filter:1; + UINT jnt_comp:1; + UINT screen_content_tools:1; + UINT integer_mv:1; + UINT cdef:1; + UINT restoration:1; + UINT film_grain:1; + UINT intrabc:1; + UINT high_precision_mv:1; + UINT switchable_motion_mode:1; + UINT filter_intra:1; + UINT disable_frame_end_update_cdf:1; + UINT disable_cdf_update:1; + UINT reference_mode:1; + UINT skip_mode:1; + UINT reduced_tx_set:1; + UINT superres:1; + UINT tx_mode:2; + UINT use_ref_frame_mvs:1; + UINT enable_ref_frame_mvs:1; + UINT reference_frame_update:1; + UINT Reserved:5; + }; + UINT32 CodingParamToolFlags; + } coding; + + // Format & Picture Info flags + union + { + struct + { + UCHAR frame_type:2; + UCHAR show_frame:1; + UCHAR showable_frame:1; + UCHAR subsampling_x:1; + UCHAR subsampling_y:1; + UCHAR mono_chrome:1; + UCHAR Reserved:1; + }; + UCHAR FormatAndPictureInfoFlags; + } format; + + // References + UCHAR primary_ref_frame; + UCHAR order_hint; + UCHAR order_hint_bits; + + GST_DXVA_PicEntry_AV1 frame_refs[7]; + UCHAR RefFrameMapTextureIndex[8]; + + // Loop filter parameters + struct + { + UCHAR filter_level[2]; + UCHAR filter_level_u; + UCHAR filter_level_v; + + UCHAR sharpness_level; + union + { + struct + { + UCHAR mode_ref_delta_enabled:1; + UCHAR mode_ref_delta_update:1; + UCHAR delta_lf_multi:1; + UCHAR delta_lf_present:1; + UCHAR Reserved:4; + }; + UCHAR ControlFlags; + } DUMMYUNIONNAME; + CHAR ref_deltas[8]; + CHAR mode_deltas[2]; + UCHAR delta_lf_res; + UCHAR frame_restoration_type[3]; + USHORT log2_restoration_unit_size[3]; + UINT16 Reserved16Bits; + } loop_filter; + + // Quantization + struct + { + union + { + struct + { + UCHAR delta_q_present:1; + UCHAR delta_q_res:2; + UCHAR Reserved:5; + }; + UCHAR ControlFlags; + } DUMMYUNIONNAME; + + UCHAR base_qindex; + CHAR y_dc_delta_q; + CHAR u_dc_delta_q; + CHAR v_dc_delta_q; + CHAR u_ac_delta_q; + CHAR v_ac_delta_q; + // using_qmatrix: + UCHAR qm_y; + UCHAR qm_u; + UCHAR qm_v; + UINT16 Reserved16Bits; + } quantization; + + // Cdef parameters + struct + { + union + { + struct + { + UCHAR damping:2; + UCHAR bits:2; + UCHAR Reserved:4; + }; + UCHAR ControlFlags; + } DUMMYUNIONNAME; + + union + { + struct + { + UCHAR primary:6; + UCHAR secondary:2; + }; + UCHAR combined; + } y_strengths[8]; + + union + { + struct + { + UCHAR primary:6; + UCHAR secondary:2; + }; + UCHAR combined; + } uv_strengths[8]; + + } cdef; + + UCHAR interp_filter; + + // Segmentation + struct + { + union + { + struct + { + UCHAR enabled:1; + UCHAR update_map:1; + UCHAR update_data:1; + UCHAR temporal_update:1; + UCHAR Reserved:4; + }; + UCHAR ControlFlags; + } DUMMYUNIONNAME; + UCHAR Reserved24Bits[3]; + + union + { + struct + { + UCHAR alt_q:1; + UCHAR alt_lf_y_v:1; + UCHAR alt_lf_y_h:1; + UCHAR alt_lf_u:1; + UCHAR alt_lf_v:1; + UCHAR ref_frame:1; + UCHAR skip:1; + UCHAR globalmv:1; + }; + UCHAR mask; + } feature_mask[8]; + + SHORT feature_data[8][8]; + + } segmentation; + + struct + { + union + { + struct + { + USHORT apply_grain:1; + USHORT scaling_shift_minus8:2; + USHORT chroma_scaling_from_luma:1; + USHORT ar_coeff_lag:2; + USHORT ar_coeff_shift_minus6:2; + USHORT grain_scale_shift:2; + USHORT overlap_flag:1; + USHORT clip_to_restricted_range:1; + USHORT matrix_coeff_is_identity:1; + USHORT Reserved:3; + }; + USHORT ControlFlags; + } DUMMYUNIONNAME; + + USHORT grain_seed; + UCHAR scaling_points_y[14][2]; + UCHAR num_y_points; + UCHAR scaling_points_cb[10][2]; + UCHAR num_cb_points; + UCHAR scaling_points_cr[10][2]; + UCHAR num_cr_points; + UCHAR ar_coeffs_y[24]; + UCHAR ar_coeffs_cb[25]; + UCHAR ar_coeffs_cr[25]; + UCHAR cb_mult; + UCHAR cb_luma_mult; + UCHAR cr_mult; + UCHAR cr_luma_mult; + UCHAR Reserved8Bits; + SHORT cb_offset; + SHORT cr_offset; + } film_grain; + + UINT Reserved32Bits; + UINT StatusReportFeedbackNumber; +} GST_DXVA_PicParams_AV1; + +/* AV1 tile structure */ +typedef struct _GST_DXVA_Tile_AV1 +{ + UINT DataOffset; + UINT DataSize; + USHORT row; + USHORT column; + UINT16 Reserved16Bits; + UCHAR anchor_frame; + UCHAR Reserved8Bits; +} GST_DXVA_Tile_AV1; + +/* AV1 status reporting data structure */ +typedef struct _GST_DXVA_Status_AV1 +{ + UINT StatusReportFeedbackNumber; + GST_DXVA_PicEntry_AV1 CurrPic; + UCHAR BufType; + UCHAR Status; + UCHAR Reserved8Bits; + USHORT NumMbsAffected; +} GST_DXVA_Status_AV1; + +#pragma pack(pop) + +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1decoder.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1decoder.cpp new file mode 100644 index 0000000000..cf9bf35e6a --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1decoder.cpp @@ -0,0 +1,691 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdxvaav1decoder.h" +#include "gstdxvaav1.h" +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_dxva_av1_decoder_debug); +#define GST_CAT_DEFAULT gst_dxva_av1_decoder_debug + +/* *INDENT-OFF* */ +struct _GstDxvaAV1DecoderPrivate +{ + GstAV1SequenceHeaderOBU seq_hdr; + GST_DXVA_PicParams_AV1 pic_params; + + std::vector tile_list; + std::vector bitstream_buffer; + GPtrArray *ref_pics = nullptr; + + guint max_width = 0; + guint max_height = 0; + guint bitdepth = 0; + + gboolean configured = FALSE; +}; +/* *INDENT-ON* */ + +static void gst_dxva_av1_decoder_finalize (GObject * object); + +static gboolean gst_dxva_av1_decoder_start (GstVideoDecoder * decoder); + +static GstFlowReturn gst_dxva_av1_decoder_new_sequence (GstAV1Decoder * decoder, + const GstAV1SequenceHeaderOBU * seq_hdr, gint max_dpb_size); +static GstFlowReturn gst_dxva_av1_decoder_new_picture (GstAV1Decoder * decoder, + GstVideoCodecFrame * frame, GstAV1Picture * picture); +static GstAV1Picture *gst_dxva_av1_decoder_duplicate_picture (GstAV1Decoder * + decoder, GstVideoCodecFrame * frame, GstAV1Picture * picture); +static GstFlowReturn +gst_dxva_av1_decoder_start_picture (GstAV1Decoder * decoder, + GstAV1Picture * picture, GstAV1Dpb * dpb); +static GstFlowReturn gst_dxva_av1_decoder_decode_tile (GstAV1Decoder * decoder, + GstAV1Picture * picture, GstAV1Tile * tile); +static GstFlowReturn gst_dxva_av1_decoder_end_picture (GstAV1Decoder * decoder, + GstAV1Picture * picture); +static GstFlowReturn gst_dxva_av1_decoder_output_picture (GstAV1Decoder * + decoder, GstVideoCodecFrame * frame, GstAV1Picture * picture); + +#define gst_dxva_av1_decoder_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstDxvaAV1Decoder, + gst_dxva_av1_decoder, GST_TYPE_AV1_DECODER, + GST_DEBUG_CATEGORY_INIT (gst_dxva_av1_decoder_debug, "dxvaav1decoder", + 0, "dxvaav1decoder")); + +static void +gst_dxva_av1_decoder_class_init (GstDxvaAV1DecoderClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GstAV1DecoderClass *av1decoder_class = GST_AV1_DECODER_CLASS (klass); + + gobject_class->finalize = gst_dxva_av1_decoder_finalize; + + decoder_class->start = GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_start); + + av1decoder_class->new_sequence = + GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_new_sequence); + av1decoder_class->new_picture = + GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_new_picture); + av1decoder_class->duplicate_picture = + GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_duplicate_picture); + av1decoder_class->start_picture = + GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_start_picture); + av1decoder_class->decode_tile = + GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_decode_tile); + av1decoder_class->end_picture = + GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_end_picture); + av1decoder_class->output_picture = + GST_DEBUG_FUNCPTR (gst_dxva_av1_decoder_output_picture); +} + +static void +gst_dxva_av1_decoder_init (GstDxvaAV1Decoder * self) +{ + self->priv = new GstDxvaAV1DecoderPrivate (); + self->priv->ref_pics = g_ptr_array_new (); +} + +static void +gst_dxva_av1_decoder_finalize (GObject * object) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (object); + GstDxvaAV1DecoderPrivate *priv = self->priv; + + g_ptr_array_unref (priv->ref_pics); + delete self->priv; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dxva_av1_decoder_reset (GstDxvaAV1Decoder * self) +{ + GstDxvaAV1DecoderPrivate *priv = self->priv; + + priv->max_width = 0; + priv->max_height = 0; + priv->bitdepth = 0; + priv->configured = FALSE; +} + +static gboolean +gst_dxva_av1_decoder_start (GstVideoDecoder * decoder) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + + gst_dxva_av1_decoder_reset (self); + + return GST_VIDEO_DECODER_CLASS (parent_class)->start (decoder); +} + +static GstFlowReturn +gst_dxva_av1_decoder_new_sequence (GstAV1Decoder * decoder, + const GstAV1SequenceHeaderOBU * seq_hdr, gint max_dpb_size) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + GstDxvaAV1DecoderPrivate *priv = self->priv; + GstDxvaAV1DecoderClass *klass = GST_DXVA_AV1_DECODER_GET_CLASS (self); + gboolean modified = FALSE; + guint max_width, max_height; + GstVideoInfo info; + GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN; + GstFlowReturn ret; + + GST_LOG_OBJECT (self, "new sequence"); + + if (seq_hdr->seq_profile != GST_AV1_PROFILE_0) { + GST_WARNING_OBJECT (self, "Unsupported profile %d", seq_hdr->seq_profile); + return GST_FLOW_NOT_NEGOTIATED; + } + + if (seq_hdr->num_planes != 3) { + GST_WARNING_OBJECT (self, "Monochrome is not supported"); + return GST_FLOW_NOT_NEGOTIATED; + } + + priv->seq_hdr = *seq_hdr; + + if (priv->bitdepth != seq_hdr->bit_depth) { + GST_INFO_OBJECT (self, "Bitdepth changed %d -> %d", priv->bitdepth, + seq_hdr->bit_depth); + priv->bitdepth = seq_hdr->bit_depth; + modified = TRUE; + } + + max_width = seq_hdr->max_frame_width_minus_1 + 1; + max_height = seq_hdr->max_frame_height_minus_1 + 1; + + if (priv->max_width != max_width || priv->max_height != max_height) { + GST_INFO_OBJECT (self, "Resolution changed %dx%d -> %dx%d", + priv->max_width, priv->max_height, max_width, max_height); + priv->max_width = max_width; + priv->max_height = max_height; + modified = TRUE; + } + + if (!modified && priv->configured) + return GST_FLOW_OK; + + if (priv->bitdepth == 8) { + out_format = GST_VIDEO_FORMAT_NV12; + } else if (priv->bitdepth == 10) { + out_format = GST_VIDEO_FORMAT_P010_10LE; + } else { + GST_WARNING_OBJECT (self, "Invalid bit-depth %d", seq_hdr->bit_depth); + priv->configured = FALSE; + return GST_FLOW_NOT_NEGOTIATED; + } + + gst_video_info_set_format (&info, + out_format, priv->max_width, priv->max_height); + + g_assert (klass->configure); + ret = klass->configure (self, decoder->input_state, &info, 0, 0, + priv->max_width, priv->max_height, max_dpb_size); + + if (ret == GST_FLOW_OK) { + priv->configured = TRUE; + if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { + GST_WARNING_OBJECT (self, "Couldn't negotiate with new sequence"); + ret = GST_FLOW_NOT_NEGOTIATED; + } + } else { + priv->configured = FALSE; + } + + return ret; +} + +static GstFlowReturn +gst_dxva_av1_decoder_new_picture (GstAV1Decoder * decoder, + GstVideoCodecFrame * frame, GstAV1Picture * picture) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + GstDxvaAV1DecoderClass *klass = GST_DXVA_AV1_DECODER_GET_CLASS (self); + + g_assert (klass->new_picture); + + return klass->new_picture (self, GST_CODEC_PICTURE (picture)); +} + +static GstAV1Picture * +gst_dxva_av1_decoder_duplicate_picture (GstAV1Decoder * decoder, + GstVideoCodecFrame * frame, GstAV1Picture * picture) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + GstDxvaAV1DecoderClass *klass = GST_DXVA_AV1_DECODER_GET_CLASS (self); + GstAV1Picture *new_picture; + + g_assert (klass->duplicate_picture); + + new_picture = gst_av1_picture_new (); + if (klass->duplicate_picture (self, GST_CODEC_PICTURE (picture), + GST_CODEC_PICTURE (new_picture)) != GST_FLOW_OK) { + gst_av1_picture_unref (new_picture); + return nullptr; + } + + return new_picture; +} + +static GstFlowReturn +gst_dxva_av1_decoder_start_picture (GstAV1Decoder * decoder, + GstAV1Picture * picture, GstAV1Dpb * dpb) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + GstDxvaAV1DecoderPrivate *priv = self->priv; + GstDxvaAV1DecoderClass *klass = GST_DXVA_AV1_DECODER_GET_CLASS (self); + const GstAV1SequenceHeaderOBU *seq_hdr = &priv->seq_hdr; + const GstAV1FrameHeaderOBU *frame_hdr = &picture->frame_hdr; + GST_DXVA_PicParams_AV1 *pic_params = &priv->pic_params; + GstCodecPicture *codec_picture = GST_CODEC_PICTURE (picture); + guint i, j; + GstFlowReturn ret; + guint8 picture_id; + + g_assert (klass->start_picture); + g_assert (klass->get_picture_id); + + ret = klass->start_picture (self, codec_picture, &picture_id); + if (ret != GST_FLOW_OK) + return ret; + + priv->bitstream_buffer.resize (0); + priv->tile_list.resize (0); + g_ptr_array_set_size (priv->ref_pics, 0); + + memset (pic_params, 0, sizeof (GST_DXVA_PicParams_AV1)); + + pic_params->width = frame_hdr->frame_width; + pic_params->height = frame_hdr->frame_height; + + pic_params->max_width = seq_hdr->max_frame_width_minus_1 + 1; + pic_params->max_height = seq_hdr->max_frame_height_minus_1 + 1; + + pic_params->CurrPicTextureIndex = picture_id; + pic_params->superres_denom = frame_hdr->superres_denom; + pic_params->bitdepth = seq_hdr->bit_depth; + pic_params->seq_profile = seq_hdr->seq_profile; + + /* TILES */ + pic_params->tiles.cols = frame_hdr->tile_info.tile_cols; + pic_params->tiles.rows = frame_hdr->tile_info.tile_rows; + pic_params->tiles.context_update_id = + frame_hdr->tile_info.context_update_tile_id; + + for (i = 0; i < pic_params->tiles.cols; i++) { + pic_params->tiles.widths[i] = + frame_hdr->tile_info.width_in_sbs_minus_1[i] + 1; + } + + for (i = 0; i < pic_params->tiles.rows; i++) { + pic_params->tiles.heights[i] = + frame_hdr->tile_info.height_in_sbs_minus_1[i] + 1; + } + + /* CODING TOOLS */ + pic_params->coding.use_128x128_superblock = seq_hdr->use_128x128_superblock; + pic_params->coding.intra_edge_filter = seq_hdr->enable_filter_intra; + pic_params->coding.interintra_compound = seq_hdr->enable_interintra_compound; + pic_params->coding.masked_compound = seq_hdr->enable_masked_compound; + pic_params->coding.warped_motion = frame_hdr->allow_warped_motion; + pic_params->coding.dual_filter = seq_hdr->enable_dual_filter; + pic_params->coding.jnt_comp = seq_hdr->enable_jnt_comp; + pic_params->coding.screen_content_tools = + frame_hdr->allow_screen_content_tools; + pic_params->coding.integer_mv = frame_hdr->force_integer_mv; + pic_params->coding.cdef = seq_hdr->enable_cdef; + pic_params->coding.restoration = seq_hdr->enable_restoration; + pic_params->coding.film_grain = seq_hdr->film_grain_params_present; + pic_params->coding.intrabc = frame_hdr->allow_intrabc; + pic_params->coding.high_precision_mv = frame_hdr->allow_high_precision_mv; + pic_params->coding.switchable_motion_mode = + frame_hdr->is_motion_mode_switchable; + pic_params->coding.filter_intra = seq_hdr->enable_filter_intra; + pic_params->coding.disable_frame_end_update_cdf = + frame_hdr->disable_frame_end_update_cdf; + pic_params->coding.disable_cdf_update = frame_hdr->disable_cdf_update; + pic_params->coding.reference_mode = frame_hdr->reference_select; + pic_params->coding.skip_mode = frame_hdr->skip_mode_present; + pic_params->coding.reduced_tx_set = frame_hdr->reduced_tx_set; + pic_params->coding.superres = frame_hdr->use_superres; + pic_params->coding.tx_mode = frame_hdr->tx_mode; + pic_params->coding.use_ref_frame_mvs = frame_hdr->use_ref_frame_mvs; + pic_params->coding.enable_ref_frame_mvs = seq_hdr->enable_ref_frame_mvs; + pic_params->coding.reference_frame_update = 1; + + /* FORMAT */ + pic_params->format.frame_type = frame_hdr->frame_type; + pic_params->format.show_frame = frame_hdr->show_frame; + pic_params->format.showable_frame = frame_hdr->showable_frame; + pic_params->format.subsampling_x = seq_hdr->color_config.subsampling_x; + pic_params->format.subsampling_y = seq_hdr->color_config.subsampling_y; + pic_params->format.mono_chrome = seq_hdr->color_config.mono_chrome; + + /* REFERENCES */ + pic_params->primary_ref_frame = frame_hdr->primary_ref_frame; + pic_params->order_hint = frame_hdr->order_hint; + if (seq_hdr->enable_order_hint) { + pic_params->order_hint_bits = seq_hdr->order_hint_bits_minus_1 + 1; + } else { + pic_params->order_hint_bits = 0; + } + + for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) { + if (dpb->pic_list[i]) { + GstAV1Picture *other_pic = dpb->pic_list[i]; + const GstAV1GlobalMotionParams *gmp = &frame_hdr->global_motion_params; + + pic_params->frame_refs[i].width = other_pic->frame_hdr.frame_width; + pic_params->frame_refs[i].height = other_pic->frame_hdr.frame_height; + for (j = 0; j < 6; j++) { + pic_params->frame_refs[i].wmmat[j] = + gmp->gm_params[GST_AV1_REF_LAST_FRAME + i][j]; + } + pic_params->frame_refs[i].wminvalid = + (gmp->gm_type[GST_AV1_REF_LAST_FRAME + i] == + GST_AV1_WARP_MODEL_IDENTITY); + pic_params->frame_refs[i].wmtype = + gmp->gm_type[GST_AV1_REF_LAST_FRAME + i]; + pic_params->frame_refs[i].Index = frame_hdr->ref_frame_idx[i]; + } else { + pic_params->frame_refs[i].Index = 0xff; + } + } + + for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) { + pic_params->RefFrameMapTextureIndex[i] = 0xff; + + if (dpb->pic_list[i]) { + GstAV1Picture *other_pic = dpb->pic_list[i]; + guint8 id; + + id = klass->get_picture_id (self, GST_CODEC_PICTURE (other_pic)); + if (id != 0xff) { + pic_params->RefFrameMapTextureIndex[i] = id; + g_ptr_array_add (priv->ref_pics, other_pic); + } + } + } + + /* LOOP FILTER PARAMS */ + pic_params->loop_filter.filter_level[0] = + frame_hdr->loop_filter_params.loop_filter_level[0]; + pic_params->loop_filter.filter_level[1] = + frame_hdr->loop_filter_params.loop_filter_level[1]; + pic_params->loop_filter.filter_level_u = + frame_hdr->loop_filter_params.loop_filter_level[2]; + pic_params->loop_filter.filter_level_v = + frame_hdr->loop_filter_params.loop_filter_level[3]; + pic_params->loop_filter.sharpness_level = + frame_hdr->loop_filter_params.loop_filter_sharpness; + pic_params->loop_filter.mode_ref_delta_enabled = + frame_hdr->loop_filter_params.loop_filter_delta_enabled; + pic_params->loop_filter.mode_ref_delta_update = + frame_hdr->loop_filter_params.loop_filter_delta_update; + pic_params->loop_filter.delta_lf_multi = + frame_hdr->loop_filter_params.delta_lf_multi; + pic_params->loop_filter.delta_lf_present = + frame_hdr->loop_filter_params.delta_lf_present; + + for (i = 0; i < GST_AV1_TOTAL_REFS_PER_FRAME; i++) { + pic_params->loop_filter.ref_deltas[i] = + frame_hdr->loop_filter_params.loop_filter_ref_deltas[i]; + } + + for (i = 0; i < 2; i++) { + pic_params->loop_filter.mode_deltas[i] = + frame_hdr->loop_filter_params.loop_filter_mode_deltas[i]; + } + + pic_params->loop_filter.delta_lf_res = + frame_hdr->loop_filter_params.delta_lf_res; + + for (i = 0; i < GST_AV1_MAX_NUM_PLANES; i++) { + pic_params->loop_filter.frame_restoration_type[i] = + frame_hdr->loop_restoration_params.frame_restoration_type[i]; + } + + if (frame_hdr->loop_restoration_params.uses_lr) { + pic_params->loop_filter.log2_restoration_unit_size[0] = + (6 + frame_hdr->loop_restoration_params.lr_unit_shift); + pic_params->loop_filter.log2_restoration_unit_size[1] = + pic_params->loop_filter.log2_restoration_unit_size[2] = + (6 + frame_hdr->loop_restoration_params.lr_unit_shift - + frame_hdr->loop_restoration_params.lr_uv_shift); + } else { + pic_params->loop_filter.log2_restoration_unit_size[0] = + pic_params->loop_filter.log2_restoration_unit_size[1] = + pic_params->loop_filter.log2_restoration_unit_size[2] = 8; + } + + /* QUANTIZATION */ + pic_params->quantization.delta_q_present = + frame_hdr->quantization_params.delta_q_present; + pic_params->quantization.delta_q_res = + frame_hdr->quantization_params.delta_q_res; + pic_params->quantization.base_qindex = + frame_hdr->quantization_params.base_q_idx; + pic_params->quantization.y_dc_delta_q = + frame_hdr->quantization_params.delta_q_y_dc; + pic_params->quantization.u_dc_delta_q = + frame_hdr->quantization_params.delta_q_u_dc; + pic_params->quantization.v_dc_delta_q = + frame_hdr->quantization_params.delta_q_v_dc; + pic_params->quantization.u_ac_delta_q = + frame_hdr->quantization_params.delta_q_u_ac; + pic_params->quantization.v_ac_delta_q = + frame_hdr->quantization_params.delta_q_v_ac; + if (frame_hdr->quantization_params.using_qmatrix) { + pic_params->quantization.qm_y = frame_hdr->quantization_params.qm_y; + pic_params->quantization.qm_u = frame_hdr->quantization_params.qm_u; + pic_params->quantization.qm_v = frame_hdr->quantization_params.qm_v; + } else { + pic_params->quantization.qm_y = 0xff; + pic_params->quantization.qm_u = 0xff; + pic_params->quantization.qm_v = 0xff; + } + + /* Cdef params */ + pic_params->cdef.damping = frame_hdr->cdef_params.cdef_damping - 3; + pic_params->cdef.bits = frame_hdr->cdef_params.cdef_bits; + + for (i = 0; i < GST_AV1_CDEF_MAX; i++) { + guint8 secondary; + + pic_params->cdef.y_strengths[i].primary = + frame_hdr->cdef_params.cdef_y_pri_strength[i]; + secondary = frame_hdr->cdef_params.cdef_y_sec_strength[i]; + if (secondary == 4) + secondary--; + pic_params->cdef.y_strengths[i].secondary = secondary; + + pic_params->cdef.uv_strengths[i].primary = + frame_hdr->cdef_params.cdef_uv_pri_strength[i]; + secondary = frame_hdr->cdef_params.cdef_uv_sec_strength[i]; + if (secondary == 4) + secondary--; + pic_params->cdef.uv_strengths[i].secondary = secondary; + } + + pic_params->interp_filter = frame_hdr->interpolation_filter; + + /* SEGMENTATION */ + pic_params->segmentation.enabled = + frame_hdr->segmentation_params.segmentation_enabled; + pic_params->segmentation.update_map = + frame_hdr->segmentation_params.segmentation_update_map; + pic_params->segmentation.update_data = + frame_hdr->segmentation_params.segmentation_update_data; + pic_params->segmentation.temporal_update = + frame_hdr->segmentation_params.segmentation_temporal_update; + + for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) { + for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) { + pic_params->segmentation.feature_mask[i].mask |= + (frame_hdr->segmentation_params.feature_enabled[i][j] << j); + pic_params->segmentation.feature_data[i][j] = + frame_hdr->segmentation_params.feature_data[i][j]; + } + } + + /* FILM GRAIN */ + if (frame_hdr->film_grain_params.apply_grain) { + pic_params->film_grain.apply_grain = 1; + pic_params->film_grain.scaling_shift_minus8 = + frame_hdr->film_grain_params.grain_scaling_minus_8; + pic_params->film_grain.chroma_scaling_from_luma = + frame_hdr->film_grain_params.chroma_scaling_from_luma; + pic_params->film_grain.ar_coeff_lag = + frame_hdr->film_grain_params.ar_coeff_lag; + pic_params->film_grain.ar_coeff_shift_minus6 = + frame_hdr->film_grain_params.ar_coeff_shift_minus_6; + pic_params->film_grain.grain_scale_shift = + frame_hdr->film_grain_params.grain_scale_shift; + pic_params->film_grain.overlap_flag = + frame_hdr->film_grain_params.overlap_flag; + pic_params->film_grain.clip_to_restricted_range = + frame_hdr->film_grain_params.clip_to_restricted_range; + pic_params->film_grain.matrix_coeff_is_identity = + (seq_hdr->color_config.matrix_coefficients == GST_AV1_MC_IDENTITY); + pic_params->film_grain.grain_seed = frame_hdr->film_grain_params.grain_seed; + for (i = 0; i < frame_hdr->film_grain_params.num_y_points && i < 14; i++) { + pic_params->film_grain.scaling_points_y[i][0] = + frame_hdr->film_grain_params.point_y_value[i]; + pic_params->film_grain.scaling_points_y[i][1] = + frame_hdr->film_grain_params.point_y_scaling[i]; + } + pic_params->film_grain.num_y_points = + frame_hdr->film_grain_params.num_y_points; + + for (i = 0; i < frame_hdr->film_grain_params.num_cb_points && i < 10; i++) { + pic_params->film_grain.scaling_points_cb[i][0] = + frame_hdr->film_grain_params.point_cb_value[i]; + pic_params->film_grain.scaling_points_cb[i][1] = + frame_hdr->film_grain_params.point_cb_scaling[i]; + } + pic_params->film_grain.num_cb_points = + frame_hdr->film_grain_params.num_cb_points; + + for (i = 0; i < frame_hdr->film_grain_params.num_cr_points && i < 10; i++) { + pic_params->film_grain.scaling_points_cr[i][0] = + frame_hdr->film_grain_params.point_cr_value[i]; + pic_params->film_grain.scaling_points_cr[i][1] = + frame_hdr->film_grain_params.point_cr_scaling[i]; + } + pic_params->film_grain.num_cr_points = + frame_hdr->film_grain_params.num_cr_points; + + for (i = 0; i < 24; i++) { + pic_params->film_grain.ar_coeffs_y[i] = + frame_hdr->film_grain_params.ar_coeffs_y_plus_128[i]; + } + + for (i = 0; i < 25; i++) { + pic_params->film_grain.ar_coeffs_cb[i] = + frame_hdr->film_grain_params.ar_coeffs_cb_plus_128[i]; + pic_params->film_grain.ar_coeffs_cr[i] = + frame_hdr->film_grain_params.ar_coeffs_cr_plus_128[i]; + } + + pic_params->film_grain.cb_mult = frame_hdr->film_grain_params.cb_mult; + pic_params->film_grain.cb_luma_mult = + frame_hdr->film_grain_params.cb_luma_mult; + pic_params->film_grain.cr_mult = frame_hdr->film_grain_params.cr_mult; + pic_params->film_grain.cr_luma_mult = + frame_hdr->film_grain_params.cr_luma_mult; + pic_params->film_grain.cb_offset = frame_hdr->film_grain_params.cb_offset; + pic_params->film_grain.cr_offset = frame_hdr->film_grain_params.cr_offset; + } + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_av1_decoder_decode_tile (GstAV1Decoder * decoder, + GstAV1Picture * picture, GstAV1Tile * tile) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + GstDxvaAV1DecoderPrivate *priv = self->priv; + GstAV1TileGroupOBU *tile_group = &tile->tile_group; + + if (tile_group->num_tiles > priv->tile_list.size ()) + priv->tile_list.resize (tile_group->num_tiles); + + g_assert (tile_group->tg_end < priv->tile_list.size ()); + + GST_LOG_OBJECT (self, "Decode tile, tile count %d (start: %d - end: %d)", + tile_group->num_tiles, tile_group->tg_start, tile_group->tg_end); + + for (guint i = tile_group->tg_start; i <= tile_group->tg_end; i++) { + GST_DXVA_Tile_AV1 *dxva_tile = &priv->tile_list[i]; + + GST_TRACE_OBJECT (self, + "Tile offset %d, size %d, row %d, col %d", + tile_group->entry[i].tile_offset, tile_group->entry[i].tile_size, + tile_group->entry[i].tile_row, tile_group->entry[i].tile_col); + + dxva_tile->DataOffset = priv->bitstream_buffer.size () + + tile_group->entry[i].tile_offset; + dxva_tile->DataSize = tile_group->entry[i].tile_size; + dxva_tile->row = tile_group->entry[i].tile_row; + dxva_tile->column = tile_group->entry[i].tile_col; + /* TODO: used for tile list OBU */ + dxva_tile->anchor_frame = 0xff; + } + + GST_TRACE_OBJECT (self, "OBU size %d", tile->obu.obu_size); + + size_t pos = priv->bitstream_buffer.size (); + priv->bitstream_buffer.resize (pos + tile->obu.obu_size); + + memcpy (&priv->bitstream_buffer[0] + pos, tile->obu.data, tile->obu.obu_size); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_av1_decoder_end_picture (GstAV1Decoder * decoder, + GstAV1Picture * picture) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + GstDxvaAV1DecoderPrivate *priv = self->priv; + GstDxvaAV1DecoderClass *klass = GST_DXVA_AV1_DECODER_GET_CLASS (self); + size_t bitstream_buffer_size; + size_t bitstream_pos; + GstDxvaDecodingArgs args; + + if (priv->bitstream_buffer.empty () || priv->tile_list.empty ()) { + GST_ERROR_OBJECT (self, "No bitstream buffer to submit"); + return GST_FLOW_ERROR; + } + + memset (&args, 0, sizeof (GstDxvaDecodingArgs)); + + bitstream_pos = priv->bitstream_buffer.size (); + bitstream_buffer_size = GST_ROUND_UP_128 (bitstream_pos); + + if (bitstream_buffer_size > bitstream_pos) { + size_t padding = bitstream_buffer_size - bitstream_pos; + + /* As per DXVA spec, total amount of bitstream buffer size should be + * 128 bytes aligned. If actual data is not multiple of 128 bytes, + * the last slice data needs to be zero-padded */ + priv->bitstream_buffer.resize (bitstream_buffer_size, 0); + + GST_DXVA_Tile_AV1 & tile = priv->tile_list.back (); + tile.DataSize += padding; + } + + args.picture_params = &priv->pic_params; + args.picture_params_size = sizeof (GST_DXVA_PicParams_AV1); + args.slice_control = &priv->tile_list[0]; + args.slice_control_size = + sizeof (GST_DXVA_Tile_AV1) * priv->tile_list.size (); + args.bitstream = &priv->bitstream_buffer[0]; + args.bitstream_size = priv->bitstream_buffer.size (); + + g_assert (klass->end_picture); + + return klass->end_picture (self, GST_CODEC_PICTURE (picture), + priv->ref_pics, &args); +} + +static GstFlowReturn +gst_dxva_av1_decoder_output_picture (GstAV1Decoder * decoder, + GstVideoCodecFrame * frame, GstAV1Picture * picture) +{ + GstDxvaAV1Decoder *self = GST_DXVA_AV1_DECODER (decoder); + GstDxvaAV1DecoderClass *klass = GST_DXVA_AV1_DECODER_GET_CLASS (self); + + g_assert (klass->output_picture); + + GST_LOG_OBJECT (self, "Outputting picture %p, %dx%d", picture, + picture->frame_hdr.render_width, picture->frame_hdr.render_height); + + return klass->output_picture (self, frame, GST_CODEC_PICTURE (picture), + (GstVideoBufferFlags) 0, picture->frame_hdr.render_width, + picture->frame_hdr.render_height); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1decoder.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1decoder.h new file mode 100644 index 0000000000..404352e893 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvaav1decoder.h @@ -0,0 +1,94 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DXVA_AV1_DECODER (gst_dxva_av1_decoder_get_type()) +#define GST_DXVA_AV1_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DXVA_AV1_DECODER,GstDxvaAV1Decoder)) +#define GST_DXVA_AV1_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DXVA_AV1_DECODER,GstDxvaAV1DecoderClass)) +#define GST_DXVA_AV1_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_DXVA_AV1_DECODER,GstDxvaAV1DecoderClass)) +#define GST_IS_DXVA_AV1_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DXVA_AV1_DECODER)) +#define GST_IS_DXVA_AV1_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DXVA_AV1_DECODER)) +#define GST_DXVA_AV1_DECODER_CAST(obj) ((GstDxvaAV1Decoder*)obj) + +typedef struct _GstDxvaAV1Decoder GstDxvaAV1Decoder; +typedef struct _GstDxvaAV1DecoderClass GstDxvaAV1DecoderClass; +typedef struct _GstDxvaAV1DecoderPrivate GstDxvaAV1DecoderPrivate; + +struct _GstDxvaAV1Decoder +{ + GstAV1Decoder parent; + + /*< private >*/ + GstDxvaAV1DecoderPrivate *priv; +}; + +struct _GstDxvaAV1DecoderClass +{ + GstAV1DecoderClass parent_class; + + GstFlowReturn (*configure) (GstDxvaAV1Decoder * decoder, + GstVideoCodecState * input_state, + const GstVideoInfo * info, + gint crop_x, + gint crop_y, + gint coded_width, + gint coded_height, + gint max_dpb_size); + + GstFlowReturn (*new_picture) (GstDxvaAV1Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*duplicate_picture) (GstDxvaAV1Decoder * decoder, + GstCodecPicture * src, + GstCodecPicture * dst); + + guint8 (*get_picture_id) (GstDxvaAV1Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*start_picture) (GstDxvaAV1Decoder * decoder, + GstCodecPicture * picture, + guint8 * picture_id); + + GstFlowReturn (*end_picture) (GstDxvaAV1Decoder * decoder, + GstCodecPicture * picture, + GPtrArray * ref_pics, + const GstDxvaDecodingArgs * args); + + GstFlowReturn (*output_picture) (GstDxvaAV1Decoder * decoder, + GstVideoCodecFrame * frame, + GstCodecPicture * picture, + GstVideoBufferFlags buffer_flags, + gint display_width, + gint display_height); +}; + +GST_DXVA_API +GType gst_dxva_av1_decoder_get_type (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstDxvaAV1Decoder, gst_object_unref) + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah264decoder.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah264decoder.cpp new file mode 100644 index 0000000000..a3763f656e --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah264decoder.cpp @@ -0,0 +1,642 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdxvah264decoder.h" +#include +#include + +/* HACK: to expose dxva data structure on UWP */ +#ifdef WINAPI_PARTITION_DESKTOP +#undef WINAPI_PARTITION_DESKTOP +#endif +#define WINAPI_PARTITION_DESKTOP 1 +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_dxva_h264_decoder_debug); +#define GST_CAT_DEFAULT gst_dxva_h264_decoder_debug + +/* *INDENT-OFF* */ +struct _GstDxvaH264DecoderPrivate +{ + DXVA_PicParams_H264 pic_params; + DXVA_Qmatrix_H264 iq_matrix; + + std::vector slice_list; + std::vector bitstream_buffer; + GPtrArray *ref_pics = nullptr; + + gint crop_x = 0; + gint crop_y = 0; + gint width = 0; + gint height = 0; + gint coded_width = 0; + gint coded_height = 0; + gint bitdepth = 0; + guint8 chroma_format_idc = 0; + GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN; + gboolean interlaced = FALSE; + gint max_dpb_size = 0; + + gboolean configured = FALSE; +}; +/* *INDENT-ON* */ + +static void gst_dxva_h264_decoder_finalize (GObject * object); + +static gboolean gst_dxva_h264_decoder_start (GstVideoDecoder * decoder); + +static GstFlowReturn +gst_dxva_h264_decoder_new_sequence (GstH264Decoder * decoder, + const GstH264SPS * sps, gint max_dpb_size); +static GstFlowReturn +gst_dxva_h264_decoder_new_picture (GstH264Decoder * decoder, + GstVideoCodecFrame * frame, GstH264Picture * picture); +static GstFlowReturn +gst_dxva_h264_decoder_new_field_picture (GstH264Decoder * decoder, + GstH264Picture * first_field, GstH264Picture * second_field); +static GstFlowReturn +gst_dxva_h264_decoder_start_picture (GstH264Decoder * decoder, + GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb); +static GstFlowReturn +gst_dxva_h264_decoder_decode_slice (GstH264Decoder * decoder, + GstH264Picture * picture, GstH264Slice * slice, GArray * ref_pic_list0, + GArray * ref_pic_list1); +static GstFlowReturn +gst_dxva_h264_decoder_end_picture (GstH264Decoder * decoder, + GstH264Picture * picture); +static GstFlowReturn +gst_dxva_h264_decoder_output_picture (GstH264Decoder * decoder, + GstVideoCodecFrame * frame, GstH264Picture * picture); + +#define gst_dxva_h264_decoder_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstDxvaH264Decoder, + gst_dxva_h264_decoder, GST_TYPE_H264_DECODER, + GST_DEBUG_CATEGORY_INIT (gst_dxva_h264_decoder_debug, "dxvah264decoder", + 0, "dxvah264decoder")); + +static void +gst_dxva_h264_decoder_class_init (GstDxvaH264DecoderClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GstH264DecoderClass *h264decoder_class = GST_H264_DECODER_CLASS (klass); + + object_class->finalize = gst_dxva_h264_decoder_finalize; + + decoder_class->start = GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_start); + + h264decoder_class->new_sequence = + GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_new_sequence); + h264decoder_class->new_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_new_picture); + h264decoder_class->new_field_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_new_field_picture); + h264decoder_class->start_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_start_picture); + h264decoder_class->decode_slice = + GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_decode_slice); + h264decoder_class->end_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_end_picture); + h264decoder_class->output_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h264_decoder_output_picture); +} + +static void +gst_dxva_h264_decoder_init (GstDxvaH264Decoder * self) +{ + self->priv = new GstDxvaH264DecoderPrivate (); + self->priv->ref_pics = g_ptr_array_new (); +} + +static void +gst_dxva_h264_decoder_finalize (GObject * object) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (object); + GstDxvaH264DecoderPrivate *priv = self->priv; + + g_ptr_array_unref (priv->ref_pics); + delete self->priv; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dxva_h264_decoder_reset (GstDxvaH264Decoder * self) +{ + GstDxvaH264DecoderPrivate *priv = self->priv; + + priv->crop_x = 0; + priv->crop_y = 0; + priv->width = 0; + priv->height = 0; + priv->coded_width = 0; + priv->coded_height = 0; + priv->bitdepth = 0; + priv->chroma_format_idc = 0; + priv->out_format = GST_VIDEO_FORMAT_UNKNOWN; + priv->interlaced = FALSE; + priv->max_dpb_size = 0; + priv->configured = FALSE; +} + +static gboolean +gst_dxva_h264_decoder_start (GstVideoDecoder * decoder) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + + gst_dxva_h264_decoder_reset (self); + + return GST_VIDEO_DECODER_CLASS (parent_class)->start (decoder); +} + +static GstFlowReturn +gst_dxva_h264_decoder_new_sequence (GstH264Decoder * decoder, + const GstH264SPS * sps, gint max_dpb_size) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + GstDxvaH264DecoderPrivate *priv = self->priv; + GstDxvaH264DecoderClass *klass = GST_DXVA_H264_DECODER_GET_CLASS (self); + gint crop_width, crop_height; + gboolean interlaced; + gboolean modified = FALSE; + GstVideoInfo info; + GstFlowReturn ret; + + GST_LOG_OBJECT (self, "new sequence"); + + if (sps->frame_cropping_flag) { + crop_width = sps->crop_rect_width; + crop_height = sps->crop_rect_height; + } else { + crop_width = sps->width; + crop_height = sps->height; + } + + if (priv->width != crop_width || priv->height != crop_height || + priv->coded_width != sps->width || priv->coded_height != sps->height || + priv->crop_x != sps->crop_rect_x || priv->crop_y != sps->crop_rect_y) { + GST_INFO_OBJECT (self, + "resolution change, %dx%d (%dx%d) -> %dx%d (%dx%d)", + priv->width, priv->height, priv->coded_width, priv->coded_height, + crop_width, crop_height, sps->width, sps->height); + priv->crop_x = sps->crop_rect_x; + priv->crop_y = sps->crop_rect_y; + priv->width = crop_width; + priv->height = crop_height; + priv->coded_width = sps->width; + priv->coded_height = sps->height; + modified = TRUE; + } + + if (priv->bitdepth != sps->bit_depth_luma_minus8 + 8) { + gint bitdepth = sps->bit_depth_luma_minus8 + 8; + GST_INFO_OBJECT (self, + "bitdepth change, %d -> %d", priv->bitdepth, bitdepth); + priv->bitdepth = bitdepth; + modified = TRUE; + } + + if (priv->chroma_format_idc != sps->chroma_format_idc) { + GST_INFO_OBJECT (self, "chroma format change, %d -> %d", + priv->chroma_format_idc, sps->chroma_format_idc); + priv->chroma_format_idc = sps->chroma_format_idc; + modified = TRUE; + } + + interlaced = !sps->frame_mbs_only_flag; + if (priv->interlaced != interlaced) { + GST_INFO_OBJECT (self, "interlaced sequence change, %d -> %d", + priv->interlaced, interlaced); + priv->interlaced = interlaced; + modified = TRUE; + } + + if (priv->max_dpb_size < max_dpb_size) { + GST_INFO_OBJECT (self, "Requires larger DPB size (%d -> %d)", + priv->max_dpb_size, max_dpb_size); + modified = TRUE; + } + + if (!modified && priv->configured) + return GST_FLOW_OK; + + priv->out_format = GST_VIDEO_FORMAT_UNKNOWN; + + if (priv->bitdepth == 8) { + if (priv->chroma_format_idc == 1) { + priv->out_format = GST_VIDEO_FORMAT_NV12; + } else { + GST_FIXME_OBJECT (self, "Could not support 8bits non-4:2:0 format"); + } + } + + if (priv->out_format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_ERROR_OBJECT (self, "Could not support bitdepth/chroma format"); + priv->configured = FALSE; + return GST_FLOW_NOT_NEGOTIATED; + } + + gst_video_info_set_interlaced_format (&info, priv->out_format, + priv->interlaced ? GST_VIDEO_INTERLACE_MODE_MIXED : + GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, priv->width, priv->height); + + priv->max_dpb_size = max_dpb_size; + + g_assert (klass->configure); + ret = klass->configure (self, decoder->input_state, &info, priv->crop_x, + priv->crop_y, priv->coded_width, priv->coded_height, max_dpb_size); + + if (ret == GST_FLOW_OK) { + priv->configured = TRUE; + if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { + GST_WARNING_OBJECT (self, "Couldn't negotiate with new sequence"); + ret = GST_FLOW_NOT_NEGOTIATED; + } + } else { + priv->configured = FALSE; + } + + return ret; +} + +static GstFlowReturn +gst_dxva_h264_decoder_new_picture (GstH264Decoder * decoder, + GstVideoCodecFrame * frame, GstH264Picture * picture) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + GstDxvaH264DecoderClass *klass = GST_DXVA_H264_DECODER_GET_CLASS (self); + + g_assert (klass->new_picture); + + return klass->new_picture (self, GST_CODEC_PICTURE (picture)); +} + +static GstFlowReturn +gst_dxva_h264_decoder_new_field_picture (GstH264Decoder * decoder, + GstH264Picture * first_field, GstH264Picture * second_field) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + GstDxvaH264DecoderClass *klass = GST_DXVA_H264_DECODER_GET_CLASS (self); + + g_assert (klass->duplicate_picture); + + return klass->duplicate_picture (self, GST_CODEC_PICTURE (first_field), + GST_CODEC_PICTURE (second_field)); +} + +static void +gst_dxva_h264_decoder_picture_params_from_sps (GstDxvaH264Decoder * self, + const GstH264SPS * sps, gboolean field_pic, DXVA_PicParams_H264 * params) +{ +#define COPY_FIELD(f) \ + (params)->f = (sps)->f + + params->wFrameWidthInMbsMinus1 = sps->pic_width_in_mbs_minus1; + if (!sps->frame_mbs_only_flag) { + params->wFrameHeightInMbsMinus1 = + ((sps->pic_height_in_map_units_minus1 + 1) << 1) - 1; + } else { + params->wFrameHeightInMbsMinus1 = sps->pic_height_in_map_units_minus1; + } + params->residual_colour_transform_flag = sps->separate_colour_plane_flag; + params->MbaffFrameFlag = (sps->mb_adaptive_frame_field_flag && !field_pic); + params->field_pic_flag = field_pic; + params->MinLumaBipredSize8x8Flag = sps->level_idc >= 31; + + COPY_FIELD (num_ref_frames); + COPY_FIELD (chroma_format_idc); + COPY_FIELD (frame_mbs_only_flag); + COPY_FIELD (bit_depth_luma_minus8); + COPY_FIELD (bit_depth_chroma_minus8); + COPY_FIELD (log2_max_frame_num_minus4); + COPY_FIELD (pic_order_cnt_type); + COPY_FIELD (log2_max_pic_order_cnt_lsb_minus4); + COPY_FIELD (delta_pic_order_always_zero_flag); + COPY_FIELD (direct_8x8_inference_flag); + +#undef COPY_FIELD +} + +static void +gst_dxva_h264_decoder_picture_params_from_pps (GstDxvaH264Decoder * self, + const GstH264PPS * pps, DXVA_PicParams_H264 * params) +{ +#define COPY_FIELD(f) \ + (params)->f = (pps)->f + + COPY_FIELD (constrained_intra_pred_flag); + COPY_FIELD (weighted_pred_flag); + COPY_FIELD (weighted_bipred_idc); + COPY_FIELD (transform_8x8_mode_flag); + COPY_FIELD (pic_init_qs_minus26); + COPY_FIELD (chroma_qp_index_offset); + COPY_FIELD (second_chroma_qp_index_offset); + COPY_FIELD (pic_init_qp_minus26); + COPY_FIELD (num_ref_idx_l0_active_minus1); + COPY_FIELD (num_ref_idx_l1_active_minus1); + COPY_FIELD (entropy_coding_mode_flag); + COPY_FIELD (pic_order_present_flag); + COPY_FIELD (deblocking_filter_control_present_flag); + COPY_FIELD (redundant_pic_cnt_present_flag); + COPY_FIELD (num_slice_groups_minus1); + COPY_FIELD (slice_group_map_type); + +#undef COPY_FIELD +} + +static void +gst_dxva_h264_decoder_picture_params_from_slice_header (GstDxvaH264Decoder * + self, const GstH264SliceHdr * slice_header, DXVA_PicParams_H264 * params) +{ + params->sp_for_switch_flag = slice_header->sp_for_switch_flag; + params->field_pic_flag = slice_header->field_pic_flag; + params->CurrPic.AssociatedFlag = slice_header->bottom_field_flag; + params->IntraPicFlag = + GST_H264_IS_I_SLICE (slice_header) || GST_H264_IS_SI_SLICE (slice_header); +} + +static gboolean +gst_dxva_h264_decoder_fill_picture_params (GstDxvaH264Decoder * self, + const GstH264SliceHdr * slice_header, DXVA_PicParams_H264 * params) +{ + const GstH264SPS *sps; + const GstH264PPS *pps; + + g_return_val_if_fail (slice_header->pps != nullptr, FALSE); + g_return_val_if_fail (slice_header->pps->sequence != nullptr, FALSE); + + pps = slice_header->pps; + sps = pps->sequence; + + params->MbsConsecutiveFlag = 1; + params->Reserved16Bits = 3; + params->ContinuationFlag = 1; + params->Reserved8BitsA = 0; + params->Reserved8BitsB = 0; + params->StatusReportFeedbackNumber = 1; + + gst_dxva_h264_decoder_picture_params_from_sps (self, + sps, slice_header->field_pic_flag, params); + gst_dxva_h264_decoder_picture_params_from_pps (self, pps, params); + gst_dxva_h264_decoder_picture_params_from_slice_header (self, + slice_header, params); + + return TRUE; +} + +static inline void +init_pic_params (DXVA_PicParams_H264 * params) +{ + memset (params, 0, sizeof (DXVA_PicParams_H264)); + for (guint i = 0; i < G_N_ELEMENTS (params->RefFrameList); i++) + params->RefFrameList[i].bPicEntry = 0xff; +} + +static GstFlowReturn +gst_dxva_h264_decoder_start_picture (GstH264Decoder * decoder, + GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + GstDxvaH264DecoderClass *klass = GST_DXVA_H264_DECODER_GET_CLASS (self); + GstDxvaH264DecoderPrivate *priv = self->priv; + DXVA_PicParams_H264 *pic_params = &priv->pic_params; + DXVA_Qmatrix_H264 *iq_matrix = &priv->iq_matrix; + GstCodecPicture *codec_picture = GST_CODEC_PICTURE (picture); + GArray *dpb_array; + GstH264PPS *pps; + guint i, j; + GstFlowReturn ret; + guint8 picture_id; + + g_assert (klass->start_picture); + g_assert (klass->get_picture_id); + + ret = klass->start_picture (self, codec_picture, &picture_id); + if (ret != GST_FLOW_OK) + return ret; + + pps = slice->header.pps; + + priv->slice_list.resize (0); + priv->bitstream_buffer.resize (0); + g_ptr_array_set_size (priv->ref_pics, 0); + + init_pic_params (pic_params); + gst_dxva_h264_decoder_fill_picture_params (self, &slice->header, pic_params); + + pic_params->CurrPic.Index7Bits = picture_id; + pic_params->RefPicFlag = GST_H264_PICTURE_IS_REF (picture); + pic_params->frame_num = picture->frame_num; + + if (picture->field == GST_H264_PICTURE_FIELD_TOP_FIELD) { + pic_params->CurrFieldOrderCnt[0] = picture->top_field_order_cnt; + pic_params->CurrFieldOrderCnt[1] = 0; + } else if (picture->field == GST_H264_PICTURE_FIELD_BOTTOM_FIELD) { + pic_params->CurrFieldOrderCnt[0] = 0; + pic_params->CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt; + } else { + pic_params->CurrFieldOrderCnt[0] = picture->top_field_order_cnt; + pic_params->CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt; + } + + dpb_array = gst_h264_dpb_get_pictures_all (dpb); + for (i = 0, j = 0; i < dpb_array->len && j < 16; i++) { + GstH264Picture *other = g_array_index (dpb_array, GstH264Picture *, i); + + if (!GST_H264_PICTURE_IS_REF (other)) + continue; + + /* Ignore nonexisting picture */ + if (other->nonexisting) + continue; + + /* The second field picture will be handled differently */ + if (other->second_field) + continue; + + pic_params->RefFrameList[j].Index7Bits = + klass->get_picture_id (self, GST_CODEC_PICTURE (other)); + + if (GST_H264_PICTURE_IS_LONG_TERM_REF (other)) { + pic_params->RefFrameList[j].AssociatedFlag = 1; + pic_params->FrameNumList[j] = other->long_term_frame_idx; + } else { + pic_params->RefFrameList[j].AssociatedFlag = 0; + pic_params->FrameNumList[j] = other->frame_num; + } + + switch (other->field) { + case GST_H264_PICTURE_FIELD_TOP_FIELD: + pic_params->FieldOrderCntList[j][0] = other->top_field_order_cnt; + pic_params->UsedForReferenceFlags |= 0x1 << (2 * j); + break; + case GST_H264_PICTURE_FIELD_BOTTOM_FIELD: + pic_params->FieldOrderCntList[j][1] = other->bottom_field_order_cnt; + pic_params->UsedForReferenceFlags |= 0x1 << (2 * j + 1); + break; + default: + pic_params->FieldOrderCntList[j][0] = other->top_field_order_cnt; + pic_params->FieldOrderCntList[j][1] = other->bottom_field_order_cnt; + pic_params->UsedForReferenceFlags |= 0x3 << (2 * j); + break; + } + + if (other->other_field) { + GstH264Picture *other_field = other->other_field; + + switch (other_field->field) { + case GST_H264_PICTURE_FIELD_TOP_FIELD: + pic_params->FieldOrderCntList[j][0] = + other_field->top_field_order_cnt; + pic_params->UsedForReferenceFlags |= 0x1 << (2 * j); + break; + case GST_H264_PICTURE_FIELD_BOTTOM_FIELD: + pic_params->FieldOrderCntList[j][1] = + other_field->bottom_field_order_cnt; + pic_params->UsedForReferenceFlags |= 0x1 << (2 * j + 1); + break; + default: + break; + } + } + + g_ptr_array_add (priv->ref_pics, other); + j++; + } + g_array_unref (dpb_array); + + G_STATIC_ASSERT (sizeof (iq_matrix->bScalingLists4x4) == + sizeof (pps->scaling_lists_4x4)); + memcpy (iq_matrix->bScalingLists4x4, pps->scaling_lists_4x4, + sizeof (pps->scaling_lists_4x4)); + + G_STATIC_ASSERT (sizeof (iq_matrix->bScalingLists8x8[0]) == + sizeof (pps->scaling_lists_8x8[0])); + memcpy (iq_matrix->bScalingLists8x8[0], pps->scaling_lists_8x8[0], + sizeof (pps->scaling_lists_8x8[0])); + memcpy (iq_matrix->bScalingLists8x8[1], pps->scaling_lists_8x8[1], + sizeof (pps->scaling_lists_8x8[1])); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_h264_decoder_decode_slice (GstH264Decoder * decoder, + GstH264Picture * picture, GstH264Slice * slice, GArray * ref_pic_list0, + GArray * ref_pic_list1) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + GstDxvaH264DecoderPrivate *priv = self->priv; + DXVA_Slice_H264_Short dxva_slice; + static const guint8 start_code[] = { 0, 0, 1 }; + const size_t start_code_size = sizeof (start_code); + + dxva_slice.BSNALunitDataLocation = priv->bitstream_buffer.size (); + /* Includes 3 bytes start code prefix */ + dxva_slice.SliceBytesInBuffer = slice->nalu.size + start_code_size; + dxva_slice.wBadSliceChopping = 0; + + priv->slice_list.push_back (dxva_slice); + + size_t pos = priv->bitstream_buffer.size (); + priv->bitstream_buffer.resize (pos + start_code_size + slice->nalu.size); + + /* Fill start code prefix */ + memcpy (&priv->bitstream_buffer[0] + pos, start_code, start_code_size); + + /* Copy bitstream */ + memcpy (&priv->bitstream_buffer[0] + pos + start_code_size, + slice->nalu.data + slice->nalu.offset, slice->nalu.size); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_h264_decoder_end_picture (GstH264Decoder * decoder, + GstH264Picture * picture) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + GstDxvaH264DecoderPrivate *priv = self->priv; + GstDxvaH264DecoderClass *klass = GST_DXVA_H264_DECODER_GET_CLASS (self); + size_t bitstream_buffer_size; + size_t bitstream_pos; + GstDxvaDecodingArgs args; + + GST_LOG_OBJECT (self, "end picture %p, (poc %d)", + picture, picture->pic_order_cnt); + + if (priv->bitstream_buffer.empty () || priv->slice_list.empty ()) { + GST_ERROR_OBJECT (self, "No bitstream buffer to submit"); + return GST_FLOW_ERROR; + } + + memset (&args, 0, sizeof (GstDxvaDecodingArgs)); + + bitstream_pos = priv->bitstream_buffer.size (); + bitstream_buffer_size = GST_ROUND_UP_128 (bitstream_pos); + + if (bitstream_buffer_size > bitstream_pos) { + size_t padding = bitstream_buffer_size - bitstream_pos; + + /* As per DXVA spec, total amount of bitstream buffer size should be + * 128 bytes aligned. If actual data is not multiple of 128 bytes, + * the last slice data needs to be zero-padded */ + priv->bitstream_buffer.resize (bitstream_buffer_size, 0); + + DXVA_Slice_H264_Short & slice = priv->slice_list.back (); + slice.SliceBytesInBuffer += padding; + } + + args.picture_params = &priv->pic_params; + args.picture_params_size = sizeof (DXVA_PicParams_H264); + args.slice_control = &priv->slice_list[0]; + args.slice_control_size = + sizeof (DXVA_Slice_H264_Short) * priv->slice_list.size (); + args.bitstream = &priv->bitstream_buffer[0]; + args.bitstream_size = priv->bitstream_buffer.size (); + args.inverse_quantization_matrix = &priv->iq_matrix; + args.inverse_quantization_matrix_size = sizeof (DXVA_Qmatrix_H264); + + g_assert (klass->end_picture); + + return klass->end_picture (self, GST_CODEC_PICTURE (picture), + priv->ref_pics, &args); +} + +static GstFlowReturn +gst_dxva_h264_decoder_output_picture (GstH264Decoder * decoder, + GstVideoCodecFrame * frame, GstH264Picture * picture) +{ + GstDxvaH264Decoder *self = GST_DXVA_H264_DECODER (decoder); + GstDxvaH264DecoderClass *klass = GST_DXVA_H264_DECODER_GET_CLASS (self); + GstDxvaH264DecoderPrivate *priv = self->priv; + + g_assert (klass->output_picture); + + GST_LOG_OBJECT (self, + "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt); + + return klass->output_picture (self, frame, GST_CODEC_PICTURE (picture), + picture->buffer_flags, priv->width, priv->height); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah264decoder.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah264decoder.h new file mode 100644 index 0000000000..1f8258cb5a --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah264decoder.h @@ -0,0 +1,94 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DXVA_H264_DECODER (gst_dxva_h264_decoder_get_type()) +#define GST_DXVA_H264_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DXVA_H264_DECODER,GstDxvaH264Decoder)) +#define GST_DXVA_H264_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DXVA_H264_DECODER,GstDxvaH264DecoderClass)) +#define GST_DXVA_H264_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_DXVA_H264_DECODER,GstDxvaH264DecoderClass)) +#define GST_IS_DXVA_H264_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DXVA_H264_DECODER)) +#define GST_IS_DXVA_H264_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DXVA_H264_DECODER)) +#define GST_DXVA_H264_DECODER_CAST(obj) ((GstDxvaH264Decoder*)obj) + +typedef struct _GstDxvaH264Decoder GstDxvaH264Decoder; +typedef struct _GstDxvaH264DecoderClass GstDxvaH264DecoderClass; +typedef struct _GstDxvaH264DecoderPrivate GstDxvaH264DecoderPrivate; + +struct _GstDxvaH264Decoder +{ + GstH264Decoder parent; + + /*< private >*/ + GstDxvaH264DecoderPrivate *priv; +}; + +struct _GstDxvaH264DecoderClass +{ + GstH264DecoderClass parent_class; + + GstFlowReturn (*configure) (GstDxvaH264Decoder * decoder, + GstVideoCodecState * input_state, + const GstVideoInfo * info, + gint crop_x, + gint crop_y, + gint coded_width, + gint coded_height, + gint max_dpb_size); + + GstFlowReturn (*new_picture) (GstDxvaH264Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*duplicate_picture) (GstDxvaH264Decoder * decoder, + GstCodecPicture * src, + GstCodecPicture * dst); + + guint8 (*get_picture_id) (GstDxvaH264Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*start_picture) (GstDxvaH264Decoder * decoder, + GstCodecPicture * picture, + guint8 * picture_id); + + GstFlowReturn (*end_picture) (GstDxvaH264Decoder * decoder, + GstCodecPicture * picture, + GPtrArray * ref_pics, + const GstDxvaDecodingArgs * args); + + GstFlowReturn (*output_picture) (GstDxvaH264Decoder * decoder, + GstVideoCodecFrame * frame, + GstCodecPicture * picture, + GstVideoBufferFlags buffer_flags, + gint display_width, + gint display_height); +}; + +GST_DXVA_API +GType gst_dxva_h264_decoder_get_type (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstDxvaH264Decoder, gst_object_unref) + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah265decoder.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah265decoder.cpp new file mode 100644 index 0000000000..8d1031574e --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah265decoder.cpp @@ -0,0 +1,740 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdxvah265decoder.h" +#include +#include + +/* HACK: to expose dxva data structure on UWP */ +#ifdef WINAPI_PARTITION_DESKTOP +#undef WINAPI_PARTITION_DESKTOP +#endif +#define WINAPI_PARTITION_DESKTOP 1 +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_dxva_h265_decoder_debug); +#define GST_CAT_DEFAULT gst_dxva_h265_decoder_debug + +/* *INDENT-OFF* */ +struct _GstDxvaH265DecoderPrivate +{ + DXVA_PicParams_HEVC pic_params; + DXVA_Qmatrix_HEVC iq_matrix; + + std::vector slice_list; + std::vector bitstream_buffer; + GPtrArray *ref_pics = nullptr; + + gboolean submit_iq_data; + + gint crop_x = 0; + gint crop_y = 0; + gint width = 0; + gint height = 0; + gint coded_width = 0; + gint coded_height = 0; + gint bitdepth = 0; + guint8 chroma_format_idc = 0; + GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN; + GstVideoInterlaceMode interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + gint max_dpb_size = 0; + + gboolean configured; +}; +/* *INDENT-ON* */ + +static void gst_dxva_h265_decoder_finalize (GObject * object); + +static gboolean gst_dxva_h265_decoder_start (GstVideoDecoder * decoder); + +static GstFlowReturn +gst_dxva_h265_decoder_new_sequence (GstH265Decoder * decoder, + const GstH265SPS * sps, gint max_dpb_size); +static GstFlowReturn +gst_dxva_h265_decoder_new_picture (GstH265Decoder * decoder, + GstVideoCodecFrame * frame, GstH265Picture * picture); +static GstFlowReturn +gst_dxva_h265_decoder_start_picture (GstH265Decoder * decoder, + GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb); +static GstFlowReturn +gst_dxva_h265_decoder_decode_slice (GstH265Decoder * decoder, + GstH265Picture * picture, GstH265Slice * slice, + GArray * ref_pic_list0, GArray * ref_pic_list1); +static GstFlowReturn +gst_dxva_h265_decoder_end_picture (GstH265Decoder * decoder, + GstH265Picture * picture); +static GstFlowReturn +gst_dxva_h265_decoder_output_picture (GstH265Decoder * + decoder, GstVideoCodecFrame * frame, GstH265Picture * picture); + +#define gst_dxva_h265_decoder_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstDxvaH265Decoder, + gst_dxva_h265_decoder, GST_TYPE_H265_DECODER, + GST_DEBUG_CATEGORY_INIT (gst_dxva_h265_decoder_debug, "dxvah265decoder", + 0, "dxvah265decoder")); + +static void +gst_dxva_h265_decoder_class_init (GstDxvaH265DecoderClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (klass); + + gobject_class->finalize = gst_dxva_h265_decoder_finalize; + + decoder_class->start = GST_DEBUG_FUNCPTR (gst_dxva_h265_decoder_start); + + h265decoder_class->new_sequence = + GST_DEBUG_FUNCPTR (gst_dxva_h265_decoder_new_sequence); + h265decoder_class->new_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h265_decoder_new_picture); + h265decoder_class->start_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h265_decoder_start_picture); + h265decoder_class->decode_slice = + GST_DEBUG_FUNCPTR (gst_dxva_h265_decoder_decode_slice); + h265decoder_class->end_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h265_decoder_end_picture); + h265decoder_class->output_picture = + GST_DEBUG_FUNCPTR (gst_dxva_h265_decoder_output_picture); +} + +static void +gst_dxva_h265_decoder_init (GstDxvaH265Decoder * self) +{ + self->priv = new GstDxvaH265DecoderPrivate (); + self->priv->ref_pics = g_ptr_array_new (); +} + +static void +gst_dxva_h265_decoder_finalize (GObject * object) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (object); + GstDxvaH265DecoderPrivate *priv = self->priv; + + g_ptr_array_unref (priv->ref_pics); + delete self->priv; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dxva_h265_decoder_reset (GstDxvaH265Decoder * self) +{ + GstDxvaH265DecoderPrivate *priv = self->priv; + + priv->crop_x = 0; + priv->crop_y = 0; + priv->width = 0; + priv->height = 0; + priv->coded_width = 0; + priv->coded_height = 0; + priv->bitdepth = 0; + priv->chroma_format_idc = 0; + priv->out_format = GST_VIDEO_FORMAT_UNKNOWN; + priv->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + priv->max_dpb_size = 0; + priv->configured = FALSE; +} + +static gboolean +gst_dxva_h265_decoder_start (GstVideoDecoder * decoder) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (decoder); + + gst_dxva_h265_decoder_reset (self); + + return GST_VIDEO_DECODER_CLASS (parent_class)->start (decoder); +} + +static GstFlowReturn +gst_dxva_h265_decoder_new_sequence (GstH265Decoder * decoder, + const GstH265SPS * sps, gint max_dpb_size) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (decoder); + GstDxvaH265DecoderPrivate *priv = self->priv; + GstDxvaH265DecoderClass *klass = GST_DXVA_H265_DECODER_GET_CLASS (self); + gint crop_width, crop_height; + gboolean modified = FALSE; + GstVideoInterlaceMode interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + GstVideoInfo info; + GstFlowReturn ret; + + GST_LOG_OBJECT (self, "new sequence"); + + if (sps->conformance_window_flag) { + crop_width = sps->crop_rect_width; + crop_height = sps->crop_rect_height; + } else { + crop_width = sps->width; + crop_height = sps->height; + } + + if (priv->width != crop_width || priv->height != crop_height || + priv->coded_width != sps->width || priv->coded_height != sps->height || + priv->crop_x != sps->crop_rect_x || priv->crop_y != sps->crop_rect_y) { + GST_INFO_OBJECT (self, "resolution changed %dx%d (%dx%d) -> %dx%d (%dx%d)", + priv->width, priv->height, priv->coded_width, priv->coded_height, + crop_width, crop_height, sps->width, sps->height); + priv->crop_x = sps->crop_rect_x; + priv->crop_y = sps->crop_rect_y; + priv->width = crop_width; + priv->height = crop_height; + priv->coded_width = sps->width; + priv->coded_height = sps->height; + modified = TRUE; + } + + if (priv->bitdepth != sps->bit_depth_luma_minus8 + 8) { + gint bitdepth = sps->bit_depth_luma_minus8 + 8; + GST_INFO_OBJECT (self, + "bitdepth change, %d -> %d", priv->bitdepth, bitdepth); + priv->bitdepth = bitdepth; + modified = TRUE; + } + + if (sps->vui_parameters_present_flag && sps->vui_params.field_seq_flag) { + interlace_mode = GST_VIDEO_INTERLACE_MODE_ALTERNATE; + } else { + /* 7.4.4 Profile, tier and level sementics */ + if (sps->profile_tier_level.progressive_source_flag && + !sps->profile_tier_level.interlaced_source_flag) { + interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + } else { + interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED; + } + } + + if (priv->interlace_mode != interlace_mode) { + GST_INFO_OBJECT (self, "Interlace mode change %d -> %d", + priv->interlace_mode, interlace_mode); + priv->interlace_mode = interlace_mode; + modified = TRUE; + } + + if (priv->chroma_format_idc != sps->chroma_format_idc) { + GST_INFO_OBJECT (self, "chroma format changed"); + priv->chroma_format_idc = sps->chroma_format_idc; + modified = TRUE; + } + + if (priv->max_dpb_size < max_dpb_size) { + GST_INFO_OBJECT (self, "Requires larger DPB size (%d -> %d)", + priv->max_dpb_size, max_dpb_size); + modified = TRUE; + } + + if (!modified && priv->configured) + return GST_FLOW_OK; + + priv->out_format = GST_VIDEO_FORMAT_UNKNOWN; + + if (priv->bitdepth == 8) { + if (priv->chroma_format_idc == 1) { + priv->out_format = GST_VIDEO_FORMAT_NV12; + } else { + GST_FIXME_OBJECT (self, "Could not support 8bits non-4:2:0 format"); + } + } else if (priv->bitdepth == 10) { + if (priv->chroma_format_idc == 1) { + priv->out_format = GST_VIDEO_FORMAT_P010_10LE; + } else { + GST_FIXME_OBJECT (self, "Could not support 10bits non-4:2:0 format"); + } + } + + if (priv->out_format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_ERROR_OBJECT (self, "Could not support bitdepth/chroma format"); + priv->configured = FALSE; + return GST_FLOW_NOT_NEGOTIATED; + } + + gst_video_info_set_interlaced_format (&info, priv->out_format, + priv->interlace_mode, priv->width, priv->height); + + priv->max_dpb_size = max_dpb_size; + + g_assert (klass->configure); + ret = klass->configure (self, decoder->input_state, &info, priv->crop_x, + priv->crop_y, priv->coded_width, priv->coded_height, max_dpb_size); + + if (ret == GST_FLOW_OK) { + priv->configured = TRUE; + if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { + GST_WARNING_OBJECT (self, "Couldn't negotiate with new sequence"); + ret = GST_FLOW_NOT_NEGOTIATED; + } + } else { + priv->configured = FALSE; + } + + return ret; +} + +static GstFlowReturn +gst_dxva_h265_decoder_new_picture (GstH265Decoder * decoder, + GstVideoCodecFrame * frame, GstH265Picture * picture) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (decoder); + GstDxvaH265DecoderClass *klass = GST_DXVA_H265_DECODER_GET_CLASS (self); + + g_assert (klass->new_picture); + + return klass->new_picture (self, GST_CODEC_PICTURE (picture)); +} + +static void +gst_dxva_h265_decoder_picture_params_from_sps (GstDxvaH265Decoder * self, + const GstH265SPS * sps, DXVA_PicParams_HEVC * params) +{ +#define COPY_FIELD(f) \ + (params)->f = (sps)->f +#define COPY_FIELD_WITH_PREFIX(f) \ + (params)->G_PASTE(sps_,f) = (sps)->f + + params->PicWidthInMinCbsY = + sps->width >> (sps->log2_min_luma_coding_block_size_minus3 + 3); + params->PicHeightInMinCbsY = + sps->height >> (sps->log2_min_luma_coding_block_size_minus3 + 3); + params->sps_max_dec_pic_buffering_minus1 = + sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1]; + + COPY_FIELD (chroma_format_idc); + COPY_FIELD (separate_colour_plane_flag); + COPY_FIELD (bit_depth_luma_minus8); + COPY_FIELD (bit_depth_chroma_minus8); + COPY_FIELD (log2_max_pic_order_cnt_lsb_minus4); + COPY_FIELD (log2_min_luma_coding_block_size_minus3); + COPY_FIELD (log2_diff_max_min_luma_coding_block_size); + COPY_FIELD (log2_min_transform_block_size_minus2); + COPY_FIELD (log2_diff_max_min_transform_block_size); + COPY_FIELD (max_transform_hierarchy_depth_inter); + COPY_FIELD (max_transform_hierarchy_depth_intra); + COPY_FIELD (num_short_term_ref_pic_sets); + COPY_FIELD (num_long_term_ref_pics_sps); + COPY_FIELD (scaling_list_enabled_flag); + COPY_FIELD (amp_enabled_flag); + COPY_FIELD (sample_adaptive_offset_enabled_flag); + COPY_FIELD (pcm_enabled_flag); + + if (sps->pcm_enabled_flag) { + COPY_FIELD (pcm_sample_bit_depth_luma_minus1); + COPY_FIELD (pcm_sample_bit_depth_chroma_minus1); + COPY_FIELD (log2_min_pcm_luma_coding_block_size_minus3); + COPY_FIELD (log2_diff_max_min_pcm_luma_coding_block_size); + } + + COPY_FIELD (pcm_loop_filter_disabled_flag); + COPY_FIELD (long_term_ref_pics_present_flag); + COPY_FIELD_WITH_PREFIX (temporal_mvp_enabled_flag); + COPY_FIELD (strong_intra_smoothing_enabled_flag); + +#undef COPY_FIELD +#undef COPY_FIELD_WITH_PREFIX +} + +static void +gst_dxva_h265_decoder_picture_params_from_pps (GstDxvaH265Decoder * self, + const GstH265PPS * pps, DXVA_PicParams_HEVC * params) +{ + guint i; + +#define COPY_FIELD(f) \ + (params)->f = (pps)->f +#define COPY_FIELD_WITH_PREFIX(f) \ + (params)->G_PASTE(pps_,f) = (pps)->f + + COPY_FIELD (num_ref_idx_l0_default_active_minus1); + COPY_FIELD (num_ref_idx_l1_default_active_minus1); + COPY_FIELD (init_qp_minus26); + COPY_FIELD (dependent_slice_segments_enabled_flag); + COPY_FIELD (output_flag_present_flag); + COPY_FIELD (num_extra_slice_header_bits); + COPY_FIELD (sign_data_hiding_enabled_flag); + COPY_FIELD (cabac_init_present_flag); + COPY_FIELD (constrained_intra_pred_flag); + COPY_FIELD (transform_skip_enabled_flag); + COPY_FIELD (cu_qp_delta_enabled_flag); + COPY_FIELD_WITH_PREFIX (slice_chroma_qp_offsets_present_flag); + COPY_FIELD (weighted_pred_flag); + COPY_FIELD (weighted_bipred_flag); + COPY_FIELD (transquant_bypass_enabled_flag); + COPY_FIELD (tiles_enabled_flag); + COPY_FIELD (entropy_coding_sync_enabled_flag); + COPY_FIELD (uniform_spacing_flag); + + if (pps->tiles_enabled_flag) + COPY_FIELD (loop_filter_across_tiles_enabled_flag); + + COPY_FIELD_WITH_PREFIX (loop_filter_across_slices_enabled_flag); + COPY_FIELD (deblocking_filter_override_enabled_flag); + COPY_FIELD_WITH_PREFIX (deblocking_filter_disabled_flag); + COPY_FIELD (lists_modification_present_flag); + COPY_FIELD (slice_segment_header_extension_present_flag); + COPY_FIELD_WITH_PREFIX (cb_qp_offset); + COPY_FIELD_WITH_PREFIX (cr_qp_offset); + + if (pps->tiles_enabled_flag) { + COPY_FIELD (num_tile_columns_minus1); + COPY_FIELD (num_tile_rows_minus1); + if (!pps->uniform_spacing_flag) { + for (i = 0; i < pps->num_tile_columns_minus1 && + i < G_N_ELEMENTS (params->column_width_minus1); i++) + COPY_FIELD (column_width_minus1[i]); + + for (i = 0; i < pps->num_tile_rows_minus1 && + i < G_N_ELEMENTS (params->row_height_minus1); i++) + COPY_FIELD (row_height_minus1[i]); + } + } + + COPY_FIELD (diff_cu_qp_delta_depth); + COPY_FIELD_WITH_PREFIX (beta_offset_div2); + COPY_FIELD_WITH_PREFIX (tc_offset_div2); + COPY_FIELD (log2_parallel_merge_level_minus2); + +#undef COPY_FIELD +#undef COPY_FIELD_WITH_PREFIX +} + +static void +gst_dxva_h265_decoder_picture_params_from_slice_header (GstDxvaH265Decoder * + self, const GstH265SliceHdr * slice_header, DXVA_PicParams_HEVC * params) +{ + if (slice_header->short_term_ref_pic_set_sps_flag == 0) { + params->ucNumDeltaPocsOfRefRpsIdx = + slice_header->short_term_ref_pic_sets.NumDeltaPocsOfRefRpsIdx; + params->wNumBitsForShortTermRPSInSlice = + slice_header->short_term_ref_pic_set_size; + } +} + +static gboolean +gst_dxva_h265_decoder_fill_picture_params (GstDxvaH265Decoder * self, + const GstH265SliceHdr * slice_header, DXVA_PicParams_HEVC * params) +{ + const GstH265SPS *sps; + const GstH265PPS *pps; + + pps = slice_header->pps; + sps = pps->sps; + + /* not related to hevc syntax */ + params->NoPicReorderingFlag = 0; + params->NoBiPredFlag = 0; + params->ReservedBits1 = 0; + params->StatusReportFeedbackNumber = 1; + + gst_dxva_h265_decoder_picture_params_from_sps (self, sps, params); + gst_dxva_h265_decoder_picture_params_from_pps (self, pps, params); + gst_dxva_h265_decoder_picture_params_from_slice_header (self, + slice_header, params); + + return TRUE; +} + +static UCHAR +gst_dxva_h265_decoder_get_ref_index (const DXVA_PicParams_HEVC * pic_params, + guint8 picture_id) +{ + if (picture_id == 0xff) + return 0xff; + + for (UCHAR i = 0; i < G_N_ELEMENTS (pic_params->RefPicList); i++) { + if (pic_params->RefPicList[i].Index7Bits == picture_id) + return i; + } + + return 0xff; +} + +static inline void +init_pic_params (DXVA_PicParams_HEVC * params) +{ + memset (params, 0, sizeof (DXVA_PicParams_HEVC)); + for (guint i = 0; i < G_N_ELEMENTS (params->RefPicList); i++) + params->RefPicList[i].bPicEntry = 0xff; + + for (guint i = 0; i < G_N_ELEMENTS (params->RefPicSetStCurrBefore); i++) { + params->RefPicSetStCurrBefore[i] = 0xff; + params->RefPicSetStCurrAfter[i] = 0xff; + params->RefPicSetLtCurr[i] = 0xff; + } +} + +static GstFlowReturn +gst_dxva_h265_decoder_start_picture (GstH265Decoder * decoder, + GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (decoder); + GstDxvaH265DecoderPrivate *priv = self->priv; + GstDxvaH265DecoderClass *klass = GST_DXVA_H265_DECODER_GET_CLASS (self); + DXVA_PicParams_HEVC *pic_params = &priv->pic_params; + DXVA_Qmatrix_HEVC *iq_matrix = &priv->iq_matrix; + GstCodecPicture *codec_picture = GST_CODEC_PICTURE (picture); + guint i, j; + GArray *dpb_array; + GstH265SPS *sps; + GstH265PPS *pps; + GstH265ScalingList *scaling_list = nullptr; + GstFlowReturn ret; + guint8 picture_id; + + g_assert (klass->start_picture); + g_assert (klass->get_picture_id); + + ret = klass->start_picture (self, codec_picture, &picture_id); + if (ret != GST_FLOW_OK) + return ret; + + pps = slice->header.pps; + g_assert (pps); + + sps = pps->sps; + g_assert (sps); + + priv->slice_list.resize (0); + priv->bitstream_buffer.resize (0); + g_ptr_array_set_size (priv->ref_pics, 0); + + init_pic_params (pic_params); + gst_dxva_h265_decoder_fill_picture_params (self, &slice->header, pic_params); + + pic_params->CurrPic.Index7Bits = picture_id; + pic_params->IrapPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type); + pic_params->IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type); + pic_params->IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type); + pic_params->CurrPicOrderCntVal = picture->pic_order_cnt; + + dpb_array = gst_h265_dpb_get_pictures_all (dpb); + for (i = 0, j = 0; + i < dpb_array->len && j < G_N_ELEMENTS (pic_params->RefPicList); i++) { + GstH265Picture *other = g_array_index (dpb_array, GstH265Picture *, i); + guint8 id; + + if (!other->ref) + continue; + + id = klass->get_picture_id (self, GST_CODEC_PICTURE (other)); + if (id != 0xff) { + pic_params->RefPicList[j].Index7Bits = id; + pic_params->RefPicList[j].AssociatedFlag = other->long_term; + pic_params->PicOrderCntValList[j] = other->pic_order_cnt; + g_ptr_array_add (priv->ref_pics, other); + } + + j++; + } + g_array_unref (dpb_array); + + for (i = 0, j = 0; i < G_N_ELEMENTS (pic_params->RefPicSetStCurrBefore); i++) { + GstH265Picture *other = nullptr; + guint8 id = 0xff; + + while (!other && j < decoder->NumPocStCurrBefore) + other = decoder->RefPicSetStCurrBefore[j++]; + + if (other) + id = klass->get_picture_id (self, GST_CODEC_PICTURE (other)); + + pic_params->RefPicSetStCurrBefore[i] = + gst_dxva_h265_decoder_get_ref_index (pic_params, id); + } + + for (i = 0, j = 0; i < G_N_ELEMENTS (pic_params->RefPicSetStCurrAfter); i++) { + GstH265Picture *other = nullptr; + guint8 id = 0xff; + + while (!other && j < decoder->NumPocStCurrAfter) + other = decoder->RefPicSetStCurrAfter[j++]; + + if (other) + id = klass->get_picture_id (self, GST_CODEC_PICTURE (other)); + + pic_params->RefPicSetStCurrAfter[i] = + gst_dxva_h265_decoder_get_ref_index (pic_params, id); + } + + for (i = 0, j = 0; i < G_N_ELEMENTS (pic_params->RefPicSetLtCurr); i++) { + GstH265Picture *other = nullptr; + guint8 id = 0xff; + + while (!other && j < decoder->NumPocLtCurr) + other = decoder->RefPicSetLtCurr[j++]; + + if (other) + id = klass->get_picture_id (self, GST_CODEC_PICTURE (other)); + + pic_params->RefPicSetLtCurr[i] = + gst_dxva_h265_decoder_get_ref_index (pic_params, id); + } + + if (pps->scaling_list_data_present_flag || + (sps->scaling_list_enabled_flag + && !sps->scaling_list_data_present_flag)) { + scaling_list = &pps->scaling_list; + } else if (sps->scaling_list_enabled_flag && + sps->scaling_list_data_present_flag) { + scaling_list = &sps->scaling_list; + } + + if (scaling_list) { + G_STATIC_ASSERT (sizeof (iq_matrix->ucScalingLists0) == + sizeof (scaling_list->scaling_lists_4x4)); + G_STATIC_ASSERT (sizeof (iq_matrix->ucScalingLists1) == + sizeof (scaling_list->scaling_lists_8x8)); + G_STATIC_ASSERT (sizeof (iq_matrix->ucScalingLists2) == + sizeof (scaling_list->scaling_lists_16x16)); + G_STATIC_ASSERT (sizeof (iq_matrix->ucScalingLists3) == + sizeof (scaling_list->scaling_lists_32x32)); + + memcpy (iq_matrix->ucScalingLists0, scaling_list->scaling_lists_4x4, + sizeof (iq_matrix->ucScalingLists0)); + memcpy (iq_matrix->ucScalingLists1, scaling_list->scaling_lists_8x8, + sizeof (iq_matrix->ucScalingLists1)); + memcpy (iq_matrix->ucScalingLists2, scaling_list->scaling_lists_16x16, + sizeof (iq_matrix->ucScalingLists2)); + memcpy (iq_matrix->ucScalingLists3, scaling_list->scaling_lists_32x32, + sizeof (iq_matrix->ucScalingLists3)); + + for (i = 0; i < G_N_ELEMENTS (iq_matrix->ucScalingListDCCoefSizeID2); i++) { + iq_matrix->ucScalingListDCCoefSizeID2[i] = + scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8; + } + + for (i = 0; i < G_N_ELEMENTS (iq_matrix->ucScalingListDCCoefSizeID3); i++) { + iq_matrix->ucScalingListDCCoefSizeID3[i] = + scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8; + } + + priv->submit_iq_data = TRUE; + } else { + priv->submit_iq_data = FALSE; + } + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_h265_decoder_decode_slice (GstH265Decoder * decoder, + GstH265Picture * picture, GstH265Slice * slice, + GArray * ref_pic_list0, GArray * ref_pic_list1) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (decoder); + GstDxvaH265DecoderPrivate *priv = self->priv; + DXVA_Slice_HEVC_Short dxva_slice; + static const guint8 start_code[] = { 0, 0, 1 }; + const size_t start_code_size = sizeof (start_code); + + dxva_slice.BSNALunitDataLocation = priv->bitstream_buffer.size (); + /* Includes 3 bytes start code prefix */ + dxva_slice.SliceBytesInBuffer = slice->nalu.size + start_code_size; + dxva_slice.wBadSliceChopping = 0; + + priv->slice_list.push_back (dxva_slice); + + size_t pos = priv->bitstream_buffer.size (); + priv->bitstream_buffer.resize (pos + start_code_size + slice->nalu.size); + + /* Fill start code prefix */ + memcpy (&priv->bitstream_buffer[0] + pos, start_code, start_code_size); + + /* Copy bitstream */ + memcpy (&priv->bitstream_buffer[0] + pos + start_code_size, + slice->nalu.data + slice->nalu.offset, slice->nalu.size); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_h265_decoder_end_picture (GstH265Decoder * decoder, + GstH265Picture * picture) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (decoder); + GstDxvaH265DecoderPrivate *priv = self->priv; + GstDxvaH265DecoderClass *klass = GST_DXVA_H265_DECODER_GET_CLASS (self); + size_t bitstream_buffer_size; + size_t bitstream_pos; + GstDxvaDecodingArgs args; + + GST_LOG_OBJECT (self, "end picture %p, (poc %d)", + picture, picture->pic_order_cnt); + + if (priv->bitstream_buffer.empty () || priv->slice_list.empty ()) { + GST_ERROR_OBJECT (self, "No bitstream buffer to submit"); + return GST_FLOW_ERROR; + } + + memset (&args, 0, sizeof (GstDxvaDecodingArgs)); + + bitstream_pos = priv->bitstream_buffer.size (); + bitstream_buffer_size = GST_ROUND_UP_128 (bitstream_pos); + + if (bitstream_buffer_size > bitstream_pos) { + size_t padding = bitstream_buffer_size - bitstream_pos; + + /* As per DXVA spec, total amount of bitstream buffer size should be + * 128 bytes aligned. If actual data is not multiple of 128 bytes, + * the last slice data needs to be zero-padded */ + priv->bitstream_buffer.resize (bitstream_buffer_size, 0); + + DXVA_Slice_HEVC_Short & slice = priv->slice_list.back (); + slice.SliceBytesInBuffer += padding; + } + + args.picture_params = &priv->pic_params; + args.picture_params_size = sizeof (DXVA_PicParams_HEVC); + args.slice_control = &priv->slice_list[0]; + args.slice_control_size = + sizeof (DXVA_Slice_HEVC_Short) * priv->slice_list.size (); + args.bitstream = &priv->bitstream_buffer[0]; + args.bitstream_size = priv->bitstream_buffer.size (); + + if (priv->submit_iq_data) { + args.inverse_quantization_matrix = &priv->iq_matrix; + args.inverse_quantization_matrix_size = sizeof (DXVA_Qmatrix_HEVC); + } + + g_assert (klass->end_picture); + + return klass->end_picture (self, GST_CODEC_PICTURE (picture), + priv->ref_pics, &args); +} + +static GstFlowReturn +gst_dxva_h265_decoder_output_picture (GstH265Decoder * decoder, + GstVideoCodecFrame * frame, GstH265Picture * picture) +{ + GstDxvaH265Decoder *self = GST_DXVA_H265_DECODER (decoder); + GstDxvaH265DecoderPrivate *priv = self->priv; + GstDxvaH265DecoderClass *klass = GST_DXVA_H265_DECODER_GET_CLASS (self); + + g_assert (klass->output_picture); + + GST_LOG_OBJECT (self, "Outputting picture %p, poc %d, picture_struct %d, " + "buffer flags 0x%x", picture, picture->pic_order_cnt, picture->pic_struct, + picture->buffer_flags); + + return klass->output_picture (self, frame, GST_CODEC_PICTURE (picture), + picture->buffer_flags, priv->width, priv->height); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah265decoder.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah265decoder.h new file mode 100644 index 0000000000..7184927916 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvah265decoder.h @@ -0,0 +1,90 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DXVA_H265_DECODER (gst_dxva_h265_decoder_get_type()) +#define GST_DXVA_H265_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DXVA_H265_DECODER,GstDxvaH265Decoder)) +#define GST_DXVA_H265_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DXVA_H265_DECODER,GstDxvaH265DecoderClass)) +#define GST_DXVA_H265_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_DXVA_H265_DECODER,GstDxvaH265DecoderClass)) +#define GST_IS_DXVA_H265_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DXVA_H265_DECODER)) +#define GST_IS_DXVA_H265_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DXVA_H265_DECODER)) +#define GST_DXVA_H265_DECODER_CAST(obj) ((GstDxvaH265Decoder*)obj) + +typedef struct _GstDxvaH265Decoder GstDxvaH265Decoder; +typedef struct _GstDxvaH265DecoderClass GstDxvaH265DecoderClass; +typedef struct _GstDxvaH265DecoderPrivate GstDxvaH265DecoderPrivate; + +struct _GstDxvaH265Decoder +{ + GstH265Decoder parent; + + /*< private >*/ + GstDxvaH265DecoderPrivate *priv; +}; + +struct _GstDxvaH265DecoderClass +{ + GstH265DecoderClass parent_class; + + GstFlowReturn (*configure) (GstDxvaH265Decoder * decoder, + GstVideoCodecState * input_state, + const GstVideoInfo * info, + gint crop_x, + gint crop_y, + gint coded_width, + gint coded_height, + gint max_dpb_size); + + GstFlowReturn (*new_picture) (GstDxvaH265Decoder * decoder, + GstCodecPicture * picture); + + guint8 (*get_picture_id) (GstDxvaH265Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*start_picture) (GstDxvaH265Decoder * decoder, + GstCodecPicture * picture, + guint8 * picture_id); + + GstFlowReturn (*end_picture) (GstDxvaH265Decoder * decoder, + GstCodecPicture * picture, + GPtrArray * ref_pics, + const GstDxvaDecodingArgs * args); + + GstFlowReturn (*output_picture) (GstDxvaH265Decoder * decoder, + GstVideoCodecFrame * frame, + GstCodecPicture * picture, + GstVideoBufferFlags buffer_flags, + gint display_width, + gint display_height); +}; + +GST_DXVA_API +GType gst_dxva_h265_decoder_get_type (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstDxvaH265Decoder, gst_object_unref) + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvampeg2decoder.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvampeg2decoder.cpp new file mode 100644 index 0000000000..e177018257 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvampeg2decoder.cpp @@ -0,0 +1,537 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdxvampeg2decoder.h" +#include +#include + +/* HACK: to expose dxva data structure on UWP */ +#ifdef WINAPI_PARTITION_DESKTOP +#undef WINAPI_PARTITION_DESKTOP +#endif +#define WINAPI_PARTITION_DESKTOP 1 +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_dxva_mpeg2_decoder_debug); +#define GST_CAT_DEFAULT gst_dxva_mpeg2_decoder_debug + +/* *INDENT-OFF* */ +struct _GstDxvaMpeg2DecoderPrivate +{ + DXVA_PictureParameters pic_params; + DXVA_QmatrixData iq_matrix; + + std::vector slice_list; + std::vector bitstream_buffer; + GPtrArray *ref_pics = nullptr; + + gboolean submit_iq_data; + + gint width = 0; + gint height = 0; + guint width_in_mb = 0; + guint height_in_mb = 0; + GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN; + GstMpegVideoSequenceHdr seq; + GstMpegVideoProfile profile = GST_MPEG_VIDEO_PROFILE_MAIN; + gboolean interlaced = FALSE; + + gboolean configured = FALSE; +}; +/* *INDENT-ON* */ + +static void gst_dxva_mpeg2_decoder_finalize (GObject * object); + +static gboolean gst_dxva_mpeg2_decoder_start (GstVideoDecoder * decoder); + +static GstFlowReturn gst_dxva_mpeg2_decoder_new_sequence (GstMpeg2Decoder * + decoder, const GstMpegVideoSequenceHdr * seq, + const GstMpegVideoSequenceExt * seq_ext, + const GstMpegVideoSequenceDisplayExt * seq_display_ext, + const GstMpegVideoSequenceScalableExt * seq_scalable_ext, + gint max_dpb_size); +static GstFlowReturn +gst_dxva_mpeg2_decoder_new_picture (GstMpeg2Decoder * decoder, + GstVideoCodecFrame * frame, GstMpeg2Picture * picture); +static GstFlowReturn +gst_dxva_mpeg2_decoder_new_field_picture (GstMpeg2Decoder * decoder, + GstMpeg2Picture * first_field, GstMpeg2Picture * second_field); +static GstFlowReturn +gst_dxva_mpeg2_decoder_start_picture (GstMpeg2Decoder * decoder, + GstMpeg2Picture * picture, GstMpeg2Slice * slice, + GstMpeg2Picture * prev_picture, GstMpeg2Picture * next_picture); +static GstFlowReturn +gst_dxva_mpeg2_decoder_decode_slice (GstMpeg2Decoder * decoder, + GstMpeg2Picture * picture, GstMpeg2Slice * slice); +static GstFlowReturn +gst_dxva_mpeg2_decoder_end_picture (GstMpeg2Decoder * decoder, + GstMpeg2Picture * picture); +static GstFlowReturn +gst_dxva_mpeg2_decoder_output_picture (GstMpeg2Decoder * decoder, + GstVideoCodecFrame * frame, GstMpeg2Picture * picture); + +#define gst_dxva_mpeg2_decoder_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstDxvaMpeg2Decoder, + gst_dxva_mpeg2_decoder, GST_TYPE_MPEG2_DECODER, + GST_DEBUG_CATEGORY_INIT (gst_dxva_mpeg2_decoder_debug, "dxvampeg2decoder", + 0, "dxvampeg2decoder")); + +static void +gst_dxva_mpeg2_decoder_class_init (GstDxvaMpeg2DecoderClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GstMpeg2DecoderClass *mpeg2decoder_class = GST_MPEG2_DECODER_CLASS (klass); + + gobject_class->finalize = gst_dxva_mpeg2_decoder_finalize; + + decoder_class->start = GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_start); + + mpeg2decoder_class->new_sequence = + GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_new_sequence); + mpeg2decoder_class->new_picture = + GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_new_picture); + mpeg2decoder_class->new_field_picture = + GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_new_field_picture); + mpeg2decoder_class->start_picture = + GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_start_picture); + mpeg2decoder_class->decode_slice = + GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_decode_slice); + mpeg2decoder_class->end_picture = + GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_end_picture); + mpeg2decoder_class->output_picture = + GST_DEBUG_FUNCPTR (gst_dxva_mpeg2_decoder_output_picture); +} + +static void +gst_dxva_mpeg2_decoder_init (GstDxvaMpeg2Decoder * self) +{ + self->priv = new GstDxvaMpeg2DecoderPrivate (); + self->priv->ref_pics = g_ptr_array_new (); +} + +static void +gst_dxva_mpeg2_decoder_finalize (GObject * object) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (object); + GstDxvaMpeg2DecoderPrivate *priv = self->priv; + + g_ptr_array_unref (priv->ref_pics); + delete self->priv; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dxva_mpeg2_decoder_reset (GstDxvaMpeg2Decoder * self) +{ + GstDxvaMpeg2DecoderPrivate *priv = self->priv; + + priv->width = 0; + priv->height = 0; + priv->width_in_mb = 0; + priv->height_in_mb = 0; + priv->out_format = GST_VIDEO_FORMAT_UNKNOWN; + priv->profile = GST_MPEG_VIDEO_PROFILE_MAIN; + priv->interlaced = FALSE; + priv->configured = FALSE; +} + +static gboolean +gst_dxva_mpeg2_decoder_start (GstVideoDecoder * decoder) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + + gst_dxva_mpeg2_decoder_reset (self); + + return GST_VIDEO_DECODER_CLASS (parent_class)->start (decoder); +} + +static GstFlowReturn +gst_dxva_mpeg2_decoder_new_sequence (GstMpeg2Decoder * decoder, + const GstMpegVideoSequenceHdr * seq, + const GstMpegVideoSequenceExt * seq_ext, + const GstMpegVideoSequenceDisplayExt * seq_display_ext, + const GstMpegVideoSequenceScalableExt * seq_scalable_ext, gint max_dpb_size) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + GstDxvaMpeg2DecoderPrivate *priv = self->priv; + GstDxvaMpeg2DecoderClass *klass = GST_DXVA_MPEG2_DECODER_GET_CLASS (self); + gboolean interlaced; + gboolean modified = FALSE; + gint width, height; + GstMpegVideoProfile mpeg_profile; + GstVideoInfo info; + GstFlowReturn ret; + + GST_LOG_OBJECT (self, "new sequence"); + + interlaced = seq_ext ? !seq_ext->progressive : FALSE; + if (priv->interlaced != interlaced) { + GST_INFO_OBJECT (self, "interlaced sequence change, %d -> %d", + priv->interlaced, interlaced); + priv->interlaced = interlaced; + modified = TRUE; + } + + width = seq->width; + height = seq->height; + if (seq_ext) { + width = (width & 0x0fff) | ((guint32) seq_ext->horiz_size_ext << 12); + height = (height & 0x0fff) | ((guint32) seq_ext->vert_size_ext << 12); + } + + if (priv->width != width || priv->height != height) { + GST_INFO_OBJECT (self, "resolution change %dx%d -> %dx%d", + priv->width, priv->height, width, height); + priv->width = width; + priv->height = height; + priv->width_in_mb = GST_ROUND_UP_16 (width) >> 4; + priv->height_in_mb = GST_ROUND_UP_16 (height) >> 4; + modified = TRUE; + } + + mpeg_profile = GST_MPEG_VIDEO_PROFILE_MAIN; + if (seq_ext) + mpeg_profile = (GstMpegVideoProfile) seq_ext->profile; + + if (mpeg_profile != GST_MPEG_VIDEO_PROFILE_MAIN && + mpeg_profile != GST_MPEG_VIDEO_PROFILE_SIMPLE) { + GST_ERROR_OBJECT (self, "Cannot support profile %d", mpeg_profile); + return GST_FLOW_NOT_NEGOTIATED; + } + + if (priv->profile != mpeg_profile) { + GST_INFO_OBJECT (self, "Profile change %d -> %d", + priv->profile, mpeg_profile); + priv->profile = mpeg_profile; + modified = TRUE; + } + + if (!modified && priv->configured) + return GST_FLOW_OK; + + priv->out_format = GST_VIDEO_FORMAT_NV12; + + gst_video_info_set_interlaced_format (&info, + priv->out_format, priv->interlaced ? GST_VIDEO_INTERLACE_MODE_MIXED : + GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, priv->width, priv->height); + + g_assert (klass->configure); + ret = klass->configure (self, decoder->input_state, &info, 0, 0, priv->width, + priv->height, max_dpb_size); + + if (ret == GST_FLOW_OK) { + priv->configured = TRUE; + if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { + GST_WARNING_OBJECT (self, "Couldn't negotiate with new sequence"); + ret = GST_FLOW_NOT_NEGOTIATED; + } + } else { + priv->configured = FALSE; + } + + return ret; +} + +static GstFlowReturn +gst_dxva_mpeg2_decoder_new_picture (GstMpeg2Decoder * decoder, + GstVideoCodecFrame * frame, GstMpeg2Picture * picture) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + GstDxvaMpeg2DecoderClass *klass = GST_DXVA_MPEG2_DECODER_GET_CLASS (self); + + g_assert (klass->new_picture); + + return klass->new_picture (self, GST_CODEC_PICTURE (picture)); +} + +static GstFlowReturn +gst_dxva_mpeg2_decoder_new_field_picture (GstMpeg2Decoder * decoder, + GstMpeg2Picture * first_field, GstMpeg2Picture * second_field) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + GstDxvaMpeg2DecoderClass *klass = GST_DXVA_MPEG2_DECODER_GET_CLASS (self); + + g_assert (klass->duplicate_picture); + + return klass->duplicate_picture (self, GST_CODEC_PICTURE (first_field), + GST_CODEC_PICTURE (second_field)); +} + +static inline WORD +_pack_f_codes (guint8 f_code[2][2]) +{ + return (((WORD) f_code[0][0] << 12) + | ((WORD) f_code[0][1] << 8) + | ((WORD) f_code[1][0] << 4) + | (f_code[1][1])); +} + +static inline WORD +_pack_pce_elements (GstMpeg2Slice * slice) +{ + return (((WORD) slice->pic_ext->intra_dc_precision << 14) + | ((WORD) slice->pic_ext->picture_structure << 12) + | ((WORD) slice->pic_ext->top_field_first << 11) + | ((WORD) slice->pic_ext->frame_pred_frame_dct << 10) + | ((WORD) slice->pic_ext->concealment_motion_vectors << 9) + | ((WORD) slice->pic_ext->q_scale_type << 8) + | ((WORD) slice->pic_ext->intra_vlc_format << 7) + | ((WORD) slice->pic_ext->alternate_scan << 6) + | ((WORD) slice->pic_ext->repeat_first_field << 5) + | ((WORD) slice->pic_ext->chroma_420_type << 4) + | ((WORD) slice->pic_ext->progressive_frame << 3)); +} + +static GstFlowReturn +gst_dxva_mpeg2_decoder_start_picture (GstMpeg2Decoder * decoder, + GstMpeg2Picture * picture, GstMpeg2Slice * slice, + GstMpeg2Picture * prev_picture, GstMpeg2Picture * next_picture) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + GstDxvaMpeg2DecoderPrivate *priv = self->priv; + GstDxvaMpeg2DecoderClass *klass = GST_DXVA_MPEG2_DECODER_GET_CLASS (self); + DXVA_PictureParameters *pic_params = &priv->pic_params; + DXVA_QmatrixData *iq_matrix = &priv->iq_matrix; + GstCodecPicture *codec_picture = GST_CODEC_PICTURE (picture); + gboolean is_field = + picture->structure != GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME; + GstFlowReturn ret; + guint8 picture_id; + + g_assert (klass->start_picture); + g_assert (klass->get_picture_id); + + ret = klass->start_picture (self, codec_picture, &picture_id); + if (ret != GST_FLOW_OK) + return ret; + + priv->slice_list.resize (0); + priv->bitstream_buffer.resize (0); + g_ptr_array_set_size (priv->ref_pics, 0); + + memset (pic_params, 0, sizeof (DXVA_PictureParameters)); + memset (iq_matrix, 0, sizeof (DXVA_QmatrixData)); + + /* Fill DXVA_PictureParameters */ + pic_params->wDecodedPictureIndex = picture_id; + pic_params->wForwardRefPictureIndex = 0xffff; + pic_params->wBackwardRefPictureIndex = 0xffff; + + switch (picture->type) { + case GST_MPEG_VIDEO_PICTURE_TYPE_B: + { + if (next_picture) { + picture_id = klass->get_picture_id (self, + GST_CODEC_PICTURE (next_picture)); + if (picture_id != 0xff) { + pic_params->wBackwardRefPictureIndex = picture_id; + g_ptr_array_add (priv->ref_pics, next_picture); + } + } + } + /* fall-through */ + case GST_MPEG_VIDEO_PICTURE_TYPE_P: + { + if (prev_picture) { + picture_id = klass->get_picture_id (self, + GST_CODEC_PICTURE (prev_picture)); + if (picture_id != 0xff) { + pic_params->wForwardRefPictureIndex = picture_id; + g_ptr_array_add (priv->ref_pics, prev_picture); + } + } + } + default: + break; + } + + pic_params->wPicWidthInMBminus1 = priv->width_in_mb - 1; + pic_params->wPicHeightInMBminus1 = (priv->height_in_mb >> is_field) - 1; + pic_params->bMacroblockWidthMinus1 = 15; + pic_params->bMacroblockHeightMinus1 = 15; + pic_params->bBlockWidthMinus1 = 7; + pic_params->bBlockHeightMinus1 = 7; + pic_params->bBPPminus1 = 7; + pic_params->bPicStructure = (BYTE) picture->structure; + if (picture->first_field && is_field) { + pic_params->bSecondField = TRUE; + } + pic_params->bPicIntra = picture->type == GST_MPEG_VIDEO_PICTURE_TYPE_I; + pic_params->bPicBackwardPrediction = + picture->type == GST_MPEG_VIDEO_PICTURE_TYPE_B; + /* FIXME: 1 -> 4:2:0, 2 -> 4:2:2, 3 -> 4:4:4 */ + pic_params->bChromaFormat = 1; + pic_params->bPicScanFixed = 1; + pic_params->bPicScanMethod = slice->pic_ext->alternate_scan; + pic_params->wBitstreamFcodes = _pack_f_codes (slice->pic_ext->f_code); + pic_params->wBitstreamPCEelements = _pack_pce_elements (slice); + + /* Fill DXVA_QmatrixData */ + if (slice->quant_matrix && + /* The value in bNewQmatrix[0] and bNewQmatrix[1] must not both be zero. + * https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/dxva/ns-dxva-_dxva_qmatrixdata + */ + (slice->quant_matrix->load_intra_quantiser_matrix || + slice->quant_matrix->load_non_intra_quantiser_matrix)) { + GstMpegVideoQuantMatrixExt *quant_matrix = slice->quant_matrix; + + if (quant_matrix->load_intra_quantiser_matrix) { + iq_matrix->bNewQmatrix[0] = 1; + for (guint i = 0; i < 64; i++) { + iq_matrix->Qmatrix[0][i] = quant_matrix->intra_quantiser_matrix[i]; + } + } + + if (quant_matrix->load_non_intra_quantiser_matrix) { + iq_matrix->bNewQmatrix[1] = 1; + for (guint i = 0; i < 64; i++) { + iq_matrix->Qmatrix[1][i] = quant_matrix->non_intra_quantiser_matrix[i]; + } + } + + if (quant_matrix->load_chroma_intra_quantiser_matrix) { + iq_matrix->bNewQmatrix[2] = 1; + for (guint i = 0; i < 64; i++) { + iq_matrix->Qmatrix[2][i] = + quant_matrix->chroma_intra_quantiser_matrix[i]; + } + } + + if (quant_matrix->load_chroma_non_intra_quantiser_matrix) { + iq_matrix->bNewQmatrix[3] = 1; + for (guint i = 0; i < 64; i++) { + iq_matrix->Qmatrix[3][i] = + quant_matrix->chroma_non_intra_quantiser_matrix[i]; + } + } + + priv->submit_iq_data = TRUE; + } else { + priv->submit_iq_data = FALSE; + } + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_mpeg2_decoder_decode_slice (GstMpeg2Decoder * decoder, + GstMpeg2Picture * picture, GstMpeg2Slice * slice) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + GstDxvaMpeg2DecoderPrivate *priv = self->priv; + GstMpegVideoSliceHdr *header = &slice->header; + GstMpegVideoPacket *packet = &slice->packet; + DXVA_SliceInfo slice_info = { 0, }; + + g_assert (packet->offset >= 4); + + slice_info.wHorizontalPosition = header->mb_column; + slice_info.wVerticalPosition = header->mb_row; + /* including start code 4 bytes */ + slice_info.dwSliceBitsInBuffer = 8 * (packet->size + 4); + slice_info.dwSliceDataLocation = priv->bitstream_buffer.size (); + /* XXX: We don't have information about the number of MBs in this slice. + * Just store offset here, and actual number will be calculated later */ + slice_info.wNumberMBsInSlice = + (header->mb_row * priv->width_in_mb) + header->mb_column; + slice_info.wQuantizerScaleCode = header->quantiser_scale_code; + slice_info.wMBbitOffset = header->header_size + 32; + + priv->slice_list.push_back (slice_info); + + size_t pos = priv->bitstream_buffer.size (); + priv->bitstream_buffer.resize (pos + packet->size + 4); + memcpy (&priv->bitstream_buffer[0] + pos, packet->data + packet->offset - 4, + packet->size + 4); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_mpeg2_decoder_end_picture (GstMpeg2Decoder * decoder, + GstMpeg2Picture * picture) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + GstDxvaMpeg2DecoderPrivate *priv = self->priv; + GstDxvaMpeg2DecoderClass *klass = GST_DXVA_MPEG2_DECODER_GET_CLASS (self); + GstDxvaDecodingArgs args; + gboolean is_field = + picture->structure != GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME; + guint mb_count = priv->width_in_mb * (priv->height_in_mb >> is_field); + + if (priv->bitstream_buffer.empty ()) { + GST_ERROR_OBJECT (self, "No bitstream buffer to submit"); + return GST_FLOW_ERROR; + } + + memset (&args, 0, sizeof (GstDxvaDecodingArgs)); + + DXVA_SliceInfo *first = &priv->slice_list[0]; + for (size_t i = 0; i < priv->slice_list.size (); i++) { + DXVA_SliceInfo *slice = first + i; + + /* Update the number of MBs per slice */ + if (i == priv->slice_list.size () - 1) { + slice->wNumberMBsInSlice = mb_count - slice->wNumberMBsInSlice; + } else { + DXVA_SliceInfo *next = first + i + 1; + slice->wNumberMBsInSlice = + next->wNumberMBsInSlice - slice->wNumberMBsInSlice; + } + } + + args.picture_params = &priv->pic_params; + args.picture_params_size = sizeof (DXVA_PictureParameters); + args.slice_control = &priv->slice_list[0]; + args.slice_control_size = sizeof (DXVA_SliceInfo) * priv->slice_list.size (); + args.bitstream = &priv->bitstream_buffer[0]; + args.bitstream_size = priv->bitstream_buffer.size (); + if (priv->submit_iq_data) { + args.inverse_quantization_matrix = &priv->iq_matrix; + args.inverse_quantization_matrix_size = sizeof (DXVA_QmatrixData); + } + + g_assert (klass->end_picture); + + return klass->end_picture (self, GST_CODEC_PICTURE (picture), + priv->ref_pics, &args); +} + +static GstFlowReturn +gst_dxva_mpeg2_decoder_output_picture (GstMpeg2Decoder * decoder, + GstVideoCodecFrame * frame, GstMpeg2Picture * picture) +{ + GstDxvaMpeg2Decoder *self = GST_DXVA_MPEG2_DECODER (decoder); + GstDxvaMpeg2DecoderPrivate *priv = self->priv; + GstDxvaMpeg2DecoderClass *klass = GST_DXVA_MPEG2_DECODER_GET_CLASS (self); + + g_assert (klass->output_picture); + + GST_LOG_OBJECT (self, "Outputting picture %p", picture); + + return klass->output_picture (self, frame, GST_CODEC_PICTURE (picture), + picture->buffer_flags, priv->width, priv->height); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvampeg2decoder.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvampeg2decoder.h new file mode 100644 index 0000000000..914c97947e --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvampeg2decoder.h @@ -0,0 +1,94 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DXVA_MPEG2_DECODER (gst_dxva_mpeg2_decoder_get_type()) +#define GST_DXVA_MPEG2_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DXVA_MPEG2_DECODER,GstDxvaMpeg2Decoder)) +#define GST_DXVA_MPEG2_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DXVA_MPEG2_DECODER,GstDxvaMpeg2DecoderClass)) +#define GST_DXVA_MPEG2_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_DXVA_MPEG2_DECODER,GstDxvaMpeg2DecoderClass)) +#define GST_IS_DXVA_MPEG2_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DXVA_MPEG2_DECODER)) +#define GST_IS_DXVA_MPEG2_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DXVA_MPEG2_DECODER)) +#define GST_DXVA_MPEG2_DECODER_CAST(obj) ((GstDxvaMpeg2Decoder*)obj) + +typedef struct _GstDxvaMpeg2Decoder GstDxvaMpeg2Decoder; +typedef struct _GstDxvaMpeg2DecoderClass GstDxvaMpeg2DecoderClass; +typedef struct _GstDxvaMpeg2DecoderPrivate GstDxvaMpeg2DecoderPrivate; + +struct _GstDxvaMpeg2Decoder +{ + GstMpeg2Decoder parent; + + /*< private >*/ + GstDxvaMpeg2DecoderPrivate *priv; +}; + +struct _GstDxvaMpeg2DecoderClass +{ + GstMpeg2DecoderClass parent_class; + + GstFlowReturn (*configure) (GstDxvaMpeg2Decoder * decoder, + GstVideoCodecState * input_state, + const GstVideoInfo * info, + gint crop_x, + gint crop_y, + gint coded_width, + gint coded_height, + gint max_dpb_size); + + GstFlowReturn (*new_picture) (GstDxvaMpeg2Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*duplicate_picture) (GstDxvaMpeg2Decoder * decoder, + GstCodecPicture * src, + GstCodecPicture * dst); + + guint8 (*get_picture_id) (GstDxvaMpeg2Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*start_picture) (GstDxvaMpeg2Decoder * decoder, + GstCodecPicture * picture, + guint8 * picture_id); + + GstFlowReturn (*end_picture) (GstDxvaMpeg2Decoder * decoder, + GstCodecPicture * picture, + GPtrArray * ref_pics, + const GstDxvaDecodingArgs * args); + + GstFlowReturn (*output_picture) (GstDxvaMpeg2Decoder * decoder, + GstVideoCodecFrame * frame, + GstCodecPicture * picture, + GstVideoBufferFlags buffer_flags, + gint display_width, + gint display_height); +}; + +GST_DXVA_API +GType gst_dxva_mpeg2_decoder_get_type (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstDxvaMpeg2Decoder, gst_object_unref) + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvatypes.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvatypes.h new file mode 100644 index 0000000000..97aade47a5 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvatypes.h @@ -0,0 +1,86 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstDxvaDecodingArgs GstDxvaDecodingArgs; +typedef struct _GstDxvaResolution GstDxvaResolution; + +/** + * GstDxvaDecodingArgs: + * + * Since: 1.24 + */ +struct _GstDxvaDecodingArgs +{ + gpointer picture_params; + gsize picture_params_size; + + gpointer slice_control; + gsize slice_control_size; + + gpointer bitstream; + gsize bitstream_size; + + gpointer inverse_quantization_matrix; + gsize inverse_quantization_matrix_size; +}; + +/** + * GstDxvaCodec: + * + * Since: 1.24 + */ +typedef enum +{ + GST_DXVA_CODEC_NONE, + GST_DXVA_CODEC_MPEG2, + GST_DXVA_CODEC_H264, + GST_DXVA_CODEC_H265, + GST_DXVA_CODEC_VP8, + GST_DXVA_CODEC_VP9, + GST_DXVA_CODEC_AV1, + + /* the last of supported codec */ + GST_DXVA_CODEC_LAST +} GstDxvaCodec; + +/** + * GstDxvaResolution: + * + * Since: 1.24 + */ +struct _GstDxvaResolution +{ + guint width; + guint height; +}; + +static const GstDxvaResolution gst_dxva_resolutions[] = { + {1920, 1088}, {2560, 1440}, {3840, 2160}, {4096, 2160}, + {7680, 4320}, {8192, 4320}, {15360, 8640}, {16384, 8640} +}; + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvautils.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvautils.cpp new file mode 100644 index 0000000000..8aeabe8553 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvautils.cpp @@ -0,0 +1,58 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdxvautils.h" + +/** + * gst_dxva_codec_to_string: + * @codec: a #GstDxvaCodec + * + * Returns: the string representation of @codec + * + * Since: 1.24 + */ +const gchar * +gst_dxva_codec_to_string (GstDxvaCodec codec) +{ + switch (codec) { + case GST_DXVA_CODEC_NONE: + return "none"; + case GST_DXVA_CODEC_H264: + return "H.264"; + case GST_DXVA_CODEC_VP9: + return "VP9"; + case GST_DXVA_CODEC_H265: + return "H.265"; + case GST_DXVA_CODEC_VP8: + return "VP8"; + case GST_DXVA_CODEC_MPEG2: + return "MPEG2"; + case GST_DXVA_CODEC_AV1: + return "AV1"; + default: + g_assert_not_reached (); + break; + } + + return "Unknown"; +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvautils.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvautils.h new file mode 100644 index 0000000000..d7501de7c9 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvautils.h @@ -0,0 +1,31 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +GST_DXVA_API +const gchar * gst_dxva_codec_to_string (GstDxvaCodec codec); + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp8decoder.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp8decoder.cpp new file mode 100644 index 0000000000..36699de0bb --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp8decoder.cpp @@ -0,0 +1,413 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdxvavp8decoder.h" +#include +#include + +/* HACK: to expose dxva data structure on UWP */ +#ifdef WINAPI_PARTITION_DESKTOP +#undef WINAPI_PARTITION_DESKTOP +#endif +#define WINAPI_PARTITION_DESKTOP 1 +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_dxva_vp8_decoder_debug); +#define GST_CAT_DEFAULT gst_dxva_vp8_decoder_debug + +/* *INDENT-OFF* */ +struct _GstDxvaVp8DecoderPrivate +{ + DXVA_PicParams_VP8 pic_params; + DXVA_Slice_VPx_Short slice; + + std::vector bitstream_buffer; + GPtrArray *ref_pics = nullptr; + + gint width = 0; + gint height = 0; +}; +/* *INDENT-ON* */ + +static void gst_dxva_vp8_decoder_finalize (GObject * object); + +static gboolean gst_dxva_vp8_decoder_start (GstVideoDecoder * decoder); + +static GstFlowReturn gst_dxva_vp8_decoder_new_sequence (GstVp8Decoder * decoder, + const GstVp8FrameHdr * frame_hdr, gint max_dpb_size); +static GstFlowReturn gst_dxva_vp8_decoder_new_picture (GstVp8Decoder * decoder, + GstVideoCodecFrame * frame, GstVp8Picture * picture); +static GstFlowReturn +gst_dxva_vp8_decoder_decode_picture (GstVp8Decoder * decoder, + GstVp8Picture * picture, GstVp8Parser * parser); +static GstFlowReturn gst_dxva_vp8_decoder_end_picture (GstVp8Decoder * decoder, + GstVp8Picture * picture); +static GstFlowReturn gst_dxva_vp8_decoder_output_picture (GstVp8Decoder * + decoder, GstVideoCodecFrame * frame, GstVp8Picture * picture); + +#define gst_dxva_vp8_decoder_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstDxvaVp8Decoder, + gst_dxva_vp8_decoder, GST_TYPE_VP8_DECODER, + GST_DEBUG_CATEGORY_INIT (gst_dxva_vp8_decoder_debug, "dxvavp8decoder", + 0, "dxvavp8decoder")); + +static void +gst_dxva_vp8_decoder_class_init (GstDxvaVp8DecoderClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GstVp8DecoderClass *vp8decoder_class = GST_VP8_DECODER_CLASS (klass); + + object_class->finalize = gst_dxva_vp8_decoder_finalize; + + decoder_class->start = GST_DEBUG_FUNCPTR (gst_dxva_vp8_decoder_start); + + vp8decoder_class->new_sequence = + GST_DEBUG_FUNCPTR (gst_dxva_vp8_decoder_new_sequence); + vp8decoder_class->new_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp8_decoder_new_picture); + vp8decoder_class->decode_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp8_decoder_decode_picture); + vp8decoder_class->end_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp8_decoder_end_picture); + vp8decoder_class->output_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp8_decoder_output_picture); +} + +static void +gst_dxva_vp8_decoder_init (GstDxvaVp8Decoder * self) +{ + self->priv = new GstDxvaVp8DecoderPrivate (); + self->priv->ref_pics = g_ptr_array_new (); +} + +static void +gst_dxva_vp8_decoder_finalize (GObject * object) +{ + GstDxvaVp8Decoder *self = GST_DXVA_VP8_DECODER (object); + GstDxvaVp8DecoderPrivate *priv = self->priv; + + g_ptr_array_unref (priv->ref_pics); + delete self->priv; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dxva_vp8_decoder_reset (GstDxvaVp8Decoder * self) +{ + GstDxvaVp8DecoderPrivate *priv = self->priv; + + priv->width = 0; + priv->height = 0; +} + +static gboolean +gst_dxva_vp8_decoder_start (GstVideoDecoder * decoder) +{ + GstDxvaVp8Decoder *self = GST_DXVA_VP8_DECODER (decoder); + + gst_dxva_vp8_decoder_reset (self); + + return GST_VIDEO_DECODER_CLASS (parent_class)->start (decoder); +} + +static GstFlowReturn +gst_dxva_vp8_decoder_new_sequence (GstVp8Decoder * decoder, + const GstVp8FrameHdr * frame_hdr, gint max_dpb_size) +{ + GstDxvaVp8Decoder *self = GST_DXVA_VP8_DECODER (decoder); + GstDxvaVp8DecoderPrivate *priv = self->priv; + GstDxvaVp8DecoderClass *klass = GST_DXVA_VP8_DECODER_GET_CLASS (self); + GstVideoInfo info; + GstFlowReturn ret; + + GST_LOG_OBJECT (self, "new sequence"); + + priv->width = frame_hdr->width; + priv->height = frame_hdr->height; + + gst_video_info_set_format (&info, + GST_VIDEO_FORMAT_NV12, frame_hdr->width, frame_hdr->height); + + g_assert (klass->configure); + + ret = klass->configure (self, decoder->input_state, &info, 0, 0, + frame_hdr->width, frame_hdr->height, max_dpb_size); + + if (ret == GST_FLOW_OK && + !gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { + GST_WARNING_OBJECT (self, "Couldn't negotiate with new sequence"); + ret = GST_FLOW_NOT_NEGOTIATED; + } + + return ret; +} + +static GstFlowReturn +gst_dxva_vp8_decoder_new_picture (GstVp8Decoder * decoder, + GstVideoCodecFrame * frame, GstVp8Picture * picture) +{ + GstDxvaVp8Decoder *self = GST_DXVA_VP8_DECODER (decoder); + GstDxvaVp8DecoderClass *klass = GST_DXVA_VP8_DECODER_GET_CLASS (self); + + g_assert (klass->new_picture); + + return klass->new_picture (self, GST_CODEC_PICTURE (picture)); +} + +static void +gst_dxva_vp8_decoder_copy_frame_params (GstDxvaVp8Decoder * self, + GstVp8Picture * picture, GstVp8Parser * parser, DXVA_PicParams_VP8 * params) +{ + const GstVp8FrameHdr *frame_hdr = &picture->frame_hdr; + gint i; + + /* 0: keyframe, 1: inter */ + params->frame_type = !frame_hdr->key_frame; + params->version = frame_hdr->version; + params->show_frame = frame_hdr->show_frame; + params->clamp_type = frame_hdr->clamping_type; + + params->filter_type = frame_hdr->filter_type; + params->filter_level = frame_hdr->loop_filter_level; + params->sharpness_level = frame_hdr->sharpness_level; + params->mode_ref_lf_delta_enabled = + parser->mb_lf_adjust.loop_filter_adj_enable; + params->mode_ref_lf_delta_update = + parser->mb_lf_adjust.mode_ref_lf_delta_update; + for (i = 0; i < 4; i++) { + params->ref_lf_deltas[i] = parser->mb_lf_adjust.ref_frame_delta[i]; + params->mode_lf_deltas[i] = parser->mb_lf_adjust.mb_mode_delta[i]; + } + params->log2_nbr_of_dct_partitions = frame_hdr->log2_nbr_of_dct_partitions; + params->base_qindex = frame_hdr->quant_indices.y_ac_qi; + params->y1dc_delta_q = frame_hdr->quant_indices.y_dc_delta; + params->y2dc_delta_q = frame_hdr->quant_indices.y2_dc_delta; + params->y2ac_delta_q = frame_hdr->quant_indices.y2_ac_delta; + params->uvdc_delta_q = frame_hdr->quant_indices.uv_dc_delta; + params->uvac_delta_q = frame_hdr->quant_indices.uv_ac_delta; + + params->ref_frame_sign_bias_golden = frame_hdr->sign_bias_golden; + params->ref_frame_sign_bias_altref = frame_hdr->sign_bias_alternate; + + params->refresh_entropy_probs = frame_hdr->refresh_entropy_probs; + + memcpy (params->vp8_coef_update_probs, frame_hdr->token_probs.prob, + sizeof (frame_hdr->token_probs.prob)); + + params->mb_no_coeff_skip = frame_hdr->mb_no_skip_coeff; + params->prob_skip_false = frame_hdr->prob_skip_false; + params->prob_intra = frame_hdr->prob_intra; + params->prob_last = frame_hdr->prob_last; + params->prob_golden = frame_hdr->prob_gf; + + memcpy (params->intra_16x16_prob, frame_hdr->mode_probs.y_prob, + sizeof (frame_hdr->mode_probs.y_prob)); + memcpy (params->intra_chroma_prob, frame_hdr->mode_probs.uv_prob, + sizeof (frame_hdr->mode_probs.uv_prob)); + memcpy (params->vp8_mv_update_probs, frame_hdr->mv_probs.prob, + sizeof (frame_hdr->mv_probs.prob)); +} + +static gboolean +gst_dxva_vp8_decoder_copy_reference_frames (GstDxvaVp8Decoder * self, + DXVA_PicParams_VP8 * params) +{ + GstVp8Decoder *decoder = GST_VP8_DECODER (self); + GstDxvaVp8DecoderPrivate *priv = self->priv; + GstDxvaVp8DecoderClass *klass = GST_DXVA_VP8_DECODER_GET_CLASS (self); + guint8 id; + + params->alt_fb_idx.bPicEntry = 0xff; + if (decoder->alt_ref_picture) { + id = klass->get_picture_id (self, + GST_CODEC_PICTURE (decoder->alt_ref_picture)); + if (id != 0xff) { + params->alt_fb_idx.Index7Bits = id; + g_ptr_array_add (priv->ref_pics, decoder->alt_ref_picture); + } + } + + params->gld_fb_idx.bPicEntry = 0xff; + if (decoder->golden_ref_picture) { + id = klass->get_picture_id (self, + GST_CODEC_PICTURE (decoder->golden_ref_picture)); + + if (id != 0xff) { + params->gld_fb_idx.Index7Bits = id; + g_ptr_array_add (priv->ref_pics, decoder->golden_ref_picture); + } + } + + params->lst_fb_idx.bPicEntry = 0xff; + if (decoder->last_picture) { + id = klass->get_picture_id (self, + GST_CODEC_PICTURE (decoder->last_picture)); + + if (id != 0xff) { + params->gld_fb_idx.Index7Bits = id; + g_ptr_array_add (priv->ref_pics, decoder->last_picture); + } + } + + return TRUE; +} + +static void +gst_dxva_vp8_decoder_copy_segmentation_params (GstDxvaVp8Decoder * self, + GstVp8Parser * parser, DXVA_PicParams_VP8 * params) +{ + const GstVp8Segmentation *seg = &parser->segmentation; + gint i; + + params->stVP8Segments.segmentation_enabled = seg->segmentation_enabled; + params->stVP8Segments.update_mb_segmentation_map = + seg->update_mb_segmentation_map; + params->stVP8Segments.update_mb_segmentation_data = + seg->update_segment_feature_data; + params->stVP8Segments.mb_segement_abs_delta = seg->segment_feature_mode; + + for (i = 0; i < 4; i++) { + params->stVP8Segments.segment_feature_data[0][i] = + seg->quantizer_update_value[i]; + } + + for (i = 0; i < 4; i++) { + params->stVP8Segments.segment_feature_data[1][i] = seg->lf_update_value[i]; + } + + for (i = 0; i < 3; i++) { + params->stVP8Segments.mb_segment_tree_probs[i] = seg->segment_prob[i]; + } +} + +static GstFlowReturn +gst_dxva_vp8_decoder_decode_picture (GstVp8Decoder * decoder, + GstVp8Picture * picture, GstVp8Parser * parser) +{ + GstDxvaVp8Decoder *self = GST_DXVA_VP8_DECODER (decoder); + GstDxvaVp8DecoderPrivate *priv = self->priv; + GstDxvaVp8DecoderClass *klass = GST_DXVA_VP8_DECODER_GET_CLASS (self); + DXVA_PicParams_VP8 *pic_params = &priv->pic_params; + DXVA_Slice_VPx_Short *slice = &priv->slice; + const GstVp8FrameHdr *frame_hdr = &picture->frame_hdr; + GstCodecPicture *codec_picture = GST_CODEC_PICTURE (picture); + GstFlowReturn ret; + guint8 picture_id; + + g_assert (klass->start_picture); + g_assert (klass->get_picture_id); + + ret = klass->start_picture (self, codec_picture, &picture_id); + if (ret != GST_FLOW_OK) + return ret; + + priv->bitstream_buffer.resize (0); + g_ptr_array_set_size (priv->ref_pics, 0); + + memset (pic_params, 0, sizeof (DXVA_PicParams_VP8)); + + pic_params->first_part_size = frame_hdr->first_part_size; + pic_params->width = priv->width; + pic_params->height = priv->height; + pic_params->CurrPic.Index7Bits = picture_id; + pic_params->StatusReportFeedbackNumber = 1; + + if (!gst_dxva_vp8_decoder_copy_reference_frames (self, pic_params)) + return GST_FLOW_ERROR; + + gst_dxva_vp8_decoder_copy_frame_params (self, picture, parser, pic_params); + gst_dxva_vp8_decoder_copy_segmentation_params (self, parser, pic_params); + + priv->bitstream_buffer.resize (picture->size); + memcpy (&priv->bitstream_buffer[0], picture->data, picture->size); + + slice->BSNALunitDataLocation = 0; + slice->SliceBytesInBuffer = priv->bitstream_buffer.size (); + slice->wBadSliceChopping = 0; + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_vp8_decoder_end_picture (GstVp8Decoder * decoder, + GstVp8Picture * picture) +{ + GstDxvaVp8Decoder *self = GST_DXVA_VP8_DECODER (decoder); + GstDxvaVp8DecoderPrivate *priv = self->priv; + GstDxvaVp8DecoderClass *klass = GST_DXVA_VP8_DECODER_GET_CLASS (self); + size_t bitstream_buffer_size; + size_t bitstream_pos; + GstDxvaDecodingArgs args; + + if (priv->bitstream_buffer.empty ()) { + GST_ERROR_OBJECT (self, "No bitstream buffer to submit"); + return GST_FLOW_ERROR; + } + + memset (&args, 0, sizeof (GstDxvaDecodingArgs)); + + bitstream_pos = priv->bitstream_buffer.size (); + bitstream_buffer_size = GST_ROUND_UP_128 (bitstream_pos); + + if (bitstream_buffer_size > bitstream_pos) { + size_t padding = bitstream_buffer_size - bitstream_pos; + + /* As per DXVA spec, total amount of bitstream buffer size should be + * 128 bytes aligned. If actual data is not multiple of 128 bytes, + * the last slice data needs to be zero-padded */ + priv->bitstream_buffer.resize (bitstream_buffer_size, 0); + + priv->slice.SliceBytesInBuffer += padding; + } + + args.picture_params = &priv->pic_params; + args.picture_params_size = sizeof (DXVA_PicParams_VP8); + args.slice_control = &priv->slice; + args.slice_control_size = sizeof (DXVA_Slice_VPx_Short); + args.bitstream = &priv->bitstream_buffer[0]; + args.bitstream_size = priv->bitstream_buffer.size (); + + g_assert (klass->end_picture); + + return klass->end_picture (self, GST_CODEC_PICTURE (picture), + priv->ref_pics, &args); +} + +static GstFlowReturn +gst_dxva_vp8_decoder_output_picture (GstVp8Decoder * decoder, + GstVideoCodecFrame * frame, GstVp8Picture * picture) +{ + GstDxvaVp8Decoder *self = GST_DXVA_VP8_DECODER (decoder); + GstDxvaVp8DecoderPrivate *priv = self->priv; + GstDxvaVp8DecoderClass *klass = GST_DXVA_VP8_DECODER_GET_CLASS (self); + + g_assert (klass->output_picture); + + GST_LOG_OBJECT (self, "Outputting picture %p", picture); + + return klass->output_picture (self, frame, GST_CODEC_PICTURE (picture), + (GstVideoBufferFlags) 0, priv->width, priv->height); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp8decoder.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp8decoder.h new file mode 100644 index 0000000000..084a7961db --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp8decoder.h @@ -0,0 +1,90 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DXVA_VP8_DECODER (gst_dxva_vp8_decoder_get_type()) +#define GST_DXVA_VP8_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DXVA_VP8_DECODER,GstDxvaVp8Decoder)) +#define GST_DXVA_VP8_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DXVA_VP8_DECODER,GstDxvaVp8DecoderClass)) +#define GST_DXVA_VP8_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_DXVA_VP8_DECODER,GstDxvaVp8DecoderClass)) +#define GST_IS_DXVA_VP8_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DXVA_VP8_DECODER)) +#define GST_IS_DXVA_VP8_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DXVA_VP8_DECODER)) +#define GST_DXVA_VP8_DECODER_CAST(obj) ((GstDxvaVp8Decoder*)obj) + +typedef struct _GstDxvaVp8Decoder GstDxvaVp8Decoder; +typedef struct _GstDxvaVp8DecoderClass GstDxvaVp8DecoderClass; +typedef struct _GstDxvaVp8DecoderPrivate GstDxvaVp8DecoderPrivate; + +struct _GstDxvaVp8Decoder +{ + GstVp8Decoder parent; + + /*< private >*/ + GstDxvaVp8DecoderPrivate *priv; +}; + +struct _GstDxvaVp8DecoderClass +{ + GstVp8DecoderClass parent_class; + + GstFlowReturn (*configure) (GstDxvaVp8Decoder * decoder, + GstVideoCodecState * input_state, + const GstVideoInfo * info, + gint crop_x, + gint crop_y, + gint coded_width, + gint coded_height, + gint max_dpb_size); + + GstFlowReturn (*new_picture) (GstDxvaVp8Decoder * decoder, + GstCodecPicture * picture); + + guint8 (*get_picture_id) (GstDxvaVp8Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*start_picture) (GstDxvaVp8Decoder * decoder, + GstCodecPicture * picture, + guint8 * picture_id); + + GstFlowReturn (*end_picture) (GstDxvaVp8Decoder * decoder, + GstCodecPicture * picture, + GPtrArray * ref_pics, + const GstDxvaDecodingArgs * args); + + GstFlowReturn (*output_picture) (GstDxvaVp8Decoder * decoder, + GstVideoCodecFrame * frame, + GstCodecPicture * picture, + GstVideoBufferFlags buffer_flags, + gint display_width, + gint display_height); +}; + +GST_DXVA_API +GType gst_dxva_vp8_decoder_get_type (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstDxvaVp8Decoder, gst_object_unref) + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp9decoder.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp9decoder.cpp new file mode 100644 index 0000000000..802e00a67a --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp9decoder.cpp @@ -0,0 +1,503 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdxvavp9decoder.h" +#include +#include + +/* HACK: to expose dxva data structure on UWP */ +#ifdef WINAPI_PARTITION_DESKTOP +#undef WINAPI_PARTITION_DESKTOP +#endif +#define WINAPI_PARTITION_DESKTOP 1 +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_dxva_vp9_decoder_debug); +#define GST_CAT_DEFAULT gst_dxva_vp9_decoder_debug + +/* *INDENT-OFF* */ +struct _GstDxvaVp9DecoderPrivate +{ + DXVA_PicParams_VP9 pic_params; + DXVA_Slice_VPx_Short slice; + + std::vector bitstream_buffer; + GPtrArray *ref_pics = nullptr; + + /* To calculate use_prev_in_find_mv_refs */ + guint last_frame_width = 0; + guint last_frame_height = 0; + gboolean last_show_frame = FALSE; +}; +/* *INDENT-ON* */ + +static void gst_dxva_vp9_decoder_finalize (GObject * object); + +static gboolean gst_dxva_vp9_decoder_start (GstVideoDecoder * decoder); + +static GstFlowReturn gst_dxva_vp9_decoder_new_sequence (GstVp9Decoder * decoder, + const GstVp9FrameHeader * frame_hdr, gint max_dpb_size); +static GstFlowReturn gst_dxva_vp9_decoder_new_picture (GstVp9Decoder * decoder, + GstVideoCodecFrame * frame, GstVp9Picture * picture); +static GstVp9Picture *gst_dxva_vp9_decoder_duplicate_picture (GstVp9Decoder * + decoder, GstVideoCodecFrame * frame, GstVp9Picture * picture); +static GstFlowReturn +gst_dxva_vp9_decoder_decode_picture (GstVp9Decoder * decoder, + GstVp9Picture * picture, GstVp9Dpb * dpb); +static GstFlowReturn gst_dxva_vp9_decoder_end_picture (GstVp9Decoder * decoder, + GstVp9Picture * picture); +static GstFlowReturn gst_dxva_vp9_decoder_output_picture (GstVp9Decoder * + decoder, GstVideoCodecFrame * frame, GstVp9Picture * picture); + +#define gst_dxva_vp9_decoder_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstDxvaVp9Decoder, + gst_dxva_vp9_decoder, GST_TYPE_VP9_DECODER, + GST_DEBUG_CATEGORY_INIT (gst_dxva_vp9_decoder_debug, "dxvavp9decoder", + 0, "dxvavp9decoder")); + +static void +gst_dxva_vp9_decoder_class_init (GstDxvaVp9DecoderClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GstVp9DecoderClass *vp9decoder_class = GST_VP9_DECODER_CLASS (klass); + + object_class->finalize = gst_dxva_vp9_decoder_finalize; + + decoder_class->start = GST_DEBUG_FUNCPTR (gst_dxva_vp9_decoder_start); + + vp9decoder_class->new_sequence = + GST_DEBUG_FUNCPTR (gst_dxva_vp9_decoder_new_sequence); + vp9decoder_class->new_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp9_decoder_new_picture); + vp9decoder_class->duplicate_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp9_decoder_duplicate_picture); + vp9decoder_class->decode_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp9_decoder_decode_picture); + vp9decoder_class->end_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp9_decoder_end_picture); + vp9decoder_class->output_picture = + GST_DEBUG_FUNCPTR (gst_dxva_vp9_decoder_output_picture); +} + +static void +gst_dxva_vp9_decoder_init (GstDxvaVp9Decoder * self) +{ + self->priv = new GstDxvaVp9DecoderPrivate (); + self->priv->ref_pics = g_ptr_array_new (); +} + +static void +gst_dxva_vp9_decoder_finalize (GObject * object) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (object); + GstDxvaVp9DecoderPrivate *priv = self->priv; + + g_ptr_array_unref (priv->ref_pics); + delete self->priv; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dxva_vp9_decoder_reset (GstDxvaVp9Decoder * self) +{ + GstDxvaVp9DecoderPrivate *priv = self->priv; + + priv->last_frame_width = 0; + priv->last_frame_height = 0; + priv->last_show_frame = FALSE; +} + +static gboolean +gst_dxva_vp9_decoder_start (GstVideoDecoder * decoder) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (decoder); + + gst_dxva_vp9_decoder_reset (self); + + return GST_VIDEO_DECODER_CLASS (parent_class)->start (decoder); +} + +static GstFlowReturn +gst_dxva_vp9_decoder_new_sequence (GstVp9Decoder * decoder, + const GstVp9FrameHeader * frame_hdr, gint max_dpb_size) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (decoder); + GstDxvaVp9DecoderPrivate *priv = self->priv; + GstDxvaVp9DecoderClass *klass = GST_DXVA_VP9_DECODER_GET_CLASS (self); + GstVideoInfo info; + GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN; + GstFlowReturn ret; + + GST_LOG_OBJECT (self, "new sequence"); + + if (frame_hdr->profile == GST_VP9_PROFILE_0) + out_format = GST_VIDEO_FORMAT_NV12; + else if (frame_hdr->profile == GST_VP9_PROFILE_2) + out_format = GST_VIDEO_FORMAT_P010_10LE; + + if (out_format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_ERROR_OBJECT (self, "Could not support profile %d", frame_hdr->profile); + return GST_FLOW_NOT_NEGOTIATED; + } + + /* Will be updated per decode_picture */ + priv->last_frame_width = priv->last_frame_height = 0; + priv->last_show_frame = FALSE; + + gst_video_info_set_format (&info, + out_format, frame_hdr->width, frame_hdr->height); + + g_assert (klass->configure); + + ret = klass->configure (self, decoder->input_state, &info, 0, 0, + frame_hdr->width, frame_hdr->height, max_dpb_size); + + if (ret == GST_FLOW_OK && + !gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { + GST_WARNING_OBJECT (self, "Couldn't negotiate with new sequence"); + ret = GST_FLOW_NOT_NEGOTIATED; + } + + return ret; +} + +static GstFlowReturn +gst_dxva_vp9_decoder_new_picture (GstVp9Decoder * decoder, + GstVideoCodecFrame * frame, GstVp9Picture * picture) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (decoder); + GstDxvaVp9DecoderClass *klass = GST_DXVA_VP9_DECODER_GET_CLASS (self); + + g_assert (klass->new_picture); + + return klass->new_picture (self, GST_CODEC_PICTURE (picture)); +} + +static GstVp9Picture * +gst_dxva_vp9_decoder_duplicate_picture (GstVp9Decoder * decoder, + GstVideoCodecFrame * frame, GstVp9Picture * picture) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (decoder); + GstDxvaVp9DecoderClass *klass = GST_DXVA_VP9_DECODER_GET_CLASS (self); + GstVp9Picture *new_picture; + + g_assert (klass->duplicate_picture); + + new_picture = gst_vp9_picture_new (); + new_picture->frame_hdr = picture->frame_hdr; + + if (klass->duplicate_picture (self, GST_CODEC_PICTURE (picture), + GST_CODEC_PICTURE (new_picture)) != GST_FLOW_OK) { + gst_vp9_picture_unref (new_picture); + return nullptr; + } + + return new_picture; +} + +static void +gst_dxva_vp9_decoder_copy_frame_params (GstDxvaVp9Decoder * self, + GstVp9Picture * picture, DXVA_PicParams_VP9 * params) +{ + const GstVp9FrameHeader *frame_hdr = &picture->frame_hdr; + + params->profile = frame_hdr->profile; + params->frame_type = frame_hdr->frame_type; + params->show_frame = frame_hdr->show_frame; + params->error_resilient_mode = frame_hdr->error_resilient_mode; + params->subsampling_x = frame_hdr->subsampling_x; + params->subsampling_y = frame_hdr->subsampling_y; + params->refresh_frame_context = frame_hdr->refresh_frame_context; + params->frame_parallel_decoding_mode = + frame_hdr->frame_parallel_decoding_mode; + params->intra_only = frame_hdr->intra_only; + params->frame_context_idx = frame_hdr->frame_context_idx; + params->reset_frame_context = frame_hdr->reset_frame_context; + if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) + params->allow_high_precision_mv = 0; + else + params->allow_high_precision_mv = frame_hdr->allow_high_precision_mv; + + params->width = frame_hdr->width; + params->height = frame_hdr->height; + params->BitDepthMinus8Luma = frame_hdr->bit_depth - 8; + params->BitDepthMinus8Chroma = frame_hdr->bit_depth - 8; + + params->interp_filter = frame_hdr->interpolation_filter; + params->log2_tile_cols = frame_hdr->tile_cols_log2; + params->log2_tile_rows = frame_hdr->tile_rows_log2; +} + +static void +gst_dxva_vp9_decoder_copy_reference_frames (GstDxvaVp9Decoder * self, + GstVp9Picture * picture, GstVp9Dpb * dpb, DXVA_PicParams_VP9 * params) +{ + GstDxvaVp9DecoderPrivate *priv = self->priv; + GstDxvaVp9DecoderClass *klass = GST_DXVA_VP9_DECODER_GET_CLASS (self); + + for (guint i = 0; i < GST_VP9_REF_FRAMES; i++) { + params->ref_frame_map[i].bPicEntry = 0xff; + params->ref_frame_coded_width[i] = 0; + params->ref_frame_coded_height[i] = 0; + + if (dpb->pic_list[i]) { + GstVp9Picture *other = dpb->pic_list[i]; + guint8 id = klass->get_picture_id (self, GST_CODEC_PICTURE (other)); + + if (id != 0xff) { + params->ref_frame_map[i].Index7Bits = id; + params->ref_frame_coded_width[i] = other->frame_hdr.width; + params->ref_frame_coded_height[i] = other->frame_hdr.height; + g_ptr_array_add (priv->ref_pics, other); + } + } + } +} + +static void +gst_dxva_vp9_decoder_copy_frame_refs (GstDxvaVp9Decoder * self, + GstVp9Picture * picture, DXVA_PicParams_VP9 * params) +{ + const GstVp9FrameHeader *frame_hdr = &picture->frame_hdr; + gint i; + + for (i = 0; i < GST_VP9_REFS_PER_FRAME; i++) + params->frame_refs[i] = params->ref_frame_map[frame_hdr->ref_frame_idx[i]]; + + G_STATIC_ASSERT (G_N_ELEMENTS (params->ref_frame_sign_bias) == + G_N_ELEMENTS (frame_hdr->ref_frame_sign_bias)); + G_STATIC_ASSERT (sizeof (params->ref_frame_sign_bias) == + sizeof (frame_hdr->ref_frame_sign_bias)); + memcpy (params->ref_frame_sign_bias, + frame_hdr->ref_frame_sign_bias, sizeof (frame_hdr->ref_frame_sign_bias)); +} + +static void +gst_dxva_vp9_decoder_copy_loop_filter_params (GstDxvaVp9Decoder * self, + GstVp9Picture * picture, DXVA_PicParams_VP9 * params) +{ + GstDxvaVp9DecoderPrivate *priv = self->priv; + const GstVp9FrameHeader *frame_hdr = &picture->frame_hdr; + const GstVp9LoopFilterParams *lfp = &frame_hdr->loop_filter_params; + + params->filter_level = lfp->loop_filter_level; + params->sharpness_level = lfp->loop_filter_sharpness; + params->mode_ref_delta_enabled = lfp->loop_filter_delta_enabled; + params->mode_ref_delta_update = lfp->loop_filter_delta_update; + params->use_prev_in_find_mv_refs = + priv->last_show_frame && !frame_hdr->error_resilient_mode; + + if (frame_hdr->frame_type != GST_VP9_KEY_FRAME && !frame_hdr->intra_only) { + params->use_prev_in_find_mv_refs &= + (frame_hdr->width == priv->last_frame_width && + frame_hdr->height == priv->last_frame_height); + } + + G_STATIC_ASSERT (G_N_ELEMENTS (params->ref_deltas) == + G_N_ELEMENTS (lfp->loop_filter_ref_deltas)); + G_STATIC_ASSERT (sizeof (params->ref_deltas) == + sizeof (lfp->loop_filter_ref_deltas)); + memcpy (params->ref_deltas, lfp->loop_filter_ref_deltas, + sizeof (lfp->loop_filter_ref_deltas)); + + G_STATIC_ASSERT (G_N_ELEMENTS (params->mode_deltas) == + G_N_ELEMENTS (lfp->loop_filter_mode_deltas)); + G_STATIC_ASSERT (sizeof (params->mode_deltas) == + sizeof (lfp->loop_filter_mode_deltas)); + memcpy (params->mode_deltas, lfp->loop_filter_mode_deltas, + sizeof (lfp->loop_filter_mode_deltas)); +} + +static void +gst_dxva_vp9_decoder_copy_quant_params (GstDxvaVp9Decoder * self, + GstVp9Picture * picture, DXVA_PicParams_VP9 * params) +{ + const GstVp9FrameHeader *frame_hdr = &picture->frame_hdr; + const GstVp9QuantizationParams *qp = &frame_hdr->quantization_params; + + params->base_qindex = qp->base_q_idx; + params->y_dc_delta_q = qp->delta_q_y_dc; + params->uv_dc_delta_q = qp->delta_q_uv_dc; + params->uv_ac_delta_q = qp->delta_q_uv_ac; +} + +static void +gst_dxva_vp9_decoder_copy_segmentation_params (GstDxvaVp9Decoder * self, + GstVp9Picture * picture, DXVA_PicParams_VP9 * params) +{ + const GstVp9FrameHeader *frame_hdr = &picture->frame_hdr; + const GstVp9SegmentationParams *sp = &frame_hdr->segmentation_params; + + params->stVP9Segments.enabled = sp->segmentation_enabled; + params->stVP9Segments.update_map = sp->segmentation_update_map; + params->stVP9Segments.temporal_update = sp->segmentation_temporal_update; + params->stVP9Segments.abs_delta = sp->segmentation_abs_or_delta_update; + + G_STATIC_ASSERT (G_N_ELEMENTS (params->stVP9Segments.tree_probs) == + G_N_ELEMENTS (sp->segmentation_tree_probs)); + G_STATIC_ASSERT (sizeof (params->stVP9Segments.tree_probs) == + sizeof (sp->segmentation_tree_probs)); + memcpy (params->stVP9Segments.tree_probs, sp->segmentation_tree_probs, + sizeof (sp->segmentation_tree_probs)); + + G_STATIC_ASSERT (G_N_ELEMENTS (params->stVP9Segments.pred_probs) == + G_N_ELEMENTS (sp->segmentation_pred_prob)); + G_STATIC_ASSERT (sizeof (params->stVP9Segments.pred_probs) == + sizeof (sp->segmentation_pred_prob)); + + if (sp->segmentation_temporal_update) { + memcpy (params->stVP9Segments.pred_probs, sp->segmentation_pred_prob, + sizeof (params->stVP9Segments.pred_probs)); + } else { + memset (params->stVP9Segments.pred_probs, 255, + sizeof (params->stVP9Segments.pred_probs)); + } + + for (guint i = 0; i < GST_VP9_MAX_SEGMENTS; i++) { + params->stVP9Segments.feature_mask[i] = + (sp->feature_enabled[i][GST_VP9_SEG_LVL_ALT_Q] << 0) | + (sp->feature_enabled[i][GST_VP9_SEG_LVL_ALT_L] << 1) | + (sp->feature_enabled[i][GST_VP9_SEG_LVL_REF_FRAME] << 2) | + (sp->feature_enabled[i][GST_VP9_SEG_SEG_LVL_SKIP] << 3); + + for (guint j = 0; j < 3; j++) + params->stVP9Segments.feature_data[i][j] = sp->feature_data[i][j]; + params->stVP9Segments.feature_data[i][3] = 0; + } +} + +static GstFlowReturn +gst_dxva_vp9_decoder_decode_picture (GstVp9Decoder * decoder, + GstVp9Picture * picture, GstVp9Dpb * dpb) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (decoder); + GstDxvaVp9DecoderPrivate *priv = self->priv; + GstDxvaVp9DecoderClass *klass = GST_DXVA_VP9_DECODER_GET_CLASS (self); + DXVA_PicParams_VP9 *pic_params = &priv->pic_params; + DXVA_Slice_VPx_Short *slice = &priv->slice; + GstCodecPicture *codec_picture = GST_CODEC_PICTURE (picture); + GstFlowReturn ret; + guint8 picture_id; + + g_assert (klass->start_picture); + g_assert (klass->get_picture_id); + + ret = klass->start_picture (self, codec_picture, &picture_id); + if (ret != GST_FLOW_OK) + return ret; + + priv->bitstream_buffer.resize (0); + g_ptr_array_set_size (priv->ref_pics, 0); + + memset (pic_params, 0, sizeof (DXVA_PicParams_VP9)); + + pic_params->CurrPic.Index7Bits = picture_id; + pic_params->uncompressed_header_size_byte_aligned = + picture->frame_hdr.frame_header_length_in_bytes; + pic_params->first_partition_size = picture->frame_hdr.header_size_in_bytes; + pic_params->StatusReportFeedbackNumber = 1; + + gst_dxva_vp9_decoder_copy_reference_frames (self, picture, dpb, pic_params); + gst_dxva_vp9_decoder_copy_frame_params (self, picture, pic_params); + gst_dxva_vp9_decoder_copy_frame_refs (self, picture, pic_params); + gst_dxva_vp9_decoder_copy_loop_filter_params (self, picture, pic_params); + gst_dxva_vp9_decoder_copy_quant_params (self, picture, pic_params); + gst_dxva_vp9_decoder_copy_segmentation_params (self, picture, pic_params); + + priv->bitstream_buffer.resize (picture->size); + memcpy (&priv->bitstream_buffer[0], picture->data, picture->size); + + slice->BSNALunitDataLocation = 0; + slice->SliceBytesInBuffer = priv->bitstream_buffer.size (); + slice->wBadSliceChopping = 0; + + priv->last_frame_width = pic_params->width; + priv->last_frame_height = pic_params->height; + priv->last_show_frame = pic_params->show_frame; + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dxva_vp9_decoder_end_picture (GstVp9Decoder * decoder, + GstVp9Picture * picture) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (decoder); + GstDxvaVp9DecoderPrivate *priv = self->priv; + GstDxvaVp9DecoderClass *klass = GST_DXVA_VP9_DECODER_GET_CLASS (self); + size_t bitstream_buffer_size; + size_t bitstream_pos; + GstDxvaDecodingArgs args; + + if (priv->bitstream_buffer.empty ()) { + GST_ERROR_OBJECT (self, "No bitstream buffer to submit"); + return GST_FLOW_ERROR; + } + + memset (&args, 0, sizeof (GstDxvaDecodingArgs)); + + bitstream_pos = priv->bitstream_buffer.size (); + bitstream_buffer_size = GST_ROUND_UP_128 (bitstream_pos); + + if (bitstream_buffer_size > bitstream_pos) { + size_t padding = bitstream_buffer_size - bitstream_pos; + + /* As per DXVA spec, total amount of bitstream buffer size should be + * 128 bytes aligned. If actual data is not multiple of 128 bytes, + * the last slice data needs to be zero-padded */ + priv->bitstream_buffer.resize (bitstream_buffer_size, 0); + + priv->slice.SliceBytesInBuffer += padding; + } + + args.picture_params = &priv->pic_params; + args.picture_params_size = sizeof (DXVA_PicParams_VP9); + args.slice_control = &priv->slice; + args.slice_control_size = sizeof (DXVA_Slice_VPx_Short); + args.bitstream = &priv->bitstream_buffer[0]; + args.bitstream_size = priv->bitstream_buffer.size (); + + g_assert (klass->end_picture); + + return klass->end_picture (self, GST_CODEC_PICTURE (picture), + priv->ref_pics, &args); +} + +static GstFlowReturn +gst_dxva_vp9_decoder_output_picture (GstVp9Decoder * decoder, + GstVideoCodecFrame * frame, GstVp9Picture * picture) +{ + GstDxvaVp9Decoder *self = GST_DXVA_VP9_DECODER (decoder); + GstDxvaVp9DecoderClass *klass = GST_DXVA_VP9_DECODER_GET_CLASS (self); + + g_assert (klass->output_picture); + + GST_LOG_OBJECT (self, "Outputting picture %p", picture); + + return klass->output_picture (self, frame, GST_CODEC_PICTURE (picture), + (GstVideoBufferFlags) 0, picture->frame_hdr.width, + picture->frame_hdr.height); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp9decoder.h b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp9decoder.h new file mode 100644 index 0000000000..a07c28d85d --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/gstdxvavp9decoder.h @@ -0,0 +1,94 @@ +/* GStreamer + * Copyright (C) 2023 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DXVA_VP9_DECODER (gst_dxva_vp9_decoder_get_type()) +#define GST_DXVA_VP9_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DXVA_VP9_DECODER,GstDxvaVp9Decoder)) +#define GST_DXVA_VP9_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DXVA_VP9_DECODER,GstDxvaVp9DecoderClass)) +#define GST_DXVA_VP9_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_DXVA_VP9_DECODER,GstDxvaVp9DecoderClass)) +#define GST_IS_DXVA_VP9_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DXVA_VP9_DECODER)) +#define GST_IS_DXVA_VP9_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DXVA_VP9_DECODER)) +#define GST_DXVA_VP9_DECODER_CAST(obj) ((GstDxvaVp9Decoder*)obj) + +typedef struct _GstDxvaVp9Decoder GstDxvaVp9Decoder; +typedef struct _GstDxvaVp9DecoderClass GstDxvaVp9DecoderClass; +typedef struct _GstDxvaVp9DecoderPrivate GstDxvaVp9DecoderPrivate; + +struct _GstDxvaVp9Decoder +{ + GstVp9Decoder parent; + + /*< private >*/ + GstDxvaVp9DecoderPrivate *priv; +}; + +struct _GstDxvaVp9DecoderClass +{ + GstVp9DecoderClass parent_class; + + GstFlowReturn (*configure) (GstDxvaVp9Decoder * decoder, + GstVideoCodecState * input_state, + const GstVideoInfo * info, + gint crop_x, + gint crop_y, + gint coded_width, + gint coded_height, + gint max_dpb_size); + + GstFlowReturn (*new_picture) (GstDxvaVp9Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*duplicate_picture) (GstDxvaVp9Decoder * decoder, + GstCodecPicture * src, + GstCodecPicture * dst); + + guint8 (*get_picture_id) (GstDxvaVp9Decoder * decoder, + GstCodecPicture * picture); + + GstFlowReturn (*start_picture) (GstDxvaVp9Decoder * decoder, + GstCodecPicture * picture, + guint8 * picture_id); + + GstFlowReturn (*end_picture) (GstDxvaVp9Decoder * decoder, + GstCodecPicture * picture, + GPtrArray * ref_pics, + const GstDxvaDecodingArgs * args); + + GstFlowReturn (*output_picture) (GstDxvaVp9Decoder * decoder, + GstVideoCodecFrame * frame, + GstCodecPicture * picture, + GstVideoBufferFlags buffer_flags, + gint display_width, + gint display_height); +}; + +GST_DXVA_API +GType gst_dxva_vp9_decoder_get_type (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstDxvaVp9Decoder, gst_object_unref) + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/dxva/meson.build b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/meson.build new file mode 100644 index 0000000000..3625344e0d --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/dxva/meson.build @@ -0,0 +1,55 @@ +dxva_sources = [ + 'gstdxvaav1decoder.cpp', + 'gstdxvah264decoder.cpp', + 'gstdxvah265decoder.cpp', + 'gstdxvampeg2decoder.cpp', + 'gstdxvautils.cpp', + 'gstdxvavp8decoder.cpp', + 'gstdxvavp9decoder.cpp', +] + +extra_args = [ + '-DGST_USE_UNSTABLE_API', + '-DBUILDING_GST_DXVA', + '-DG_LOG_DOMAIN="GStreamer-Dxva"', +] + +if host_system != 'windows' + subdir_done() +endif + +if not cc.has_header('dxva.h') or not cc.has_header('d3d9.h') + subdir_done() +endif + +# MinGW 32bits compiler seems to be complaining about redundant-decls +# when ComPtr is in use. Let's just disable the warning +if cc.get_id() != 'msvc' + extra_mingw_args = cc.get_supported_arguments([ + '-Wno-redundant-decls', + ]) + + extra_args += extra_mingw_args +endif + +pkg_name = 'gstreamer-dxva-' + api_version +gstdxva = library('gstdxva-' + api_version, + dxva_sources, + c_args : gst_plugins_bad_args + extra_args, + cpp_args : gst_plugins_bad_args + extra_args, + include_directories : [configinc, libsinc], + version : libversion, + soversion : soversion, + install : true, + dependencies : [gstvideo_dep, gstcodecs_dep] +) + +library_def = {'lib': gstdxva} +gst_libraries += [[pkg_name, library_def]] + +# Still non-public api, should not install headers +gstdxva_dep = declare_dependency(link_with : gstdxva, + include_directories : [libsinc], + dependencies : [gstvideo_dep, gstcodecs_dep]) + +meson.override_dependency(pkg_name, gstdxva_dep) \ No newline at end of file diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/meson.build b/subprojects/gst-plugins-bad/gst-libs/gst/meson.build index 515f981945..fc4ba6942b 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/meson.build +++ b/subprojects/gst-plugins-bad/gst-libs/gst/meson.build @@ -8,6 +8,7 @@ subdir('codecs') subdir('d3d11') # cuda can depend on d3d11 subdir('cuda') +subdir('dxva') subdir('insertbin') subdir('interfaces') subdir('isoff')