mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-14 05:12:09 +00:00
5523b75550
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>
1292 lines
43 KiB
C
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);
|
|
}
|