vaav1enc: Enable intrablock copy and palette mode

This allow screen content coding (SCC) optimization feature.

Co-authored-by: Victor Jaquez <vjaquez@igalia.com>
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8560>
This commit is contained in:
Jonathan Lui 2025-02-26 03:41:21 +00:00 committed by GStreamer Marge Bot
parent 0c378091a0
commit c81c19bfdc

View File

@ -91,6 +91,8 @@ enum
PROP_TILE_GROUPS,
PROP_MBBRC,
PROP_RATE_CONTROL,
PROP_PALETTE_MODE,
PROP_ALLOW_INTRABC,
N_PROPERTIES
};
@ -225,6 +227,8 @@ struct _GstVaAV1Enc
guint32 num_tile_rows;
guint32 tile_groups;
guint32 mbbrc;
gboolean allow_intrabc;
gboolean enable_palette_mode;
} prop;
struct
@ -1769,6 +1773,9 @@ gst_va_av1_enc_reset_state (GstVaBaseEnc * base)
self->partition.num_tile_cols = self->prop.num_tile_cols;
self->partition.num_tile_rows = self->prop.num_tile_rows;
self->partition.tile_groups = self->prop.tile_groups;
self->features.allow_intrabc = self->prop.allow_intrabc;
self->features.enable_palette_mode = self->prop.enable_palette_mode;
GST_OBJECT_UNLOCK (self);
self->packed_headers = 0;
@ -1789,15 +1796,12 @@ gst_va_av1_enc_reset_state (GstVaBaseEnc * base)
self->features.enable_interintra_compound = FALSE;
self->features.enable_masked_compound = FALSE;
self->features.enable_warped_motion = FALSE;
self->features.enable_palette_mode = FALSE;
self->features.enable_dual_filter = FALSE;
self->features.enable_jnt_comp = FALSE;
self->features.enable_ref_frame_mvs = FALSE;
self->features.enable_superres = FALSE;
self->features.enable_restoration = FALSE;
self->features.allow_intrabc = FALSE;
self->features.enable_segmentation = FALSE;
self->features.enable_cdef = FALSE;
self->features.interpolation_filter_support = 0;
self->features.interpolation_type = 0;
self->features.obu_size_bytes = 0;
@ -1961,6 +1965,7 @@ _av1_decide_profile (GstVaAV1Enc * self, guint rt_format,
2 12 Yes YUV 4:2:0,YUV 4:2:2,YUV 4:4:4
*/
/* We only support 0 and 1 profile now */
/* note that profile 2 doesn't support screen content coding (SCC) */
if (chrome == 0 || chrome == 1) {
va_profile = VAProfileAV1Profile0;
} else if (chrome == 3) {
@ -2315,12 +2320,6 @@ _av1_setup_encoding_features (GstVaAV1Enc * self)
features.value = attrib.value;
if (self->partition.use_128x128_superblock
&& (features.bits.support_128x128_superblock == 0)) {
GST_INFO_OBJECT (self, "128x128 superblock is not supported.");
self->partition.use_128x128_superblock = FALSE;
}
self->features.enable_filter_intra =
(features.bits.support_filter_intra != 0);
self->features.enable_intra_edge_filter =
@ -2329,30 +2328,43 @@ _av1_setup_encoding_features (GstVaAV1Enc * self)
(features.bits.support_interintra_compound != 0);
self->features.enable_masked_compound =
(features.bits.support_masked_compound != 0);
/* not enable it now. */
/* TODO: not implemented */
self->features.enable_warped_motion = FALSE;
// (features.bits.support_warped_motion != 0);
self->features.enable_palette_mode = FALSE;
// (features.bits.support_palette_mode != 0);
/* (features.bits.support_warped_motion != 0); */
self->features.enable_dual_filter =
(features.bits.support_dual_filter != 0);
self->features.enable_jnt_comp = (features.bits.support_jnt_comp != 0);
self->features.enable_ref_frame_mvs =
(features.bits.support_ref_frame_mvs != 0);
/* not enable it now. */
/* TODO: not implemented */
self->features.enable_superres = FALSE;
/* (features.bits.support_superres != 0); */
/* TODO: not implemented */
self->features.enable_restoration = FALSE;
// (features.bits.support_restoration != 0);
/* not enable it now. */
self->features.allow_intrabc = FALSE;
self->features.enable_cdef = TRUE;
/* (features.bits.support_restoration != 0); */
self->features.cdef_channel_strength =
(features.bits.support_cdef_channel_strength != 0);
/* affected by the properties */
self->partition.use_128x128_superblock &=
(features.bits.support_128x128_superblock != 0);
self->features.enable_palette_mode &=
(features.bits.support_palette_mode != 0);
self->features.allow_intrabc &= (features.bits.support_allow_intrabc != 0);
/* intra-block copy is incompatible with the constrained directional
* enhancement filter */
self->features.enable_cdef = !self->features.allow_intrabc;
}
update_property_bool (base, &self->prop.use_128x128_superblock,
self->partition.use_128x128_superblock, PROP_128X128_SUPERBLOCK);
update_property_bool (base, &self->prop.allow_intrabc,
self->features.allow_intrabc, PROP_ALLOW_INTRABC);
update_property_bool (base, &self->prop.enable_palette_mode,
self->features.enable_palette_mode, PROP_PALETTE_MODE);
attrib.type = VAConfigAttribEncAV1Ext1;
attrib.value = 0;
status = vaGetConfigAttributes (gst_va_display_get_va_dpy (base->display),
@ -3027,7 +3039,11 @@ _av1_fill_sequence_header (GstVaAV1Enc * self,
.enable_order_hint = seq_param->seq_fields.bits.enable_order_hint,
.enable_jnt_comp = seq_param->seq_fields.bits.enable_jnt_comp,
.enable_ref_frame_mvs = seq_param->seq_fields.bits.enable_ref_frame_mvs,
.seq_choose_screen_content_tools = 0,
.seq_choose_screen_content_tools =
(self->features.allow_intrabc || self->features.enable_palette_mode),
.seq_force_screen_content_tools =
(self->features.allow_intrabc || self->features.enable_palette_mode) ?
GST_AV1_SELECT_SCREEN_CONTENT_TOOLS : 0,
.order_hint_bits_minus_1 = seq_param->order_hint_bits_minus_1,
.enable_superres = seq_param->seq_fields.bits.enable_superres,
.enable_cdef = seq_param->seq_fields.bits.enable_cdef,
@ -3155,6 +3171,16 @@ _av1_calculate_cdef_param (GstVaAV1Enc * self,
guint cdef_damping;
guint i;
if (!self->features.enable_cdef) {
pic_param->cdef_bits = 0;
pic_param->cdef_damping_minus_3 = 3;
for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
pic_param->cdef_y_strengths[i] = 0;
pic_param->cdef_uv_strengths[i] = 0;
}
return;
}
/* Adjust the CDEF parameter for CQP mode. In bitrate control mode, the
driver will update the CDEF value for each frame automatically. */
if (self->rc.rc_ctrl_mode == VA_RC_CQP) {
@ -3213,11 +3239,14 @@ _av1_fill_frame_param (GstVaAV1Enc * self, GstVaAV1EncFrame * va_frame,
g_assert (!(va_frame->type & FRAME_TYPE_REPEAT));
/* *INDENT-OFF* */
if (self->rc.rc_ctrl_mode == VA_RC_CQP) {
if (self->rc.rc_ctrl_mode == VA_RC_CQP && !self->features.allow_intrabc) {
loop_filter_level_y =
_av1_calculate_filter_level (self->rc.base_qindex, FALSE);
loop_filter_level_uv =
_av1_calculate_filter_level (self->rc.base_qindex, TRUE);
} else if (self->features.allow_intrabc) {
loop_filter_level_y = 0;
loop_filter_level_uv = 0;
} else {
/* In bitrate control mode, the driver will set the loop filter
level for each frame, we do not care here. */
@ -3366,6 +3395,10 @@ _av1_fill_frame_param (GstVaAV1Enc * self, GstVaAV1EncFrame * va_frame,
.skip_frames_reduced_size = 0,
};
/* *INDENT-ON* */
if (self->features.allow_intrabc) {
pic_param->ref_deltas[4] = 0;
pic_param->ref_deltas[5] = -1;
}
_av1_calculate_cdef_param (self, pic_param);
@ -3650,15 +3683,22 @@ _av1_fill_frame_header (GstVaAV1Enc * self,
};
/* *INDENT-ON* */
for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
frame_hdr->cdef_params.cdef_y_pri_strength[i] =
pic_param->cdef_y_strengths[i] / 4;
frame_hdr->cdef_params.cdef_y_sec_strength[i] =
pic_param->cdef_y_strengths[i] % 4;
frame_hdr->cdef_params.cdef_uv_pri_strength[i] =
pic_param->cdef_uv_strengths[i] / 4;
frame_hdr->cdef_params.cdef_uv_sec_strength[i] =
pic_param->cdef_uv_strengths[i] % 4;
if (frame_hdr->allow_intrabc == 0) {
for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
frame_hdr->cdef_params.cdef_y_pri_strength[i] =
pic_param->cdef_y_strengths[i] / 4;
frame_hdr->cdef_params.cdef_y_sec_strength[i] =
pic_param->cdef_y_strengths[i] % 4;
frame_hdr->cdef_params.cdef_uv_pri_strength[i] =
pic_param->cdef_uv_strengths[i] / 4;
frame_hdr->cdef_params.cdef_uv_sec_strength[i] =
pic_param->cdef_uv_strengths[i] % 4;
}
}
if (frame_hdr->allow_intrabc
|| pic_param->picture_flags.bits.palette_mode_enable) {
frame_hdr->allow_screen_content_tools = 1;
}
_av1_set_skip_mode_frame (self, va_frame, frame_hdr);
@ -4163,6 +4203,8 @@ gst_va_av1_enc_init (GTypeInstance * instance, gpointer g_class)
self->prop.num_tile_rows = 1;
self->prop.tile_groups = 1;
self->prop.mbbrc = 0;
self->prop.enable_palette_mode = FALSE;
self->prop.allow_intrabc = FALSE;
if (properties[PROP_RATE_CONTROL]) {
self->prop.rc_ctrl =
@ -4268,6 +4310,12 @@ gst_va_av1_enc_set_property (GObject * object, guint prop_id,
}
break;
}
case PROP_PALETTE_MODE:
self->prop.enable_palette_mode = g_value_get_boolean (value);
break;
case PROP_ALLOW_INTRABC:
self->prop.allow_intrabc = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -4342,6 +4390,12 @@ gst_va_av1_enc_get_property (GObject * object, guint prop_id,
case PROP_MBBRC:
g_value_set_enum (value, self->prop.mbbrc);
break;
case PROP_PALETTE_MODE:
g_value_set_boolean (value, self->prop.enable_palette_mode);
break;
case PROP_ALLOW_INTRABC:
g_value_set_boolean (value, self->prop.allow_intrabc);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -4498,6 +4552,28 @@ gst_va_av1_enc_class_init (gpointer g_klass, gpointer class_data)
g_param_spec_boolean ("superblock-128x128", "128x128 superblock",
"Enable the 128x128 superblock mode", FALSE, param_flags);
/**
* GstVaAV1Enc:palette-mode:
*
* Enable palette mode, an intra-frame optimization for blocks with a limited
* number of distinct colors, such a UI elements, for example.
*/
properties[PROP_PALETTE_MODE] =
g_param_spec_boolean ("palette-mode", "Enable palette mode",
"Enable palette mode, intra-frame optimization with limited colors",
FALSE, param_flags);
/**
* GstVaAV1Enc:allow_intrabc:
*
* Allow intra-block copy, a prediction mode for spatial redundancy within a
* frame. If it's enabled, it disables the usage of the constrained
* directional enhancement filter.
*/
properties[PROP_ALLOW_INTRABC] =
g_param_spec_boolean ("allow-intrabc", "Allow intra-block copy",
"Allow intra-block copy, a prediction mode for spatial redundancy within "
"a frame", FALSE, param_flags);
/**
* GstVaAV1Enc:min-qp:
*