/* * 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, };