gstreamer/gst-libs/gst/vaapi/gstvaapidecoder_av1.c
He Junyan 5523b75550 libs: decoder: Add decode_with_surface_id for AV1 film_grain.
The AV1 film_graim feature needs two surfaces the same time for
decoding. One is for recon surface which will be used as reference
later, and the other one is for display. The GstVaapiPicture should
contain the surface for display, while the vaBeginPicture() need
the recon surface as the target.
We add a gst_vaapi_picture_decode_with_surface_id API to handle this
kind of requirement.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/merge_requests/191>
2021-01-06 00:08:10 +08:00

1292 lines
43 KiB
C

/*
* gstvaapidecoder_av1.c - AV1 decoder
*
* Copyright (C) 2019-2020 Intel Corporation
* Author: Junyan He <junyan.he@intel.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* SECTION:gstvaapidecoder_av1
* @short_description: AV1 decoder
*/
#include "sysdeps.h"
#include <gst/codecparsers/gstav1parser.h>
#include "gstvaapidecoder_av1.h"
#include "gstvaapidecoder_objects.h"
#include "gstvaapidecoder_priv.h"
#include "gstvaapidisplay_priv.h"
#include "gstvaapicompat.h"
#define DEBUG 1
#include "gstvaapidebug.h"
#define GST_VAAPI_DECODER_AV1_CAST(decoder) ((GstVaapiDecoderAV1 *)(decoder))
typedef struct _GstVaapiDecoderAV1Private GstVaapiDecoderAV1Private;
typedef struct _GstVaapiDecoderAV1Class GstVaapiDecoderAV1Class;
typedef struct _GstVaapiPictureAV1 GstVaapiPictureAV1;
struct _GstVaapiDecoderAV1Private
{
GstVaapiProfile profile;
guint width;
guint height;
gboolean reset_context;
GstVaapiPictureAV1 *current_picture;
gboolean annex_b;
GstAV1Parser *parser;
GstAV1SequenceHeaderOBU *seq_header;
GstVaapiPictureAV1 *ref_frames[GST_AV1_NUM_REF_FRAMES];
};
/**
* GstVaapiDecoderAV1:
*
* A decoder based on AV1.
*/
struct _GstVaapiDecoderAV1
{
/*< private > */
GstVaapiDecoder parent_instance;
GstVaapiDecoderAV1Private priv;
};
/**
* GstVaapiDecoderAV1Class:
*
* A decoder class based on AV1.
*/
struct _GstVaapiDecoderAV1Class
{
/*< private > */
GstVaapiDecoderClass parent_class;
};
G_DEFINE_TYPE (GstVaapiDecoderAV1, gst_vaapi_decoder_av1,
GST_TYPE_VAAPI_DECODER);
/* ------------------------------------------------------------------------- */
/* --- AV1 Parser Info --- */
/* ------------------------------------------------------------------------- */
typedef struct _GstVaapiParserInfoAV1 GstVaapiParserInfoAV1;
struct _GstVaapiParserInfoAV1
{
GstVaapiMiniObject parent_instance;
GstAV1OBU obu;
union
{
GstAV1SequenceHeaderOBU seq_header;
GstAV1MetadataOBU metadata;
GstAV1FrameHeaderOBU frame_header;
GstAV1TileListOBU tile_list;
GstAV1TileGroupOBU tile_group;
GstAV1FrameOBU frame;
};
/* The offset between input data and real OBU data */
gint data_offset;
};
static void
parser_info_av1_finalize (GstVaapiParserInfoAV1 * pi)
{
}
static inline const GstVaapiMiniObjectClass *
parser_info_av1_class (void)
{
static const GstVaapiMiniObjectClass GstVaapiParserInfoAV1Class = {
.size = sizeof (GstVaapiParserInfoAV1),
.finalize = (GDestroyNotify) parser_info_av1_finalize
};
return &GstVaapiParserInfoAV1Class;
}
static inline GstVaapiParserInfoAV1 *
parser_info_av1_new (GstAV1OBU * obu)
{
GstVaapiParserInfoAV1 *pi = (GstVaapiParserInfoAV1 *)
gst_vaapi_mini_object_new (parser_info_av1_class ());
if (pi)
pi->obu = *obu;
return pi;
}
/* ------------------------------------------------------------------------- */
/* --- AV1 Picture --- */
/* ------------------------------------------------------------------------- */
struct _GstVaapiPictureAV1
{
GstVaapiPicture base;
/* When apply_grain enabled, recon proxy is different from the display
proxy, otherwise the same. */
GstVaapiSurfaceProxy *recon_proxy;
GstAV1FrameHeaderOBU frame_header;
gboolean cloned;
};
GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPictureAV1, gst_vaapi_picture_av1);
void
gst_vaapi_picture_av1_destroy (GstVaapiPictureAV1 * picture)
{
if (picture->recon_proxy) {
gst_vaapi_surface_proxy_unref (picture->recon_proxy);
picture->recon_proxy = NULL;
}
gst_vaapi_picture_destroy (GST_VAAPI_PICTURE (picture));
}
gboolean
gst_vaapi_picture_av1_create (GstVaapiPictureAV1 * picture,
const GstVaapiCodecObjectConstructorArgs * args)
{
if (!gst_vaapi_picture_create (GST_VAAPI_PICTURE (picture), args))
return FALSE;
picture->recon_proxy = gst_vaapi_surface_proxy_ref (picture->base.proxy);
g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy) ==
picture->base.surface_id);
return TRUE;
}
static inline GstVaapiPictureAV1 *
gst_vaapi_picture_av1_new (GstVaapiDecoderAV1 * decoder)
{
GstVaapiPictureAV1 *picture;
picture = (GstVaapiPictureAV1 *)
gst_vaapi_codec_object_new (&GstVaapiPictureAV1Class,
GST_VAAPI_CODEC_BASE (decoder), NULL,
sizeof (VADecPictureParameterBufferAV1), NULL, 0, 0);
if (picture)
picture->cloned = FALSE;
return picture;
}
static const gchar *
av1_obu_name (GstAV1OBUType type)
{
switch (type) {
case GST_AV1_OBU_SEQUENCE_HEADER:
return "sequence header";
case GST_AV1_OBU_TEMPORAL_DELIMITER:
return "temporal delimiter";
case GST_AV1_OBU_FRAME_HEADER:
return "frame header";
case GST_AV1_OBU_TILE_GROUP:
return "tile group";
case GST_AV1_OBU_METADATA:
return "metadata";
case GST_AV1_OBU_FRAME:
return "frame";
case GST_AV1_OBU_REDUNDANT_FRAME_HEADER:
return "redundant frame header";
case GST_AV1_OBU_TILE_LIST:
return "tile list";
case GST_AV1_OBU_PADDING:
return "padding";
default:
return "unknown";
}
return NULL;
}
static GstVaapiChromaType
av1_get_chroma_type (GstVaapiProfile profile,
GstAV1SequenceHeaderOBU * seq_header)
{
/* 6.4.1:
seq_profile Bit depth Monochrome support Chroma subsampling
0 8 or 10 Yes YUV 4:2:0
1 8 or 10 No YUV 4:4:4
2 8 or 10 Yes YUV 4:2:2
2 12 Yes YUV 4:2:0,YUV 4:2:2,YUV 4:4:4
*/
/* TODO: consider Monochrome case. Just return 4:2:0 for Monochrome now. */
switch (profile) {
case GST_VAAPI_PROFILE_AV1_0:
if (seq_header->bit_depth == 8) {
return GST_VAAPI_CHROMA_TYPE_YUV420;
} else if (seq_header->bit_depth == 10) {
return GST_VAAPI_CHROMA_TYPE_YUV420_10BPP;
}
break;
case GST_VAAPI_PROFILE_AV1_1:
if (seq_header->bit_depth == 8) {
return GST_VAAPI_CHROMA_TYPE_YUV444;
} else if (seq_header->bit_depth == 10) {
return GST_VAAPI_CHROMA_TYPE_YUV444_10BPP;
}
break;
default:
break;
}
GST_WARNING ("can not decide chrome type.");
return 0;
}
static GstVaapiProfile
av1_get_profile (guint profile_idc)
{
GstVaapiProfile profile;
switch (profile_idc) {
case GST_AV1_PROFILE_0:
profile = GST_VAAPI_PROFILE_AV1_0;
break;
case GST_AV1_PROFILE_1:
profile = GST_VAAPI_PROFILE_AV1_1;
break;
default:
GST_INFO ("unsupported av1 profile_idc value %d", profile_idc);
profile = GST_VAAPI_PROFILE_UNKNOWN;
break;
}
return profile;
}
static GstVaapiDecoderStatus
av1_decode_seqeunce (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit)
{
GstVaapiDecoderAV1Private *const priv = &decoder->priv;
GstVaapiProfile profile;
GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
profile = av1_get_profile (pi->seq_header.seq_profile);
if (profile == GST_VAAPI_PROFILE_UNKNOWN)
return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
profile, GST_VAAPI_ENTRYPOINT_VLD)) {
GST_WARNING ("not supported av1 profile %s",
gst_vaapi_profile_get_va_name (profile));
return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
}
if (profile != priv->profile) {
GST_DEBUG ("new av1 profile %s", gst_vaapi_profile_get_va_name (profile));
/* We delay the context creation to when we know the frame resolution */
priv->reset_context = TRUE;
priv->profile = profile;
}
/* update the sequence */
if (priv->seq_header)
g_slice_free (GstAV1SequenceHeaderOBU, priv->seq_header);
priv->seq_header = g_slice_dup (GstAV1SequenceHeaderOBU, &pi->seq_header);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
av1_decoder_ensure_context (GstVaapiDecoderAV1 * decoder)
{
GstVaapiDecoderAV1Private *const priv = &decoder->priv;
GstVaapiContextInfo info;
if (priv->reset_context) {
if (priv->current_picture)
gst_vaapi_picture_replace (&priv->current_picture, NULL);
info.profile = priv->profile;
info.entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
info.width = priv->width;
info.height = priv->height;
info.chroma_type = av1_get_chroma_type (info.profile, priv->seq_header);
if (!info.chroma_type)
return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
info.ref_frames = GST_AV1_NUM_REF_FRAMES + 2;
priv->reset_context = FALSE;
if (!gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info)) {
GST_WARNING ("can not make av1 decoder context with profile %s,"
" width %d, height %d", gst_vaapi_profile_get_va_name (info.profile),
info.width, info.height);
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
}
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static void
av1_fill_segment_info (VADecPictureParameterBufferAV1 * pic_param,
GstAV1FrameHeaderOBU * frame_header)
{
guint i, j;
uint8_t feature_mask;
#define COPY_SEG_FIELD(FP, FS) \
pic_param->seg_info.segment_info_fields.bits.FP = \
(frame_header)->segmentation_params.FS
COPY_SEG_FIELD (enabled, segmentation_enabled);
COPY_SEG_FIELD (update_map, segmentation_update_map);
COPY_SEG_FIELD (temporal_update, segmentation_temporal_update);
COPY_SEG_FIELD (update_data, segmentation_update_data);
for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++)
for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++)
pic_param->seg_info.feature_data[i][j] =
frame_header->segmentation_params.feature_data[i][j];
for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) {
feature_mask = 0;
for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) {
if (frame_header->segmentation_params.feature_enabled[i][j])
feature_mask |= 1 << j;
}
pic_param->seg_info.feature_mask[i] = feature_mask;
}
#undef COPY_SEG_FIELD
}
static void
av1_fill_film_grain_info (VADecPictureParameterBufferAV1 * pic_param,
GstAV1FrameHeaderOBU * frame_header)
{
guint i;
if (!frame_header->film_grain_params.apply_grain)
return;
#define COPY_FILM_GRAIN_FIELD(FP) \
pic_param->SUB_FIELD.FP = (frame_header)->film_grain_params.FP
#define SUB_FIELD film_grain_info.film_grain_info_fields.bits
COPY_FILM_GRAIN_FIELD (apply_grain);
COPY_FILM_GRAIN_FIELD (chroma_scaling_from_luma);
COPY_FILM_GRAIN_FIELD (grain_scaling_minus_8);
COPY_FILM_GRAIN_FIELD (ar_coeff_lag);
COPY_FILM_GRAIN_FIELD (ar_coeff_shift_minus_6);
COPY_FILM_GRAIN_FIELD (grain_scale_shift);
COPY_FILM_GRAIN_FIELD (overlap_flag);
COPY_FILM_GRAIN_FIELD (clip_to_restricted_range);
#undef SUB_FIELD
pic_param->film_grain_info.grain_seed =
frame_header->film_grain_params.grain_seed;
pic_param->film_grain_info.num_y_points =
frame_header->film_grain_params.num_y_points;
for (i = 0; i < frame_header->film_grain_params.num_y_points; i++) {
pic_param->film_grain_info.point_y_value[i] =
frame_header->film_grain_params.point_y_value[i];
pic_param->film_grain_info.point_y_scaling[i] =
frame_header->film_grain_params.point_y_scaling[i];
}
pic_param->film_grain_info.num_cb_points =
frame_header->film_grain_params.num_cb_points;
for (i = 0; i < frame_header->film_grain_params.num_cb_points; i++) {
pic_param->film_grain_info.point_cb_value[i] =
frame_header->film_grain_params.point_cb_value[i];
pic_param->film_grain_info.point_cb_scaling[i] =
frame_header->film_grain_params.point_cb_scaling[i];
}
pic_param->film_grain_info.num_cr_points =
frame_header->film_grain_params.num_cr_points;
for (i = 0; i < frame_header->film_grain_params.num_cr_points; i++) {
pic_param->film_grain_info.point_cr_value[i] =
frame_header->film_grain_params.point_cr_value[i];
pic_param->film_grain_info.point_cr_scaling[i] =
frame_header->film_grain_params.point_cr_scaling[i];
}
if (pic_param->film_grain_info.num_y_points) {
for (i = 0; i < 24; i++) {
pic_param->film_grain_info.ar_coeffs_y[i] =
frame_header->film_grain_params.ar_coeffs_y_plus_128[i] - 128;
}
}
if (frame_header->film_grain_params.chroma_scaling_from_luma
|| pic_param->film_grain_info.num_cb_points) {
for (i = 0; i < GST_AV1_MAX_NUM_POS_LUMA; i++) {
pic_param->film_grain_info.ar_coeffs_cb[i] =
frame_header->film_grain_params.ar_coeffs_cb_plus_128[i] - 128;
}
}
if (frame_header->film_grain_params.chroma_scaling_from_luma
|| pic_param->film_grain_info.num_cr_points) {
for (i = 0; i < GST_AV1_MAX_NUM_POS_LUMA; i++) {
pic_param->film_grain_info.ar_coeffs_cr[i] =
frame_header->film_grain_params.ar_coeffs_cr_plus_128[i] - 128;
}
}
#define SUB_FIELD film_grain_info
COPY_FILM_GRAIN_FIELD (cb_mult);
COPY_FILM_GRAIN_FIELD (cb_luma_mult);
COPY_FILM_GRAIN_FIELD (cb_offset);
COPY_FILM_GRAIN_FIELD (cr_mult);
COPY_FILM_GRAIN_FIELD (cr_luma_mult);
COPY_FILM_GRAIN_FIELD (cr_offset);
#undef SUB_FIELD
#undef COPY_FILM_GRAIN_FIELD
}
static void
av1_fill_loop_filter_info (VADecPictureParameterBufferAV1 * pic_param,
GstAV1FrameHeaderOBU * frame_header)
{
guint i;
pic_param->superres_scale_denominator = frame_header->superres_denom;
pic_param->interp_filter = frame_header->interpolation_filter;
pic_param->filter_level[0] =
frame_header->loop_filter_params.loop_filter_level[0];
pic_param->filter_level[1] =
frame_header->loop_filter_params.loop_filter_level[1];
pic_param->filter_level_u =
frame_header->loop_filter_params.loop_filter_level[2];
pic_param->filter_level_v =
frame_header->loop_filter_params.loop_filter_level[3];
pic_param->loop_filter_info_fields.bits.sharpness_level =
frame_header->loop_filter_params.loop_filter_sharpness;
pic_param->loop_filter_info_fields.bits.mode_ref_delta_enabled =
frame_header->loop_filter_params.loop_filter_delta_enabled;
pic_param->loop_filter_info_fields.bits.mode_ref_delta_update =
frame_header->loop_filter_params.loop_filter_delta_update;
for (i = 0; i < GST_AV1_TOTAL_REFS_PER_FRAME; i++)
pic_param->ref_deltas[i] =
frame_header->loop_filter_params.loop_filter_ref_deltas[i];
for (i = 0; i < 2; i++)
pic_param->mode_deltas[i] =
frame_header->loop_filter_params.loop_filter_mode_deltas[i];
pic_param->mode_control_fields.bits.delta_lf_present_flag =
frame_header->loop_filter_params.delta_lf_present;
pic_param->mode_control_fields.bits.log2_delta_lf_res =
frame_header->loop_filter_params.delta_lf_res;
pic_param->mode_control_fields.bits.delta_lf_multi =
frame_header->loop_filter_params.delta_lf_multi;
}
static void
av1_fill_quantization_info (VADecPictureParameterBufferAV1 * pic_param,
GstAV1FrameHeaderOBU * frame_header)
{
pic_param->base_qindex = frame_header->quantization_params.base_q_idx;
pic_param->y_dc_delta_q = frame_header->quantization_params.delta_q_y_dc;
pic_param->u_dc_delta_q = frame_header->quantization_params.delta_q_u_dc;
pic_param->u_ac_delta_q = frame_header->quantization_params.delta_q_u_ac;
pic_param->v_dc_delta_q = frame_header->quantization_params.delta_q_v_dc;
pic_param->v_ac_delta_q = frame_header->quantization_params.delta_q_v_ac;
pic_param->qmatrix_fields.bits.using_qmatrix =
frame_header->quantization_params.using_qmatrix;
if (pic_param->qmatrix_fields.bits.using_qmatrix) {
pic_param->qmatrix_fields.bits.qm_y =
frame_header->quantization_params.qm_y;
pic_param->qmatrix_fields.bits.qm_u =
frame_header->quantization_params.qm_u;
pic_param->qmatrix_fields.bits.qm_v =
frame_header->quantization_params.qm_v;
} else {
pic_param->qmatrix_fields.bits.qm_y = 0;
pic_param->qmatrix_fields.bits.qm_u = 0;
pic_param->qmatrix_fields.bits.qm_v = 0;
}
pic_param->mode_control_fields.bits.delta_q_present_flag =
frame_header->quantization_params.delta_q_present;
pic_param->mode_control_fields.bits.log2_delta_q_res =
frame_header->quantization_params.delta_q_res;
}
static void
av1_fill_cdef_info (VADecPictureParameterBufferAV1 * pic_param,
GstAV1FrameHeaderOBU * frame_header, guint8 num_planes)
{
guint8 sec_strength;
guint i;
pic_param->cdef_damping_minus_3 = frame_header->cdef_params.cdef_damping - 3;
pic_param->cdef_bits = frame_header->cdef_params.cdef_bits;
for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
sec_strength = frame_header->cdef_params.cdef_y_sec_strength[i];
g_assert (sec_strength <= 4);
/* may need to minus 1 in order to merge with primary value. */
if (sec_strength == 4)
sec_strength--;
pic_param->cdef_y_strengths[i] =
((frame_header->cdef_params.cdef_y_pri_strength[i] & 0xf) << 2) |
(sec_strength & 0x03);
}
if (num_planes > 1) {
for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
sec_strength = frame_header->cdef_params.cdef_uv_sec_strength[i];
g_assert (sec_strength <= 4);
/* may need to minus 1 in order to merge with primary value. */
if (sec_strength == 4)
sec_strength--;
pic_param->cdef_uv_strengths[i] =
((frame_header->cdef_params.cdef_uv_pri_strength[i] & 0xf) << 2) |
(sec_strength & 0x03);
}
} else {
for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
pic_param->cdef_uv_strengths[i] = 0;
}
}
}
static void
av1_fill_loop_restoration_info (VADecPictureParameterBufferAV1 * pic_param,
GstAV1FrameHeaderOBU * frame_header)
{
pic_param->loop_restoration_fields.bits.yframe_restoration_type =
frame_header->loop_restoration_params.frame_restoration_type[0];
pic_param->loop_restoration_fields.bits.cbframe_restoration_type =
frame_header->loop_restoration_params.frame_restoration_type[1];
pic_param->loop_restoration_fields.bits.crframe_restoration_type =
frame_header->loop_restoration_params.frame_restoration_type[2];
pic_param->loop_restoration_fields.bits.lr_unit_shift =
frame_header->loop_restoration_params.lr_unit_shift;
pic_param->loop_restoration_fields.bits.lr_uv_shift =
frame_header->loop_restoration_params.lr_uv_shift;
}
static void
av1_fill_global_motion_info (VADecPictureParameterBufferAV1 * pic_param,
GstAV1FrameHeaderOBU * frame_header)
{
guint i, j;
for (i = 0; i < 7; i++) {
pic_param->wm[i].wmtype =
frame_header->global_motion_params.gm_type[GST_AV1_REF_LAST_FRAME + i];
for (j = 0; j < 6; j++)
pic_param->wm[i].wmmat[j] =
frame_header->global_motion_params.gm_params
[GST_AV1_REF_LAST_FRAME + i][j];
pic_param->wm[i].wmmat[6] = 0;
pic_param->wm[i].wmmat[7] = 0;
pic_param->wm[i].invalid =
frame_header->global_motion_params.invalid[GST_AV1_REF_LAST_FRAME + i];
}
}
static gboolean
av1_fill_picture_frame_header (GstVaapiDecoderAV1 * decoder,
GstVaapiPictureAV1 * picture, GstAV1FrameHeaderOBU * frame_header)
{
GstVaapiDecoderAV1Private *priv = &decoder->priv;
VADecPictureParameterBufferAV1 *pic_param =
GST_VAAPI_PICTURE (picture)->param;
GstAV1SequenceHeaderOBU *seq_header = priv->seq_header;
guint i;
pic_param->profile = seq_header->seq_profile;
pic_param->order_hint_bits_minus_1 = seq_header->order_hint_bits_minus_1;
if (seq_header->bit_depth == 8)
pic_param->bit_depth_idx = 0;
else if (seq_header->bit_depth == 10)
pic_param->bit_depth_idx = 1;
else if (seq_header->bit_depth == 12)
pic_param->bit_depth_idx = 2;
else
g_assert (0);
pic_param->matrix_coefficients = seq_header->color_config.matrix_coefficients;
#define COPY_SEQ_FIELD(FP, FS) \
pic_param->seq_info_fields.fields.FP = (seq_header)->FS
COPY_SEQ_FIELD (still_picture, still_picture);
COPY_SEQ_FIELD (use_128x128_superblock, use_128x128_superblock);
COPY_SEQ_FIELD (enable_filter_intra, enable_filter_intra);
COPY_SEQ_FIELD (enable_intra_edge_filter, enable_intra_edge_filter);
COPY_SEQ_FIELD (enable_interintra_compound, enable_interintra_compound);
COPY_SEQ_FIELD (enable_masked_compound, enable_masked_compound);
COPY_SEQ_FIELD (enable_dual_filter, enable_dual_filter);
COPY_SEQ_FIELD (enable_order_hint, enable_order_hint);
COPY_SEQ_FIELD (enable_jnt_comp, enable_jnt_comp);
COPY_SEQ_FIELD (enable_cdef, enable_cdef);
COPY_SEQ_FIELD (mono_chrome, color_config.mono_chrome);
COPY_SEQ_FIELD (color_range, color_config.color_range);
COPY_SEQ_FIELD (subsampling_x, color_config.subsampling_x);
COPY_SEQ_FIELD (subsampling_y, color_config.subsampling_y);
COPY_SEQ_FIELD (film_grain_params_present, film_grain_params_present);
#undef COPY_SEQ_FIELD
if (frame_header->film_grain_params.apply_grain) {
g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy) !=
GST_VAAPI_PICTURE (picture)->surface_id);
pic_param->current_frame =
GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy);
pic_param->current_display_picture =
GST_VAAPI_PICTURE (picture)->surface_id;
} else {
pic_param->current_frame = GST_VAAPI_PICTURE (picture)->surface_id;
pic_param->current_display_picture =
GST_VAAPI_PICTURE (picture)->surface_id;
}
pic_param->frame_width_minus1 = frame_header->upscaled_width - 1;
pic_param->frame_height_minus1 = frame_header->frame_height - 1;
for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
if (priv->ref_frames[i])
pic_param->ref_frame_map[i] =
GST_VAAPI_SURFACE_PROXY_SURFACE_ID (priv->ref_frames[i]->recon_proxy);
else
pic_param->ref_frame_map[i] = VA_INVALID_SURFACE;
}
for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
pic_param->ref_frame_idx[i] = frame_header->ref_frame_idx[i];
}
pic_param->primary_ref_frame = frame_header->primary_ref_frame;
pic_param->order_hint = frame_header->order_hint;
av1_fill_segment_info (pic_param, frame_header);
av1_fill_film_grain_info (pic_param, frame_header);
pic_param->tile_cols = frame_header->tile_info.tile_cols;
pic_param->tile_rows = frame_header->tile_info.tile_rows;
for (i = 0; i < 63; i++) {
pic_param->width_in_sbs_minus_1[i] =
frame_header->tile_info.width_in_sbs_minus_1[i];
pic_param->height_in_sbs_minus_1[i] =
frame_header->tile_info.height_in_sbs_minus_1[i];
}
pic_param->context_update_tile_id =
frame_header->tile_info.context_update_tile_id;
#define COPY_PIC_FIELD(FIELD) \
pic_param->pic_info_fields.bits.FIELD = (frame_header)->FIELD
COPY_PIC_FIELD (frame_type);
COPY_PIC_FIELD (show_frame);
COPY_PIC_FIELD (showable_frame);
COPY_PIC_FIELD (error_resilient_mode);
COPY_PIC_FIELD (disable_cdf_update);
COPY_PIC_FIELD (allow_screen_content_tools);
COPY_PIC_FIELD (force_integer_mv);
COPY_PIC_FIELD (allow_intrabc);
COPY_PIC_FIELD (use_superres);
COPY_PIC_FIELD (allow_high_precision_mv);
COPY_PIC_FIELD (is_motion_mode_switchable);
COPY_PIC_FIELD (use_ref_frame_mvs);
COPY_PIC_FIELD (disable_frame_end_update_cdf);
pic_param->pic_info_fields.bits.uniform_tile_spacing_flag =
frame_header->tile_info.uniform_tile_spacing_flag;
COPY_PIC_FIELD (allow_warped_motion);
#undef COPY_PIC_FIELD
av1_fill_loop_filter_info (pic_param, frame_header);
av1_fill_quantization_info (pic_param, frame_header);
pic_param->mode_control_fields.bits.tx_mode = frame_header->tx_mode;
pic_param->mode_control_fields.bits.reference_select =
frame_header->reference_select;
pic_param->mode_control_fields.bits.reduced_tx_set_used =
frame_header->reduced_tx_set;
pic_param->mode_control_fields.bits.skip_mode_present =
frame_header->skip_mode_present;
av1_fill_cdef_info (pic_param, frame_header, seq_header->num_planes);
av1_fill_loop_restoration_info (pic_param, frame_header);
av1_fill_global_motion_info (pic_param, frame_header);
return TRUE;
}
static GstVaapiDecoderStatus
av1_decode_frame_header (GstVaapiDecoderAV1 * decoder,
GstVaapiDecoderUnit * unit)
{
GstVaapiDecoderAV1Private *const priv = &decoder->priv;
GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
GstAV1FrameHeaderOBU *frame_header = NULL;
GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
GstVaapiPictureAV1 *picture = NULL;
if (pi->obu.obu_type == GST_AV1_OBU_FRAME_HEADER) {
frame_header = &pi->frame_header;
} else {
g_assert (pi->obu.obu_type == GST_AV1_OBU_FRAME);
frame_header = &pi->frame.frame_header;
}
if (frame_header->show_existing_frame) {
GstVaapiPictureAV1 *to_show_picture = NULL;
to_show_picture = priv->ref_frames[frame_header->frame_to_show_map_idx];
if (to_show_picture == NULL) {
GST_ERROR ("frame_to_show_map_idx point to a invalid picture");
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
if (gst_av1_parser_reference_frame_loading (priv->parser,
&to_show_picture->frame_header) != GST_AV1_PARSER_OK) {
GST_ERROR ("load frame to show ref frame failed");
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
picture = (GstVaapiPictureAV1 *)
gst_vaapi_picture_new_clone (GST_VAAPI_PICTURE_CAST (to_show_picture));
if (!picture)
return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
gst_vaapi_surface_proxy_replace (&picture->recon_proxy,
to_show_picture->recon_proxy);
picture->cloned = TRUE;
GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
picture->frame_header = to_show_picture->frame_header;
/* only update references if the frame_to_show_map_idx is a KEY FRAME */
if (picture->frame_header.frame_type == GST_AV1_KEY_FRAME) {
picture->frame_header = to_show_picture->frame_header;
g_assert (picture->frame_header.refresh_frame_flags ==
((1 << GST_AV1_NUM_REF_FRAMES) - 1));
} else {
/* Just set to no update ref */
picture->frame_header.refresh_frame_flags = 0;
}
} else {
/* Resolution changed */
if (priv->width != priv->seq_header->max_frame_width_minus_1 + 1 ||
priv->height != priv->seq_header->max_frame_height_minus_1 + 1) {
priv->reset_context = TRUE;
priv->width = priv->seq_header->max_frame_width_minus_1 + 1;
priv->height = priv->seq_header->max_frame_height_minus_1 + 1;
GST_INFO ("change the resolution to %dx%d", priv->width, priv->height);
}
ret = av1_decoder_ensure_context (decoder);
if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS)
return ret;
picture = gst_vaapi_picture_av1_new (decoder);
if (!picture)
return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
if (frame_header->upscaled_width != priv->width ||
frame_header->frame_height != priv->height) {
GstVaapiRectangle crop_rect;
if (frame_header->upscaled_width > priv->width) {
GST_WARNING ("Frame width is %d, bigger than sequence max width %d",
frame_header->upscaled_width, priv->width);
gst_vaapi_codec_object_unref (picture);
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
if (frame_header->frame_height > priv->height) {
GST_WARNING ("Frame height is %d, bigger than sequence max height %d",
frame_header->frame_height, priv->height);
gst_vaapi_codec_object_unref (picture);
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
crop_rect.x = 0;
crop_rect.y = 0;
crop_rect.width = frame_header->upscaled_width;
crop_rect.height = frame_header->frame_height;
gst_vaapi_picture_set_crop_rect (GST_VAAPI_PICTURE (picture), &crop_rect);
}
if (frame_header->film_grain_params.apply_grain) {
GstVaapiSurfaceProxy *recon_proxy = gst_vaapi_context_get_surface_proxy
(GST_VAAPI_DECODER (decoder)->context);
if (!recon_proxy) {
gst_vaapi_codec_object_unref (picture);
return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
}
gst_vaapi_surface_proxy_replace (&picture->recon_proxy, recon_proxy);
}
picture->frame_header = *frame_header;
/* this frame will not show this time */
if (!frame_header->show_frame)
GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
GST_VAAPI_PICTURE (picture)->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
GST_VAAPI_PICTURE (picture)->type =
frame_header->frame_is_intra ? GST_VAAPI_PICTURE_TYPE_I :
GST_VAAPI_PICTURE_TYPE_P;
if (!av1_fill_picture_frame_header (decoder, picture, frame_header)) {
gst_vaapi_codec_object_unref (picture);
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
}
gst_vaapi_picture_replace (&priv->current_picture, picture);
gst_vaapi_picture_unref (picture);
return ret;
}
static GstVaapiDecoderStatus
av1_decode_tile_data (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit)
{
GstVaapiDecoderAV1Private *const priv = &decoder->priv;
GstVaapiPictureAV1 *picture = priv->current_picture;
GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
GstAV1TileGroupOBU *tile_group = &pi->tile_group;
guint32 i;
GstVaapiSlice *slice;
GstBuffer *const buffer =
GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
GstMapInfo map_info;
if (!picture) {
GST_WARNING ("Decode the tile date without a picture");
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
GST_ERROR ("failed to map buffer");
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
slice = GST_VAAPI_SLICE_NEW_N_PARAMS (AV1, decoder,
map_info.data + pi->data_offset + unit->offset, pi->obu.obu_size,
(tile_group->tg_end - tile_group->tg_start + 1));
gst_buffer_unmap (buffer, &map_info);
if (!slice) {
GST_ERROR ("failed to allocate slice");
return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
}
for (i = 0; i < tile_group->tg_end - tile_group->tg_start + 1; i++) {
VASliceParameterBufferAV1 *const slice_param =
slice->param + i * sizeof (VASliceParameterBufferAV1);
slice_param->slice_data_size =
tile_group->entry[tile_group->tg_start + i].tile_size;
slice_param->slice_data_offset =
tile_group->entry[tile_group->tg_start + i].tile_offset;
slice_param->tile_row =
tile_group->entry[tile_group->tg_start + i].tile_row;
slice_param->tile_column =
tile_group->entry[tile_group->tg_start + i].tile_col;
slice_param->slice_data_flag = 0;
}
gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
av1_decode_unit (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit)
{
GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
GST_DEBUG ("begin to decode the unit of %s", av1_obu_name (pi->obu.obu_type));
switch (pi->obu.obu_type) {
case GST_AV1_OBU_SEQUENCE_HEADER:
ret = av1_decode_seqeunce (decoder, unit);
break;
case GST_AV1_OBU_FRAME_HEADER:
ret = av1_decode_frame_header (decoder, unit);
break;
case GST_AV1_OBU_FRAME:
ret = av1_decode_frame_header (decoder, unit);
if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS)
break;
/* fall through */
case GST_AV1_OBU_TILE_GROUP:
ret = av1_decode_tile_data (decoder, unit);
break;
case GST_AV1_OBU_METADATA:
case GST_AV1_OBU_REDUNDANT_FRAME_HEADER:
case GST_AV1_OBU_PADDING:
/* Not handled */
ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
break;
default:
GST_WARNING ("can not handle obu type %s",
av1_obu_name (pi->obu.obu_type));
ret = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
return ret;
}
static GstVaapiDecoderStatus
av1_decode_current_picture (GstVaapiDecoderAV1 * decoder)
{
GstVaapiDecoderAV1Private *priv = &decoder->priv;
GstVaapiPictureAV1 *const picture =
(GstVaapiPictureAV1 *) priv->current_picture;
g_assert (picture);
if (!gst_vaapi_picture_decode_with_surface_id (GST_VAAPI_PICTURE (picture),
GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy)))
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
av1_decoder_update_state (GstVaapiDecoderAV1 * decoder,
GstVaapiPictureAV1 * picture)
{
GstVaapiDecoderAV1Private *priv = &decoder->priv;
GstAV1ParserResult ret;
guint i;
/* This is a show_existing_frame case, only update key frame */
if (picture->cloned && picture->frame_header.frame_type != GST_AV1_KEY_FRAME)
return GST_VAAPI_DECODER_STATUS_SUCCESS;
ret = gst_av1_parser_reference_frame_update (priv->parser,
&picture->frame_header);
if (ret != GST_AV1_PARSER_OK) {
GST_ERROR ("failed to update the reference.");
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
if ((picture->frame_header.refresh_frame_flags >> i) & 1) {
if (picture) {
GST_LOG ("reference frame %p to ref slot:%d", picture, i);
gst_vaapi_picture_replace (&priv->ref_frames[i], picture);
} else {
GST_ERROR ("we miss some reference frame for ref slot:%d", i);
gst_vaapi_picture_replace (&priv->ref_frames[i], NULL);
}
}
}
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static void
av1_decoder_reset (GstVaapiDecoderAV1 * decoder)
{
GstVaapiDecoderAV1Private *priv = &decoder->priv;
guint i;
priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
priv->width = 0;
priv->height = 0;
priv->annex_b = FALSE;
priv->reset_context = FALSE;
if (priv->current_picture)
gst_vaapi_picture_replace (&priv->current_picture, NULL);
if (priv->seq_header) {
g_slice_free (GstAV1SequenceHeaderOBU, priv->seq_header);
priv->seq_header = NULL;
}
for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++)
gst_vaapi_picture_replace (&priv->ref_frames[i], NULL);
}
static gboolean
av1_is_picture_end (GstVaapiParserInfoAV1 * pi)
{
GstAV1TileGroupOBU *tile_group = NULL;
if (pi->obu.obu_type == GST_AV1_OBU_FRAME) {
tile_group = &pi->frame.tile_group;
} else if (pi->obu.obu_type == GST_AV1_OBU_TILE_GROUP) {
tile_group = &pi->tile_group;
}
g_assert (tile_group);
if (tile_group->tg_end == tile_group->num_tiles - 1)
return TRUE;
return FALSE;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_av1_reset (GstVaapiDecoder * base_decoder)
{
GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
GstVaapiDecoderAV1Private *priv = &decoder->priv;
av1_decoder_reset (decoder);
gst_av1_parser_reset (priv->parser, FALSE);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_av1_parse (GstVaapiDecoder * base_decoder,
GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
{
GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
GstVaapiDecoderAV1Private *const priv = &decoder->priv;
GstVaapiParserInfoAV1 *pi;
GstAV1Parser *parser = priv->parser;
guchar *buf;
guint buf_size, flags;
GstAV1OBU obu;
GstAV1ParserResult av1_ret;
GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
guint32 consumed;
buf_size = gst_adapter_available (adapter);
if (!buf_size)
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
/* no need to do unmap here */
buf = (guchar *) gst_adapter_map (adapter, buf_size);
if (!buf)
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
av1_ret =
gst_av1_parser_identify_one_obu (parser, buf, buf_size, &obu, &consumed);
if (av1_ret == GST_AV1_PARSER_DROP) {
GST_LOG ("just discard a %s obu with size %d, consumed %d",
av1_obu_name (obu.obu_type), obu.obu_size, consumed);
gst_adapter_flush (adapter, consumed);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
} else if (av1_ret == GST_AV1_PARSER_NO_MORE_DATA) {
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
} else if (av1_ret == GST_AV1_PARSER_BITSTREAM_ERROR) {
GST_WARNING_OBJECT (decoder, "parse error, an invalid bitstream");
gst_adapter_flush (adapter, consumed);
return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
} else if (av1_ret != GST_AV1_PARSER_OK) {
GST_WARNING_OBJECT (decoder, "parse error, unknown error");
gst_adapter_flush (adapter, consumed);
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
GST_DEBUG ("get one %s obu with size %d, consumed %d",
av1_obu_name (obu.obu_type), obu.obu_size, consumed);
pi = parser_info_av1_new (&obu);
if (!pi) {
gst_adapter_flush (adapter, consumed);
return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
}
gst_vaapi_decoder_unit_set_parsed_info (unit, pi,
(GDestroyNotify) gst_vaapi_mini_object_unref);
flags = 0;
av1_ret = GST_AV1_PARSER_OK;
switch (pi->obu.obu_type) {
case GST_AV1_OBU_TEMPORAL_DELIMITER:
av1_ret = gst_av1_parser_parse_temporal_delimiter_obu (parser, &pi->obu);
flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
break;
case GST_AV1_OBU_SEQUENCE_HEADER:
av1_ret = gst_av1_parser_parse_sequence_header_obu (parser, &pi->obu,
&pi->seq_header);
break;
case GST_AV1_OBU_REDUNDANT_FRAME_HEADER:
av1_ret = gst_av1_parser_parse_frame_header_obu (parser, &pi->obu,
&pi->frame_header);
break;
case GST_AV1_OBU_FRAME_HEADER:
av1_ret = gst_av1_parser_parse_frame_header_obu (parser, &pi->obu,
&pi->frame_header);
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
if (pi->frame_header.show_existing_frame) {
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
}
break;
case GST_AV1_OBU_FRAME:
av1_ret = gst_av1_parser_parse_frame_obu (parser, &obu, &pi->frame);
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
pi->data_offset = obu.data - buf;
if (av1_is_picture_end (pi))
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
break;
case GST_AV1_OBU_METADATA:
av1_ret = gst_av1_parser_parse_metadata_obu (parser, &obu, &pi->metadata);
break;
case GST_AV1_OBU_TILE_GROUP:
av1_ret = gst_av1_parser_parse_tile_group_obu (parser, &obu,
&pi->tile_group);
flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
pi->data_offset = obu.data - buf;
if (av1_is_picture_end (pi))
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
break;
case GST_AV1_OBU_TILE_LIST:
av1_ret =
gst_av1_parser_parse_tile_list_obu (parser, &obu, &pi->tile_list);
flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
break;
case GST_AV1_OBU_PADDING:
break;
default:
GST_WARNING_OBJECT (decoder, "an unrecognized obu type %d", obu.obu_type);
av1_ret = GST_AV1_PARSER_BITSTREAM_ERROR;
break;
}
if (av1_ret != GST_AV1_PARSER_OK) {
/* Should not get NO_MORE_DATA, the obu size is already known */
GST_WARNING_OBJECT (decoder, "parse %s obu error",
av1_obu_name (pi->obu.obu_type));
gst_adapter_flush (adapter, consumed);
gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pi));
return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
}
unit->size = consumed;
unit->offset = pi->obu.data - buf;
GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
return ret;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_av1_decode (GstVaapiDecoder * base_decoder,
GstVaapiDecoderUnit * unit)
{
GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
GstVaapiDecoderStatus status;
status = av1_decode_unit (decoder, unit);
return status;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_av1_start_frame (GstVaapiDecoder * base_decoder,
GstVaapiDecoderUnit * base_unit)
{
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_av1_end_frame (GstVaapiDecoder * base_decoder)
{
GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
GstVaapiDecoderAV1Private *priv = &decoder->priv;
if (!priv->current_picture->cloned)
status = av1_decode_current_picture (decoder);
/* update state anyway */
av1_decoder_update_state (decoder, priv->current_picture);
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
goto out;
if (!gst_vaapi_picture_output (GST_VAAPI_PICTURE (priv->current_picture)))
status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
out:
gst_vaapi_picture_replace (&priv->current_picture, NULL);
return status;
}
static GstVaapiDecoderStatus
gst_vaapi_decoder_av1_flush (GstVaapiDecoder * base_decoder)
{
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static void
gst_vaapi_decoder_av1_finalize (GObject * object)
{
GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
GstVaapiDecoderAV1Private *priv = &decoder->priv;
av1_decoder_reset (decoder);
if (decoder->priv.parser)
gst_av1_parser_free (decoder->priv.parser);
priv->parser = NULL;
G_OBJECT_CLASS (gst_vaapi_decoder_av1_parent_class)->finalize (object);
}
static void
gst_vaapi_decoder_av1_class_init (GstVaapiDecoderAV1Class * klass)
{
GObjectClass *const object_class = G_OBJECT_CLASS (klass);
GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
object_class->finalize = gst_vaapi_decoder_av1_finalize;
decoder_class->reset = gst_vaapi_decoder_av1_reset;
decoder_class->parse = gst_vaapi_decoder_av1_parse;
decoder_class->decode = gst_vaapi_decoder_av1_decode;
decoder_class->start_frame = gst_vaapi_decoder_av1_start_frame;
decoder_class->end_frame = gst_vaapi_decoder_av1_end_frame;
decoder_class->flush = gst_vaapi_decoder_av1_flush;
}
static void
gst_vaapi_decoder_av1_init (GstVaapiDecoderAV1 * decoder)
{
guint i;
GstVaapiDecoderAV1Private *priv = &decoder->priv;
priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
priv->width = 0;
priv->height = 0;
priv->annex_b = FALSE;
priv->reset_context = FALSE;
priv->current_picture = NULL;
priv->seq_header = NULL;
for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++)
priv->ref_frames[i] = NULL;
priv->parser = gst_av1_parser_new ();
}
/**
* gst_vaapi_decoder_av1_new:
* @display: a #GstVaapiDisplay
* @caps: a #GstCaps holding codec information
*
* Creates a new #GstVaapiDecoder for AV1 decoding. The @caps can
* hold extra information like codec-data and pictured coded size.
*
* Return value: the newly allocated #GstVaapiDecoder object
*/
GstVaapiDecoder *
gst_vaapi_decoder_av1_new (GstVaapiDisplay * display, GstCaps * caps)
{
return g_object_new (GST_TYPE_VAAPI_DECODER_AV1, "display", display,
"caps", caps, NULL);
}