Add a V4L2 Request API hwaccel for AV1. Support for AV1 is enabled when Linux kernel headers declare the control id V4L2_CID_STATELESS_AV1_FRAME, added in v6.5. Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
636 lines
24 KiB
C
636 lines
24 KiB
C
/*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* FFmpeg is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "libavutil/mem.h"
|
|
#include "hwaccel_internal.h"
|
|
#include "hwconfig.h"
|
|
#include "av1dec.h"
|
|
#include "internal.h"
|
|
#include "v4l2_request.h"
|
|
|
|
#define V4L2_AV1_CONTROLS_MAX 4
|
|
|
|
typedef struct V4L2RequestContextAV1 {
|
|
V4L2RequestContext base;
|
|
bool has_film_grain;
|
|
} V4L2RequestContextAV1;
|
|
|
|
typedef struct V4L2RequestControlsAV1 {
|
|
V4L2RequestPictureContext pic;
|
|
struct v4l2_ctrl_av1_sequence sequence;
|
|
struct v4l2_ctrl_av1_frame frame;
|
|
struct v4l2_ctrl_av1_film_grain film_grain;
|
|
struct v4l2_ctrl_av1_tile_group_entry tile_group_entry;
|
|
struct v4l2_ctrl_av1_tile_group_entry *tile_group_entries;
|
|
unsigned int allocated_tile_group_entries;
|
|
unsigned int num_tile_group_entries;
|
|
} V4L2RequestControlsAV1;
|
|
|
|
static int get_bit_depth_from_seq(const AV1RawSequenceHeader *seq)
|
|
{
|
|
if (seq->seq_profile == AV_PROFILE_AV1_PROFESSIONAL &&
|
|
seq->color_config.high_bitdepth)
|
|
return seq->color_config.twelve_bit ? 12 : 10;
|
|
else
|
|
return seq->color_config.high_bitdepth ? 10 : 8;
|
|
}
|
|
|
|
static void fill_sequence(struct v4l2_ctrl_av1_sequence *ctrl,
|
|
const AV1DecContext *s)
|
|
{
|
|
const AV1RawSequenceHeader *seq = s->raw_seq;
|
|
|
|
*ctrl = (struct v4l2_ctrl_av1_sequence) {
|
|
.seq_profile = seq->seq_profile,
|
|
.order_hint_bits = seq->enable_order_hint ?
|
|
seq->order_hint_bits_minus_1 + 1 : 0,
|
|
.bit_depth = get_bit_depth_from_seq(seq),
|
|
.max_frame_width_minus_1 = seq->max_frame_width_minus_1,
|
|
.max_frame_height_minus_1 = seq->max_frame_height_minus_1,
|
|
};
|
|
|
|
if (seq->still_picture)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE;
|
|
|
|
if (seq->use_128x128_superblock)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK;
|
|
|
|
if (seq->enable_filter_intra)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA;
|
|
|
|
if (seq->enable_intra_edge_filter)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER;
|
|
|
|
if (seq->enable_interintra_compound)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND;
|
|
|
|
if (seq->enable_masked_compound)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND;
|
|
|
|
if (seq->enable_warped_motion)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION;
|
|
|
|
if (seq->enable_dual_filter)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER;
|
|
|
|
if (seq->enable_order_hint)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT;
|
|
|
|
if (seq->enable_jnt_comp)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP;
|
|
|
|
if (seq->enable_ref_frame_mvs)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS;
|
|
|
|
if (seq->enable_superres)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES;
|
|
|
|
if (seq->enable_cdef)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF;
|
|
|
|
if (seq->enable_restoration)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION;
|
|
|
|
if (seq->color_config.mono_chrome)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME;
|
|
|
|
if (seq->color_config.color_range)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE;
|
|
|
|
if (seq->color_config.subsampling_x)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X;
|
|
|
|
if (seq->color_config.subsampling_y)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y;
|
|
|
|
if (seq->film_grain_params_present)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT;
|
|
|
|
if (seq->color_config.separate_uv_delta_q)
|
|
ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q;
|
|
}
|
|
|
|
static void fill_frame(struct v4l2_ctrl_av1_frame *ctrl, const AV1DecContext *s)
|
|
{
|
|
const AV1RawFrameHeader *frame_header = s->raw_frame_header;
|
|
const CodedBitstreamAV1Context *cbctx = s->cbc->priv_data;
|
|
uint8_t remap_lr_type[4] = {
|
|
V4L2_AV1_FRAME_RESTORE_NONE,
|
|
V4L2_AV1_FRAME_RESTORE_SWITCHABLE,
|
|
V4L2_AV1_FRAME_RESTORE_WIENER,
|
|
V4L2_AV1_FRAME_RESTORE_SGRPROJ,
|
|
};
|
|
int i, j;
|
|
|
|
*ctrl = (struct v4l2_ctrl_av1_frame) {
|
|
.tile_info = {
|
|
.context_update_tile_id = frame_header->context_update_tile_id,
|
|
.tile_cols = frame_header->tile_cols,
|
|
.tile_rows = frame_header->tile_rows,
|
|
.tile_size_bytes = frame_header->tile_cols_log2 > 0 ||
|
|
frame_header->tile_rows_log2 > 0 ?
|
|
frame_header->tile_size_bytes_minus1 + 1 : 0,
|
|
},
|
|
|
|
.quantization = {
|
|
.base_q_idx = frame_header->base_q_idx,
|
|
.delta_q_y_dc = frame_header->delta_q_y_dc,
|
|
.delta_q_u_dc = frame_header->delta_q_u_dc,
|
|
.delta_q_u_ac = frame_header->delta_q_u_ac,
|
|
.delta_q_v_dc = frame_header->delta_q_v_dc,
|
|
.delta_q_v_ac = frame_header->delta_q_v_ac,
|
|
.qm_y = frame_header->qm_y,
|
|
.qm_u = frame_header->qm_u,
|
|
.qm_v = frame_header->qm_v,
|
|
.delta_q_res = frame_header->delta_q_res,
|
|
},
|
|
|
|
.loop_filter = {
|
|
.level[0] = frame_header->loop_filter_level[0],
|
|
.level[1] = frame_header->loop_filter_level[1],
|
|
.level[2] = frame_header->loop_filter_level[2],
|
|
.level[3] = frame_header->loop_filter_level[3],
|
|
.sharpness = frame_header->loop_filter_sharpness,
|
|
.mode_deltas[0] = frame_header->loop_filter_mode_deltas[0],
|
|
.mode_deltas[1] = frame_header->loop_filter_mode_deltas[1],
|
|
.delta_lf_res = frame_header->delta_lf_res,
|
|
},
|
|
|
|
.cdef = {
|
|
.damping_minus_3 = frame_header->cdef_damping_minus_3,
|
|
.bits = frame_header->cdef_bits,
|
|
},
|
|
|
|
.loop_restoration = {
|
|
.lr_unit_shift = frame_header->lr_unit_shift,
|
|
.lr_uv_shift = frame_header->lr_uv_shift,
|
|
},
|
|
|
|
.superres_denom = frame_header->use_superres ?
|
|
frame_header->coded_denom + AV1_SUPERRES_DENOM_MIN :
|
|
AV1_SUPERRES_NUM,
|
|
.skip_mode_frame[0] = frame_header->skip_mode_present ?
|
|
s->cur_frame.skip_mode_frame_idx[0] : 0,
|
|
.skip_mode_frame[1] = frame_header->skip_mode_present ?
|
|
s->cur_frame.skip_mode_frame_idx[1] : 0,
|
|
.primary_ref_frame = frame_header->primary_ref_frame,
|
|
.frame_type = frame_header->frame_type,
|
|
.order_hint = frame_header->order_hint,
|
|
.upscaled_width = cbctx->upscaled_width,
|
|
.interpolation_filter = frame_header->interpolation_filter,
|
|
.tx_mode = frame_header->tx_mode,
|
|
.frame_width_minus_1 = cbctx->frame_width - 1,
|
|
.frame_height_minus_1 = cbctx->frame_height - 1,
|
|
.render_width_minus_1 = cbctx->render_width - 1,
|
|
.render_height_minus_1 = cbctx->render_height - 1,
|
|
.current_frame_id = frame_header->current_frame_id,
|
|
.refresh_frame_flags = frame_header->refresh_frame_flags,
|
|
};
|
|
|
|
if (frame_header->segmentation_enabled)
|
|
ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_ENABLED;
|
|
|
|
if (frame_header->segmentation_update_map)
|
|
ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP;
|
|
|
|
if (frame_header->segmentation_temporal_update)
|
|
ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE;
|
|
|
|
if (frame_header->segmentation_update_data)
|
|
ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA;
|
|
|
|
for (i = 0; i < AV1_MAX_SEGMENTS; i++) {
|
|
for (j = 0; j < AV1_SEG_LVL_MAX; j++) {
|
|
if (frame_header->feature_enabled[i][j]) {
|
|
ctrl->segmentation.feature_enabled[i] |= V4L2_AV1_SEGMENT_FEATURE_ENABLED(j);
|
|
ctrl->segmentation.last_active_seg_id = i;
|
|
if (j >= AV1_SEG_LVL_REF_FRAME)
|
|
ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP;
|
|
}
|
|
ctrl->segmentation.feature_data[i][j] = frame_header->feature_value[i][j];
|
|
}
|
|
}
|
|
|
|
if (frame_header->uniform_tile_spacing_flag)
|
|
ctrl->tile_info.flags |= V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING;
|
|
|
|
for (i = 0; i < frame_header->tile_cols; i++) {
|
|
ctrl->tile_info.mi_col_starts[i] = frame_header->tile_start_col_sb[i];
|
|
ctrl->tile_info.width_in_sbs_minus_1[i] = frame_header->width_in_sbs_minus_1[i];
|
|
}
|
|
ctrl->tile_info.mi_col_starts[i] = 2 * ((cbctx->frame_width + 7) >> 3);
|
|
|
|
for (i = 0; i < frame_header->tile_rows; i++) {
|
|
ctrl->tile_info.mi_row_starts[i] = frame_header->tile_start_row_sb[i];
|
|
ctrl->tile_info.height_in_sbs_minus_1[i] = frame_header->height_in_sbs_minus_1[i];
|
|
}
|
|
ctrl->tile_info.mi_row_starts[i] = 2 * ((cbctx->frame_height + 7) >> 3);
|
|
|
|
if (frame_header->diff_uv_delta)
|
|
ctrl->quantization.flags |= V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA;
|
|
|
|
if (frame_header->using_qmatrix)
|
|
ctrl->quantization.flags |= V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX;
|
|
|
|
if (frame_header->delta_q_present)
|
|
ctrl->quantization.flags |= V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT;
|
|
|
|
if (frame_header->loop_filter_delta_enabled)
|
|
ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED;
|
|
|
|
if (frame_header->loop_filter_delta_update)
|
|
ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE;
|
|
|
|
if (frame_header->delta_lf_present)
|
|
ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT;
|
|
|
|
if (frame_header->delta_lf_multi)
|
|
ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI;
|
|
|
|
for (i = 0; i < AV1_NUM_REF_FRAMES; i++) {
|
|
ctrl->loop_filter.ref_deltas[i] = frame_header->loop_filter_ref_deltas[i];
|
|
}
|
|
|
|
for (i = 0; i < cbctx->num_planes; i++) {
|
|
ctrl->loop_restoration.frame_restoration_type[i] =
|
|
remap_lr_type[frame_header->lr_type[i]];
|
|
if (frame_header->lr_type[i] != AV1_RESTORE_NONE) {
|
|
ctrl->loop_restoration.flags |= V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR;
|
|
if (i > 0)
|
|
ctrl->loop_restoration.flags |= V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR;
|
|
}
|
|
}
|
|
if (ctrl->loop_restoration.flags & V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR) {
|
|
ctrl->loop_restoration.loop_restoration_size[0] =
|
|
1 << (6 + frame_header->lr_unit_shift);
|
|
ctrl->loop_restoration.loop_restoration_size[1] =
|
|
1 << (6 + frame_header->lr_unit_shift - frame_header->lr_uv_shift);
|
|
ctrl->loop_restoration.loop_restoration_size[2] =
|
|
1 << (6 + frame_header->lr_unit_shift - frame_header->lr_uv_shift);
|
|
}
|
|
|
|
for (i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) {
|
|
ctrl->global_motion.type[i] = s->cur_frame.gm_type[i];
|
|
for (j = 0; j < 6; ++j) {
|
|
ctrl->global_motion.params[i][j] = s->cur_frame.gm_params[i][j];
|
|
if (s->cur_frame.gm_invalid[i])
|
|
ctrl->global_motion.invalid |= V4L2_AV1_GLOBAL_MOTION_IS_INVALID(i);
|
|
}
|
|
|
|
if (frame_header->is_global[i])
|
|
ctrl->global_motion.flags[i] |= V4L2_AV1_GLOBAL_MOTION_FLAG_IS_GLOBAL;
|
|
|
|
if (frame_header->is_rot_zoom[i])
|
|
ctrl->global_motion.flags[i] |= V4L2_AV1_GLOBAL_MOTION_FLAG_IS_ROT_ZOOM;
|
|
|
|
if (frame_header->is_translation[i])
|
|
ctrl->global_motion.flags[i] |= V4L2_AV1_GLOBAL_MOTION_FLAG_IS_TRANSLATION;
|
|
}
|
|
|
|
for (i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) {
|
|
AVFrame *ref = s->ref[i].f;
|
|
|
|
ctrl->order_hints[i] = s->cur_frame.order_hints[i];
|
|
if (ref)
|
|
ctrl->reference_frame_ts[i] = ff_v4l2_request_get_capture_timestamp(ref);
|
|
if (i < AV1_REFS_PER_FRAME)
|
|
ctrl->ref_frame_idx[i] = frame_header->ref_frame_idx[i];
|
|
}
|
|
|
|
for (i = 0; i < (1 << frame_header->cdef_bits); i++) {
|
|
ctrl->cdef.y_pri_strength[i] = frame_header->cdef_y_pri_strength[i];
|
|
ctrl->cdef.y_sec_strength[i] = frame_header->cdef_y_sec_strength[i];
|
|
ctrl->cdef.uv_pri_strength[i] = frame_header->cdef_uv_pri_strength[i];
|
|
ctrl->cdef.uv_sec_strength[i] = frame_header->cdef_uv_sec_strength[i];
|
|
}
|
|
|
|
if (frame_header->show_frame)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_SHOW_FRAME;
|
|
|
|
if (frame_header->showable_frame)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME;
|
|
|
|
if (frame_header->error_resilient_mode)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE;
|
|
|
|
if (frame_header->disable_cdf_update)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE;
|
|
|
|
if (frame_header->allow_screen_content_tools)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS;
|
|
|
|
if (s->cur_frame.force_integer_mv)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV;
|
|
|
|
if (frame_header->allow_intrabc)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC;
|
|
|
|
if (frame_header->use_superres)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_USE_SUPERRES;
|
|
|
|
if (frame_header->allow_high_precision_mv)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV;
|
|
|
|
if (frame_header->is_motion_mode_switchable)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE;
|
|
|
|
if (frame_header->use_ref_frame_mvs)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS;
|
|
|
|
if (frame_header->disable_frame_end_update_cdf)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF;
|
|
|
|
if (frame_header->allow_warped_motion)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION;
|
|
|
|
if (frame_header->reference_select)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT;
|
|
|
|
if (frame_header->reduced_tx_set)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET;
|
|
|
|
if (frame_header->skip_mode_present) {
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED; // FIXME
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT;
|
|
}
|
|
|
|
if (frame_header->frame_size_override_flag)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE;
|
|
|
|
if (frame_header->buffer_removal_time_present_flag) {
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT;
|
|
for (i = 0; i < AV1_MAX_OPERATING_POINTS; i++)
|
|
ctrl->buffer_removal_time[i] = frame_header->buffer_removal_time[i];
|
|
}
|
|
|
|
if (frame_header->frame_refs_short_signaling)
|
|
ctrl->flags |= V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING;
|
|
}
|
|
|
|
static void fill_film_grain(struct v4l2_ctrl_av1_film_grain *ctrl,
|
|
const AV1DecContext *s)
|
|
{
|
|
const AV1RawFilmGrainParams *film_grain = &s->cur_frame.film_grain;
|
|
int i;
|
|
|
|
*ctrl = (struct v4l2_ctrl_av1_film_grain) {
|
|
.cr_mult = film_grain->cr_mult,
|
|
.grain_seed = film_grain->grain_seed,
|
|
.film_grain_params_ref_idx = film_grain->film_grain_params_ref_idx,
|
|
.num_y_points = film_grain->num_y_points,
|
|
.num_cb_points = film_grain->num_cb_points,
|
|
.num_cr_points = film_grain->num_cr_points,
|
|
.grain_scaling_minus_8 = film_grain->grain_scaling_minus_8,
|
|
.ar_coeff_lag = film_grain->ar_coeff_lag,
|
|
.ar_coeff_shift_minus_6 = film_grain->ar_coeff_shift_minus_6,
|
|
.grain_scale_shift = film_grain->grain_scale_shift,
|
|
.cb_mult = film_grain->cb_mult,
|
|
.cb_luma_mult = film_grain->cb_luma_mult,
|
|
.cr_luma_mult = film_grain->cr_luma_mult,
|
|
.cb_offset = film_grain->cb_offset,
|
|
.cr_offset = film_grain->cr_offset,
|
|
};
|
|
|
|
if (film_grain->apply_grain)
|
|
ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN;
|
|
|
|
if (film_grain->update_grain)
|
|
ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN;
|
|
|
|
if (film_grain->chroma_scaling_from_luma)
|
|
ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA;
|
|
|
|
if (film_grain->overlap_flag)
|
|
ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP;
|
|
|
|
if (film_grain->clip_to_restricted_range)
|
|
ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE;
|
|
|
|
if (!film_grain->apply_grain)
|
|
return;
|
|
|
|
for (i = 0; i < film_grain->num_y_points; i++) {
|
|
ctrl->point_y_value[i] = film_grain->point_y_value[i];
|
|
ctrl->point_y_scaling[i] = film_grain->point_y_scaling[i];
|
|
}
|
|
|
|
for (i = 0; i < film_grain->num_cb_points; i++) {
|
|
ctrl->point_cb_value[i] = film_grain->point_cb_value[i];
|
|
ctrl->point_cb_scaling[i] = film_grain->point_cb_scaling[i];
|
|
}
|
|
|
|
for (i = 0; i < film_grain->num_cr_points; i++) {
|
|
ctrl->point_cr_value[i] = film_grain->point_cr_value[i];
|
|
ctrl->point_cr_scaling[i] = film_grain->point_cr_scaling[i];
|
|
}
|
|
|
|
for (i = 0; i < 24; i++) {
|
|
ctrl->ar_coeffs_y_plus_128[i] = film_grain->ar_coeffs_y_plus_128[i];
|
|
}
|
|
|
|
for (i = 0; i < 25; i++) {
|
|
ctrl->ar_coeffs_cb_plus_128[i] = film_grain->ar_coeffs_cb_plus_128[i];
|
|
ctrl->ar_coeffs_cr_plus_128[i] = film_grain->ar_coeffs_cr_plus_128[i];
|
|
}
|
|
}
|
|
|
|
static int v4l2_request_av1_start_frame(AVCodecContext *avctx,
|
|
av_unused const AVBufferRef *buf_ref,
|
|
av_unused const uint8_t *buffer,
|
|
av_unused uint32_t size)
|
|
{
|
|
const AV1DecContext *s = avctx->priv_data;
|
|
V4L2RequestContextAV1 *ctx = avctx->internal->hwaccel_priv_data;
|
|
V4L2RequestControlsAV1 *controls = s->cur_frame.hwaccel_picture_private;
|
|
int ret;
|
|
|
|
ret = ff_v4l2_request_start_frame(avctx, &controls->pic, s->cur_frame.f);
|
|
if (ret)
|
|
return ret;
|
|
|
|
fill_sequence(&controls->sequence, s);
|
|
fill_frame(&controls->frame, s);
|
|
|
|
if (ctx->has_film_grain)
|
|
fill_film_grain(&controls->film_grain, s);
|
|
|
|
controls->tile_group_entries = &controls->tile_group_entry;
|
|
controls->allocated_tile_group_entries = 0;
|
|
controls->num_tile_group_entries = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int v4l2_request_av1_decode_slice(AVCodecContext *avctx,
|
|
const uint8_t *buffer, uint32_t size)
|
|
{
|
|
const AV1DecContext *s = avctx->priv_data;
|
|
const AV1RawFrameHeader *fh = s->raw_frame_header;
|
|
V4L2RequestControlsAV1 *controls = s->cur_frame.hwaccel_picture_private;
|
|
|
|
controls->num_tile_group_entries = fh->tile_cols * fh->tile_rows;
|
|
if (controls->num_tile_group_entries > V4L2_AV1_MAX_TILE_COUNT)
|
|
return AVERROR(EINVAL);
|
|
|
|
if (controls->num_tile_group_entries > 1 &&
|
|
controls->num_tile_group_entries > controls->allocated_tile_group_entries) {
|
|
struct v4l2_ctrl_av1_tile_group_entry *tile_group_entries;
|
|
|
|
tile_group_entries = av_realloc_array(controls->allocated_tile_group_entries ?
|
|
controls->tile_group_entries : NULL,
|
|
controls->num_tile_group_entries,
|
|
sizeof(*controls->tile_group_entries));
|
|
if (!tile_group_entries)
|
|
return AVERROR(ENOMEM);
|
|
|
|
if (!controls->allocated_tile_group_entries)
|
|
memcpy(tile_group_entries, controls->tile_group_entries,
|
|
sizeof(*controls->tile_group_entries));
|
|
|
|
controls->tile_group_entries = tile_group_entries;
|
|
controls->allocated_tile_group_entries = controls->num_tile_group_entries;
|
|
}
|
|
|
|
for (int i = 0; i < controls->num_tile_group_entries; i++) {
|
|
controls->tile_group_entries[i] = (struct v4l2_ctrl_av1_tile_group_entry) {
|
|
.tile_offset = controls->pic.output->bytesused +
|
|
s->tile_group_info[i].tile_offset,
|
|
.tile_size = s->tile_group_info[i].tile_size,
|
|
.tile_row = s->tile_group_info[i].tile_row,
|
|
.tile_col = s->tile_group_info[i].tile_column,
|
|
};
|
|
}
|
|
|
|
return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size);
|
|
}
|
|
|
|
static int v4l2_request_av1_end_frame(AVCodecContext *avctx)
|
|
{
|
|
const AV1DecContext *s = avctx->priv_data;
|
|
V4L2RequestContextAV1 *ctx = avctx->internal->hwaccel_priv_data;
|
|
V4L2RequestControlsAV1 *controls = s->cur_frame.hwaccel_picture_private;
|
|
int count = 0;
|
|
|
|
struct v4l2_ext_control control[V4L2_AV1_CONTROLS_MAX] = {};
|
|
|
|
control[count++] = (struct v4l2_ext_control) {
|
|
.id = V4L2_CID_STATELESS_AV1_SEQUENCE,
|
|
.ptr = &controls->sequence,
|
|
.size = sizeof(controls->sequence),
|
|
};
|
|
|
|
control[count++] = (struct v4l2_ext_control) {
|
|
.id = V4L2_CID_STATELESS_AV1_FRAME,
|
|
.ptr = &controls->frame,
|
|
.size = sizeof(controls->frame),
|
|
};
|
|
|
|
control[count++] = (struct v4l2_ext_control) {
|
|
.id = V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY,
|
|
.ptr = controls->tile_group_entries,
|
|
.size = sizeof(*controls->tile_group_entries) *
|
|
FFMAX(controls->num_tile_group_entries, 1),
|
|
};
|
|
|
|
if (ctx->has_film_grain) {
|
|
control[count++] = (struct v4l2_ext_control) {
|
|
.id = V4L2_CID_STATELESS_AV1_FILM_GRAIN,
|
|
.ptr = &controls->film_grain,
|
|
.size = sizeof(controls->film_grain),
|
|
};
|
|
}
|
|
|
|
return ff_v4l2_request_decode_frame(avctx, &controls->pic, control, count);
|
|
}
|
|
|
|
static void v4l2_request_av1_free_frame_priv(AVRefStructOpaque hwctx, void *data)
|
|
{
|
|
V4L2RequestControlsAV1 *controls = data;
|
|
|
|
if (controls->allocated_tile_group_entries)
|
|
av_freep(&controls->tile_group_entries);
|
|
}
|
|
|
|
static int v4l2_request_av1_post_frames_ctx(AVCodecContext *avctx)
|
|
{
|
|
V4L2RequestContextAV1 *ctx = avctx->internal->hwaccel_priv_data;
|
|
|
|
struct v4l2_query_ext_ctrl film_grain = {
|
|
.id = V4L2_CID_STATELESS_AV1_FILM_GRAIN,
|
|
};
|
|
|
|
// TODO: check V4L2_CID_MPEG_VIDEO_AV1_PROFILE
|
|
// TODO: check V4L2_CID_MPEG_VIDEO_AV1_LEVEL
|
|
|
|
if (!ff_v4l2_request_query_control(avctx, &film_grain))
|
|
ctx->has_film_grain = true;
|
|
else
|
|
ctx->has_film_grain = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int v4l2_request_av1_init(AVCodecContext *avctx)
|
|
{
|
|
const AV1DecContext *s = avctx->priv_data;
|
|
struct v4l2_ctrl_av1_sequence sequence;
|
|
|
|
struct v4l2_ext_control control[] = {
|
|
{
|
|
.id = V4L2_CID_STATELESS_AV1_SEQUENCE,
|
|
.ptr = &sequence,
|
|
.size = sizeof(sequence),
|
|
},
|
|
};
|
|
|
|
fill_sequence(&sequence, s);
|
|
|
|
return ff_v4l2_request_init(avctx, control, FF_ARRAY_ELEMS(control),
|
|
v4l2_request_av1_post_frames_ctx);
|
|
}
|
|
|
|
static int v4l2_request_av1_frame_params(AVCodecContext *avctx,
|
|
AVBufferRef *hw_frames_ctx)
|
|
{
|
|
const AV1DecContext *s = avctx->priv_data;
|
|
const AV1RawSequenceHeader *seq = s ? s->raw_seq : NULL;
|
|
uint8_t bit_depth = seq ? get_bit_depth_from_seq(seq) : 0;
|
|
|
|
return ff_v4l2_request_frame_params(avctx, hw_frames_ctx,
|
|
V4L2_PIX_FMT_AV1_FRAME, bit_depth);
|
|
}
|
|
|
|
const FFHWAccel ff_av1_v4l2request_hwaccel = {
|
|
.p.name = "av1_v4l2request",
|
|
.p.type = AVMEDIA_TYPE_VIDEO,
|
|
.p.id = AV_CODEC_ID_AV1,
|
|
.p.pix_fmt = AV_PIX_FMT_DRM_PRIME,
|
|
.start_frame = v4l2_request_av1_start_frame,
|
|
.decode_slice = v4l2_request_av1_decode_slice,
|
|
.end_frame = v4l2_request_av1_end_frame,
|
|
.flush = ff_v4l2_request_flush,
|
|
.free_frame_priv = v4l2_request_av1_free_frame_priv,
|
|
.frame_priv_data_size = sizeof(V4L2RequestControlsAV1),
|
|
.init = v4l2_request_av1_init,
|
|
.uninit = ff_v4l2_request_uninit,
|
|
.priv_data_size = sizeof(V4L2RequestContextAV1),
|
|
.frame_params = v4l2_request_av1_frame_params,
|
|
.caps_internal = HWACCEL_CAP_ASYNC_SAFE,
|
|
};
|