From c45fea96e3b90c909d5af291e0583a63272cdabe Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Mon, 4 May 2026 09:40:14 +0000 Subject: [PATCH] fourier-local: stateless control modernization + HEVC strip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compound patch carrying the fork's pre-Step-1 substrate, originally authored by Jernej Škrabec / fourier on top of bootlin's a3c2476: - src/h264.c + src/picture.c: V4L2_CID_MPEG_VIDEO_H264_* renamed to V4L2_CID_STATELESS_H264_*, struct shapes tracked to mainline (V4L2_CID_STATELESS_H264_DECODE_MODE/_START_CODE added to the passthrough shim). - include/hevc-ctrls.h: redirect shim to (kernel-side HEVC controls now live in the canonical UAPI header). - src/meson.build: src/h265.c / src/h265.h commented out — HEVC build path is excluded from this fork (RK3568 hantro G1/G2 has no HEVC, and the kernel-side HEVC controls have a separate rework in flight upstream). - src/tiled_yuv.S: aarch64 stub for tiled_to_planar (assembly source was sunxi-cedrus armv7-only; aarch64 needs a stub to keep the build linking). - include/h264-ctrls.h: removed (dead post-fourier — no source includes it; the passthrough shim's CID aliases live in the kernel header now). Functionally equivalent to the prior fork master commits: c1f5108 V4L2_PIX_FMT_H264_SLICE rename 4ccbfe9 Strip HEVC build path da9f2a5 include/h264-ctrls.h passthrough + CID aliases fc4bb10 src/h264.c track upstream UAPI shape 13e9b64 src/h264.c drop num_slices field 4d14ffb src/tiled_yuv.S aarch64 stub 1b02c9b src/h264.c include utils.h Folded into one commit during 2026-05-04 Step 1 reconciliation (see ../phase0_evidence/2026-05-04/findings.md). Per-patch history of the early fork commits preserved on the pre-step1 branch. Co-Authored-By: Claude Opus 4.7 (1M context) --- include/h264-ctrls.h | 197 ------------------------------------------- include/hevc-ctrls.h | 190 ++--------------------------------------- src/config.c | 23 +++-- src/config.h | 1 + src/context.c | 33 -------- src/context.h | 1 + src/h264.c | 181 ++++++++++++++++++++++++++++++--------- src/h264.h | 3 + src/image.c | 4 + src/meson.build | 4 +- src/picture.c | 21 +++-- src/surface.c | 28 +++++- src/surface.h | 2 +- src/tiled_yuv.S | 2 +- src/v4l2.c | 60 ++++++++++--- src/v4l2.h | 6 ++ src/video.c | 3 + 17 files changed, 274 insertions(+), 485 deletions(-) delete mode 100644 include/h264-ctrls.h diff --git a/include/h264-ctrls.h b/include/h264-ctrls.h deleted file mode 100644 index e1404d7..0000000 --- a/include/h264-ctrls.h +++ /dev/null @@ -1,197 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * These are the H.264 state controls for use with stateless H.264 - * codec drivers. - * - * It turns out that these structs are not stable yet and will undergo - * more changes. So keep them private until they are stable and ready to - * become part of the official public API. - */ - -#ifndef _H264_CTRLS_H_ -#define _H264_CTRLS_H_ - -#include - -/* Our pixel format isn't stable at the moment */ -#define V4L2_PIX_FMT_H264_SLICE_RAW v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ - -/* - * This is put insanely high to avoid conflicting with controls that - * would be added during the phase where those controls are not - * stable. It should be fixed eventually. - */ -#define V4L2_CID_MPEG_VIDEO_H264_SPS (V4L2_CID_MPEG_BASE+1000) -#define V4L2_CID_MPEG_VIDEO_H264_PPS (V4L2_CID_MPEG_BASE+1001) -#define V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (V4L2_CID_MPEG_BASE+1002) -#define V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (V4L2_CID_MPEG_BASE+1003) -#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_MPEG_BASE+1004) - -/* enum v4l2_ctrl_type type values */ -#define V4L2_CTRL_TYPE_H264_SPS 0x0110 -#define V4L2_CTRL_TYPE_H264_PPS 0x0111 -#define V4L2_CTRL_TYPE_H264_SCALING_MATRIX 0x0112 -#define V4L2_CTRL_TYPE_H264_SLICE_PARAMS 0x0113 -#define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114 - -#define V4L2_H264_SPS_CONSTRAINT_SET0_FLAG 0x01 -#define V4L2_H264_SPS_CONSTRAINT_SET1_FLAG 0x02 -#define V4L2_H264_SPS_CONSTRAINT_SET2_FLAG 0x04 -#define V4L2_H264_SPS_CONSTRAINT_SET3_FLAG 0x08 -#define V4L2_H264_SPS_CONSTRAINT_SET4_FLAG 0x10 -#define V4L2_H264_SPS_CONSTRAINT_SET5_FLAG 0x20 - -#define V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE 0x01 -#define V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS 0x02 -#define V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO 0x04 -#define V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED 0x08 -#define V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY 0x10 -#define V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD 0x20 -#define V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE 0x40 - -struct v4l2_ctrl_h264_sps { - __u8 profile_idc; - __u8 constraint_set_flags; - __u8 level_idc; - __u8 seq_parameter_set_id; - __u8 chroma_format_idc; - __u8 bit_depth_luma_minus8; - __u8 bit_depth_chroma_minus8; - __u8 log2_max_frame_num_minus4; - __u8 pic_order_cnt_type; - __u8 log2_max_pic_order_cnt_lsb_minus4; - __u8 max_num_ref_frames; - __u8 num_ref_frames_in_pic_order_cnt_cycle; - __s32 offset_for_ref_frame[255]; - __s32 offset_for_non_ref_pic; - __s32 offset_for_top_to_bottom_field; - __u16 pic_width_in_mbs_minus1; - __u16 pic_height_in_map_units_minus1; - __u32 flags; -}; - -#define V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE 0x0001 -#define V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT 0x0002 -#define V4L2_H264_PPS_FLAG_WEIGHTED_PRED 0x0004 -#define V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT 0x0008 -#define V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED 0x0010 -#define V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT 0x0020 -#define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040 -#define V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT 0x0080 - -struct v4l2_ctrl_h264_pps { - __u8 pic_parameter_set_id; - __u8 seq_parameter_set_id; - __u8 num_slice_groups_minus1; - __u8 num_ref_idx_l0_default_active_minus1; - __u8 num_ref_idx_l1_default_active_minus1; - __u8 weighted_bipred_idc; - __s8 pic_init_qp_minus26; - __s8 pic_init_qs_minus26; - __s8 chroma_qp_index_offset; - __s8 second_chroma_qp_index_offset; - __u16 flags; -}; - -struct v4l2_ctrl_h264_scaling_matrix { - __u8 scaling_list_4x4[6][16]; - __u8 scaling_list_8x8[6][64]; -}; - -struct v4l2_h264_weight_factors { - __s16 luma_weight[32]; - __s16 luma_offset[32]; - __s16 chroma_weight[32][2]; - __s16 chroma_offset[32][2]; -}; - -struct v4l2_h264_pred_weight_table { - __u16 luma_log2_weight_denom; - __u16 chroma_log2_weight_denom; - struct v4l2_h264_weight_factors weight_factors[2]; -}; - -#define V4L2_H264_SLICE_TYPE_P 0 -#define V4L2_H264_SLICE_TYPE_B 1 -#define V4L2_H264_SLICE_TYPE_I 2 -#define V4L2_H264_SLICE_TYPE_SP 3 -#define V4L2_H264_SLICE_TYPE_SI 4 - -#define V4L2_H264_SLICE_FLAG_FIELD_PIC 0x01 -#define V4L2_H264_SLICE_FLAG_BOTTOM_FIELD 0x02 -#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04 -#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08 - -struct v4l2_ctrl_h264_slice_params { - /* Size in bytes, including header */ - __u32 size; - /* Offset in bits to slice_data() from the beginning of this slice. */ - __u32 header_bit_size; - - __u16 first_mb_in_slice; - __u8 slice_type; - __u8 pic_parameter_set_id; - __u8 colour_plane_id; - __u8 redundant_pic_cnt; - __u16 frame_num; - __u16 idr_pic_id; - __u16 pic_order_cnt_lsb; - __s32 delta_pic_order_cnt_bottom; - __s32 delta_pic_order_cnt0; - __s32 delta_pic_order_cnt1; - - struct v4l2_h264_pred_weight_table pred_weight_table; - /* Size in bits of dec_ref_pic_marking() syntax element. */ - __u32 dec_ref_pic_marking_bit_size; - /* Size in bits of pic order count syntax. */ - __u32 pic_order_cnt_bit_size; - - __u8 cabac_init_idc; - __s8 slice_qp_delta; - __s8 slice_qs_delta; - __u8 disable_deblocking_filter_idc; - __s8 slice_alpha_c0_offset_div2; - __s8 slice_beta_offset_div2; - __u8 num_ref_idx_l0_active_minus1; - __u8 num_ref_idx_l1_active_minus1; - __u32 slice_group_change_cycle; - - /* - * Entries on each list are indices into - * v4l2_ctrl_h264_decode_params.dpb[]. - */ - __u8 ref_pic_list0[32]; - __u8 ref_pic_list1[32]; - - __u32 flags; -}; - -#define V4L2_H264_DPB_ENTRY_FLAG_VALID 0x01 -#define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02 -#define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 - -struct v4l2_h264_dpb_entry { - __u64 reference_ts; - __u16 frame_num; - __u16 pic_num; - /* Note that field is indicated by v4l2_buffer.field */ - __s32 top_field_order_cnt; - __s32 bottom_field_order_cnt; - __u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ -}; - -#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 - -struct v4l2_ctrl_h264_decode_params { - struct v4l2_h264_dpb_entry dpb[16]; - __u16 num_slices; - __u16 nal_ref_idc; - __u8 ref_pic_list_p0[32]; - __u8 ref_pic_list_b0[32]; - __u8 ref_pic_list_b1[32]; - __s32 top_field_order_cnt; - __s32 bottom_field_order_cnt; - __u32 flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ -}; - -#endif diff --git a/include/hevc-ctrls.h b/include/hevc-ctrls.h index 2de83d9..d802692 100644 --- a/include/hevc-ctrls.h +++ b/include/hevc-ctrls.h @@ -1,185 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * These are the HEVC state controls for use with stateless HEVC - * codec drivers. - * - * It turns out that these structs are not stable yet and will undergo - * more changes. So keep them private until they are stable and ready to - * become part of the official public API. - */ - -#ifndef _HEVC_CTRLS_H_ -#define _HEVC_CTRLS_H_ - -/* The pixel format isn't stable at the moment and will likely be renamed. */ -#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */ - -#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008) -#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009) -#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010) - -/* enum v4l2_ctrl_type type values */ -#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 -#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 -#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 - -#define V4L2_HEVC_SLICE_TYPE_B 0 -#define V4L2_HEVC_SLICE_TYPE_P 1 -#define V4L2_HEVC_SLICE_TYPE_I 2 - -/* The controls are not stable at the moment and will likely be reworked. */ -struct v4l2_ctrl_hevc_sps { - /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */ - __u8 chroma_format_idc; - __u8 separate_colour_plane_flag; - __u16 pic_width_in_luma_samples; - __u16 pic_height_in_luma_samples; - __u8 bit_depth_luma_minus8; - __u8 bit_depth_chroma_minus8; - __u8 log2_max_pic_order_cnt_lsb_minus4; - __u8 sps_max_dec_pic_buffering_minus1; - __u8 sps_max_num_reorder_pics; - __u8 sps_max_latency_increase_plus1; - __u8 log2_min_luma_coding_block_size_minus3; - __u8 log2_diff_max_min_luma_coding_block_size; - __u8 log2_min_luma_transform_block_size_minus2; - __u8 log2_diff_max_min_luma_transform_block_size; - __u8 max_transform_hierarchy_depth_inter; - __u8 max_transform_hierarchy_depth_intra; - __u8 scaling_list_enabled_flag; - __u8 amp_enabled_flag; - __u8 sample_adaptive_offset_enabled_flag; - __u8 pcm_enabled_flag; - __u8 pcm_sample_bit_depth_luma_minus1; - __u8 pcm_sample_bit_depth_chroma_minus1; - __u8 log2_min_pcm_luma_coding_block_size_minus3; - __u8 log2_diff_max_min_pcm_luma_coding_block_size; - __u8 pcm_loop_filter_disabled_flag; - __u8 num_short_term_ref_pic_sets; - __u8 long_term_ref_pics_present_flag; - __u8 num_long_term_ref_pics_sps; - __u8 sps_temporal_mvp_enabled_flag; - __u8 strong_intra_smoothing_enabled_flag; -}; - -struct v4l2_ctrl_hevc_pps { - /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ - __u8 dependent_slice_segment_flag; - __u8 output_flag_present_flag; - __u8 num_extra_slice_header_bits; - __u8 sign_data_hiding_enabled_flag; - __u8 cabac_init_present_flag; - __s8 init_qp_minus26; - __u8 constrained_intra_pred_flag; - __u8 transform_skip_enabled_flag; - __u8 cu_qp_delta_enabled_flag; - __u8 diff_cu_qp_delta_depth; - __s8 pps_cb_qp_offset; - __s8 pps_cr_qp_offset; - __u8 pps_slice_chroma_qp_offsets_present_flag; - __u8 weighted_pred_flag; - __u8 weighted_bipred_flag; - __u8 transquant_bypass_enabled_flag; - __u8 tiles_enabled_flag; - __u8 entropy_coding_sync_enabled_flag; - __u8 num_tile_columns_minus1; - __u8 num_tile_rows_minus1; - __u8 column_width_minus1[20]; - __u8 row_height_minus1[22]; - __u8 loop_filter_across_tiles_enabled_flag; - __u8 pps_loop_filter_across_slices_enabled_flag; - __u8 deblocking_filter_override_enabled_flag; - __u8 pps_disable_deblocking_filter_flag; - __s8 pps_beta_offset_div2; - __s8 pps_tc_offset_div2; - __u8 lists_modification_present_flag; - __u8 log2_parallel_merge_level_minus2; - __u8 slice_segment_header_extension_present_flag; - __u8 padding; -}; - -#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE 0x01 -#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER 0x02 -#define V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR 0x03 - -#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX 16 - -struct v4l2_hevc_dpb_entry { - __u64 timestamp; - __u8 rps; - __u8 field_pic; - __u16 pic_order_cnt[2]; - __u8 padding[2]; -}; - -struct v4l2_hevc_pred_weight_table { - __u8 luma_log2_weight_denom; - __s8 delta_chroma_log2_weight_denom; - - __s8 delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __s8 luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __s8 delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; - __s8 chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; - - __s8 delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __s8 luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __s8 delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; - __s8 chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; - - __u8 padding[2]; -}; - -struct v4l2_ctrl_hevc_slice_params { - __u32 bit_size; - __u32 data_bit_offset; - - /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ - __u8 nal_unit_type; - __u8 nuh_temporal_id_plus1; - - /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ - __u8 slice_type; - __u8 colour_plane_id; - __u16 slice_pic_order_cnt; - __u8 slice_sao_luma_flag; - __u8 slice_sao_chroma_flag; - __u8 slice_temporal_mvp_enabled_flag; - __u8 num_ref_idx_l0_active_minus1; - __u8 num_ref_idx_l1_active_minus1; - __u8 mvd_l1_zero_flag; - __u8 cabac_init_flag; - __u8 collocated_from_l0_flag; - __u8 collocated_ref_idx; - __u8 five_minus_max_num_merge_cand; - __u8 use_integer_mv_flag; - __s8 slice_qp_delta; - __s8 slice_cb_qp_offset; - __s8 slice_cr_qp_offset; - __s8 slice_act_y_qp_offset; - __s8 slice_act_cb_qp_offset; - __s8 slice_act_cr_qp_offset; - __u8 slice_deblocking_filter_disabled_flag; - __s8 slice_beta_offset_div2; - __s8 slice_tc_offset_div2; - __u8 slice_loop_filter_across_slices_enabled_flag; - - /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */ - __u8 pic_struct; - - /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ - struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __u8 num_active_dpb_entries; - __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - - __u8 num_rps_poc_st_curr_before; - __u8 num_rps_poc_st_curr_after; - __u8 num_rps_poc_lt_curr; - - /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */ - struct v4l2_hevc_pred_weight_table pred_weight_table; - - __u8 padding[2]; -}; - +/* Fourier-local override: HEVC controls are upstream since linux-media + * 6.6+, so defer to the kernel's linux/v4l2-controls.h instead of + * duplicating the struct definitions (duplication causes redefinition + * errors on newer linux-api-headers). */ +#ifndef _LIBVA_V4L2_REQUEST_HEVC_CTRLS_H +#define _LIBVA_V4L2_REQUEST_HEVC_CTRLS_H +#include #endif diff --git a/src/config.c b/src/config.c index e396268..04a9c3a 100644 --- a/src/config.c +++ b/src/config.c @@ -35,7 +35,6 @@ #include #include -#include #include #include "utils.h" @@ -54,18 +53,17 @@ VAStatus RequestCreateConfig(VADriverContextP context, VAProfile profile, int i, index; switch (profile) { - case VAProfileMPEG2Simple: - case VAProfileMPEG2Main: + case VAProfileH264Main: case VAProfileH264High: case VAProfileH264ConstrainedBaseline: case VAProfileH264MultiviewHigh: case VAProfileH264StereoHigh: - case VAProfileHEVCMain: - if (entrypoint != VAEntrypointVLD) - return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT; + // FIXME break; - + case VAProfileMPEG2Simple: + case VAProfileMPEG2Main: + case VAProfileHEVCMain: default: return VA_STATUS_ERROR_UNSUPPORTED_PROFILE; } @@ -120,6 +118,9 @@ VAStatus RequestQueryConfigProfiles(VADriverContextP context, found = v4l2_find_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_PIX_FMT_MPEG2_SLICE) || + v4l2_find_format(driver_data->video_fd, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_PIX_FMT_MPEG2_SLICE); if (found && index < (V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES - 2)) { profiles[index++] = VAProfileMPEG2Simple; @@ -128,7 +129,10 @@ VAStatus RequestQueryConfigProfiles(VADriverContextP context, found = v4l2_find_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, - V4L2_PIX_FMT_H264_SLICE_RAW); + V4L2_PIX_FMT_H264_SLICE) || + v4l2_find_format(driver_data->video_fd, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + V4L2_PIX_FMT_H264_SLICE); if (found && index < (V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES - 5)) { profiles[index++] = VAProfileH264Main; profiles[index++] = VAProfileH264High; @@ -139,6 +143,9 @@ VAStatus RequestQueryConfigProfiles(VADriverContextP context, found = v4l2_find_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_PIX_FMT_HEVC_SLICE) || + v4l2_find_format(driver_data->video_fd, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_PIX_FMT_HEVC_SLICE); if (found && index < (V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES - 1)) profiles[index++] = VAProfileHEVCMain; diff --git a/src/config.h b/src/config.h index b7b12e7..1377e49 100644 --- a/src/config.h +++ b/src/config.h @@ -43,6 +43,7 @@ struct object_config { VAEntrypoint entrypoint; VAConfigAttrib attributes[V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES]; int attributes_count; + unsigned int pixelformat; }; VAStatus RequestCreateConfig(VADriverContextP context, VAProfile profile, diff --git a/src/context.c b/src/context.c index 04ba9a6..d07cea6 100644 --- a/src/context.c +++ b/src/context.c @@ -40,7 +40,6 @@ #include #include -#include #include #include "utils.h" @@ -65,7 +64,6 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id, VAContextID id; VAStatus status; unsigned int output_type, capture_type; - unsigned int pixelformat; unsigned int index_base; unsigned int index; unsigned int i; @@ -92,37 +90,6 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id, } memset(&context_object->dpb, 0, sizeof(context_object->dpb)); - switch (config_object->profile) { - - case VAProfileMPEG2Simple: - case VAProfileMPEG2Main: - pixelformat = V4L2_PIX_FMT_MPEG2_SLICE; - break; - - case VAProfileH264Main: - case VAProfileH264High: - case VAProfileH264ConstrainedBaseline: - case VAProfileH264MultiviewHigh: - case VAProfileH264StereoHigh: - pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW; - break; - - case VAProfileHEVCMain: - pixelformat = V4L2_PIX_FMT_HEVC_SLICE; - break; - - default: - status = VA_STATUS_ERROR_UNSUPPORTED_PROFILE; - goto error; - } - - rc = v4l2_set_format(driver_data->video_fd, output_type, pixelformat, - picture_width, picture_height); - if (rc < 0) { - status = VA_STATUS_ERROR_OPERATION_FAILED; - goto error; - } - rc = v4l2_create_buffers(driver_data->video_fd, output_type, surfaces_count, &index_base); if (rc < 0) { diff --git a/src/context.h b/src/context.h index cd0910a..8f4f70f 100644 --- a/src/context.h +++ b/src/context.h @@ -50,6 +50,7 @@ struct object_context { /* H264 only */ struct h264_dpb dpb; + bool h264_start_code; }; VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id, diff --git a/src/h264.c b/src/h264.c index 25bc8cb..fb6c13a 100644 --- a/src/h264.c +++ b/src/h264.c @@ -33,9 +33,9 @@ #include #include -#include #include "request.h" +#include "utils.h" #include "surface.h" #include "v4l2.h" @@ -95,7 +95,8 @@ static struct h264_dpb_entry *dpb_find_entry(struct object_context *context) } static struct h264_dpb_entry *dpb_lookup(struct object_context *context, - VAPictureH264 *pic, unsigned int *idx) + VAPictureH264 *pic, unsigned int *idx, + unsigned char *fields) { unsigned int i; @@ -109,6 +110,16 @@ static struct h264_dpb_entry *dpb_lookup(struct object_context *context, if (idx) *idx = i; + if (fields) { + //if (entry->pic.TopFieldOrderCnt < entry->pic.BottomFieldOrderCnt) { + // *fields = V4L2_H264_TOP_FIELD_REF; + //} else if (entry->pic.TopFieldOrderCnt > entry->pic.BottomFieldOrderCnt) { + // *fields = V4L2_H264_BOTTOM_FIELD_REF; + //} else { + *fields = V4L2_H264_FRAME_REF; + //} + } + return entry; } } @@ -130,7 +141,7 @@ static void dpb_insert(struct object_context *context, VAPictureH264 *pic, if (is_picture_null(pic)) return; - if (dpb_lookup(context, pic, NULL)) + if (dpb_lookup(context, pic, NULL, NULL)) return; if (!entry) @@ -165,7 +176,7 @@ static void dpb_update(struct object_context *context, if (is_picture_null(pic)) continue; - entry = dpb_lookup(context, pic, NULL); + entry = dpb_lookup(context, pic, NULL, NULL); if (entry) { entry->age = context->dpb.age; entry->used = true; @@ -197,6 +208,7 @@ static void h264_fill_dpb(struct request_data *data, } dpb->frame_num = entry->pic.frame_idx; + dpb->pic_num = entry->pic.picture_id; dpb->top_field_order_cnt = entry->pic.TopFieldOrderCnt; dpb->bottom_field_order_cnt = entry->pic.BottomFieldOrderCnt; @@ -218,9 +230,23 @@ static void h264_va_picture_to_v4l2(struct request_data *driver_data, struct v4l2_ctrl_h264_pps *pps, struct v4l2_ctrl_h264_sps *sps) { + unsigned char *b; + unsigned char nal_ref_idc; + unsigned char nal_unit_type; + + /* Extract missing nal_ref_idc and nal_unit_type */ + b = surface->source_data; + if (context->h264_start_code) + b += 3; + nal_ref_idc = (b[0] >> 5) & 0x3; + nal_unit_type = b[0] & 0x1f; + h264_fill_dpb(driver_data, context, decode); - decode->num_slices = surface->slices_count; + //decode->num_slices = surface->slices_count; + decode->nal_ref_idc = nal_ref_idc; + if (nal_unit_type == 5) + decode->flags = V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC; decode->top_field_order_cnt = VAPicture->CurrPic.TopFieldOrderCnt; decode->bottom_field_order_cnt = VAPicture->CurrPic.BottomFieldOrderCnt; @@ -255,6 +281,7 @@ static void h264_va_picture_to_v4l2(struct request_data *driver_data, if (VAPicture->pic_fields.bits.redundant_pic_cnt_present_flag) pps->flags |= V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT; + sps->max_num_ref_frames = VAPicture->num_ref_frames; sps->chroma_format_idc = VAPicture->seq_fields.bits.chroma_format_idc; sps->bit_depth_luma_minus8 = VAPicture->bit_depth_luma_minus8; sps->bit_depth_chroma_minus8 = VAPicture->bit_depth_chroma_minus8; @@ -327,10 +354,12 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, struct object_context *context, VASliceParameterBufferH264 *VASlice, VAPictureParameterBufferH264 *VAPicture, - struct v4l2_ctrl_h264_slice_params *slice) + struct v4l2_ctrl_h264_slice_params *slice, + struct v4l2_ctrl_h264_pred_weights *weights) { - slice->size = VASlice->slice_data_size; slice->header_bit_size = VASlice->slice_data_bit_offset; + //if (context->h264_start_code) + // slice->header_bit_size += 3 * 8; slice->first_mb_in_slice = VASlice->first_mb_in_slice; slice->slice_type = VASlice->slice_type; slice->cabac_init_idc = VASlice->cabac_init_idc; @@ -351,12 +380,14 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, VAPictureH264 *pic = &VASlice->RefPicList0[i]; struct h264_dpb_entry *entry; unsigned int idx; + unsigned char fields; - entry = dpb_lookup(context, pic, &idx); + entry = dpb_lookup(context, pic, &idx, &fields); if (!entry) continue; - slice->ref_pic_list0[i] = idx; + slice->ref_pic_list0[i].index = idx; + slice->ref_pic_list0[i].fields = fields; } } @@ -370,26 +401,28 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, VAPictureH264 *pic = &VASlice->RefPicList1[i]; struct h264_dpb_entry *entry; unsigned int idx; + unsigned char fields; - entry = dpb_lookup(context, pic, &idx); + entry = dpb_lookup(context, pic, &idx, &fields); if (!entry) continue; - slice->ref_pic_list1[i] = idx; + slice->ref_pic_list1[i].index = idx; + slice->ref_pic_list0[i].fields = fields; } } if (VASlice->direct_spatial_mv_pred_flag) slice->flags |= V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED; - slice->pred_weight_table.chroma_log2_weight_denom = + weights->chroma_log2_weight_denom = VASlice->chroma_log2_weight_denom; - slice->pred_weight_table.luma_log2_weight_denom = + weights->luma_log2_weight_denom = VASlice->luma_log2_weight_denom; if (((VASlice->slice_type % 5) == H264_SLICE_P) || ((VASlice->slice_type % 5) == H264_SLICE_B)) - h264_copy_pred_table(&slice->pred_weight_table.weight_factors[0], + h264_copy_pred_table(&weights->weight_factors[0], slice->num_ref_idx_l0_active_minus1 + 1, VASlice->luma_weight_l0, VASlice->luma_offset_l0, @@ -397,7 +430,7 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, VASlice->chroma_offset_l0); if ((VASlice->slice_type % 5) == H264_SLICE_B) - h264_copy_pred_table(&slice->pred_weight_table.weight_factors[1], + h264_copy_pred_table(&weights->weight_factors[1], slice->num_ref_idx_l1_active_minus1 + 1, VASlice->luma_weight_l1, VASlice->luma_offset_l1, @@ -405,20 +438,81 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, VASlice->chroma_offset_l1); } +int h264_get_controls(struct request_data *driver_data, + struct object_context *context) +{ + struct v4l2_ext_control controls[2] = { + { + .id = V4L2_CID_STATELESS_H264_DECODE_MODE, + }, { + .id = V4L2_CID_STATELESS_H264_START_CODE, + } + }; + int rc; + + rc = v4l2_get_controls(driver_data->video_fd, -1, controls, 2); + if (rc < 0) + return VA_STATUS_ERROR_OPERATION_FAILED; + + switch (controls[0].value) { + case V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED: + break; + case V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED: + break; + default: + request_log("Unsupported decode mode\n"); + return VA_STATUS_ERROR_OPERATION_FAILED; + } + + switch (controls[1].value) { + case V4L2_STATELESS_H264_START_CODE_NONE: + context->h264_start_code = false; + break; + case V4L2_STATELESS_H264_START_CODE_ANNEX_B: + context->h264_start_code = true; + break; + default: + request_log("Unsupported start code\n"); + return VA_STATUS_ERROR_OPERATION_FAILED; + } + + return VA_STATUS_SUCCESS; +} + +static inline __u8 h264_profile_to_idc(VAProfile profile) +{ + switch (profile) { + case VAProfileH264Main: + return 77; + case VAProfileH264High: + return 100; + case VAProfileH264ConstrainedBaseline: + return 66; + case VAProfileH264MultiviewHigh: + return 118; + case VAProfileH264StereoHigh: + return 128; + default: + return 0; + } +} + int h264_set_controls(struct request_data *driver_data, struct object_context *context, + VAProfile profile, struct object_surface *surface) { struct v4l2_ctrl_h264_scaling_matrix matrix = { 0 }; struct v4l2_ctrl_h264_decode_params decode = { 0 }; struct v4l2_ctrl_h264_slice_params slice = { 0 }; + struct v4l2_ctrl_h264_pred_weights weights = { 0 }; struct v4l2_ctrl_h264_pps pps = { 0 }; struct v4l2_ctrl_h264_sps sps = { 0 }; struct h264_dpb_entry *output; int rc; output = dpb_lookup(context, &surface->params.h264.picture.CurrPic, - NULL); + NULL, NULL); if (!output) output = dpb_find_entry(context); @@ -433,33 +527,40 @@ int h264_set_controls(struct request_data *driver_data, &surface->params.h264.matrix, &matrix); h264_va_slice_to_v4l2(driver_data, context, &surface->params.h264.slice, - &surface->params.h264.picture, &slice); + &surface->params.h264.picture, &slice, &weights); - rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, &decode, - sizeof(decode)); - if (rc < 0) - return VA_STATUS_ERROR_OPERATION_FAILED; + sps.profile_idc = h264_profile_to_idc(profile); - rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, &slice, - sizeof(slice)); - if (rc < 0) - return VA_STATUS_ERROR_OPERATION_FAILED; + struct v4l2_ext_control controls[6] = { + { + .id = V4L2_CID_STATELESS_H264_SPS, + .p_h264_sps = &sps, + .size = sizeof(sps), + }, { + .id = V4L2_CID_STATELESS_H264_PPS, + .p_h264_pps = &pps, + .size = sizeof(pps), + }, { + .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, + .p_h264_scaling_matrix = &matrix, + .size = sizeof(matrix), + }, { + .id = V4L2_CID_STATELESS_H264_SLICE_PARAMS, + .p_h264_slice_params = &slice, + .size = sizeof(slice), + }, { + .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, + .p_h264_decode_params = &decode, + .size = sizeof(decode), + }, { + .id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS, + .ptr = &weights, + .size = sizeof(weights), + } + }; - rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_PPS, &pps, sizeof(pps)); - if (rc < 0) - return VA_STATUS_ERROR_OPERATION_FAILED; - - rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_SPS, &sps, sizeof(sps)); - if (rc < 0) - return VA_STATUS_ERROR_OPERATION_FAILED; - - rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, &matrix, - sizeof(matrix)); + rc = v4l2_set_controls(driver_data->video_fd, surface->request_fd, + controls, 6); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; diff --git a/src/h264.h b/src/h264.h index 35ef31d..da0b87f 100644 --- a/src/h264.h +++ b/src/h264.h @@ -51,8 +51,11 @@ struct h264_dpb { unsigned int age; }; +int h264_get_controls(struct request_data *driver_data, + struct object_context *context); int h264_set_controls(struct request_data *data, struct object_context *context, + VAProfile profile, struct object_surface *surface); #endif diff --git a/src/image.c b/src/image.c index fa8b0ea..05ed455 100644 --- a/src/image.c +++ b/src/image.c @@ -155,6 +155,7 @@ static VAStatus copy_surface_to_image (struct request_data *driver_data, return VA_STATUS_ERROR_INVALID_BUFFER; for (i = 0; i < surface_object->destination_planes_count; i++) { +#ifdef __arm__ if (!video_format_is_linear(driver_data->video_format)) tiled_to_planar(surface_object->destination_data[i], buffer_object->data + image->offsets[i], @@ -162,10 +163,13 @@ static VAStatus copy_surface_to_image (struct request_data *driver_data, i == 0 ? image->height : image->height / 2); else { +#endif memcpy(buffer_object->data + image->offsets[i], surface_object->destination_data[i], surface_object->destination_sizes[i]); +#ifdef __arm__ } +#endif } return VA_STATUS_SUCCESS; diff --git a/src/meson.build b/src/meson.build index d73abb1..b7ed642 100644 --- a/src/meson.build +++ b/src/meson.build @@ -44,7 +44,7 @@ sources = [ 'v4l2.c', 'mpeg2.c', 'h264.c', - 'h265.c' +# 'h265.c' ] headers = [ @@ -64,7 +64,7 @@ headers = [ 'v4l2.h', 'mpeg2.h', 'h264.h', - 'h265.h' +# 'h265.h' ] includes = [ diff --git a/src/picture.c b/src/picture.c index aa86265..3713f00 100644 --- a/src/picture.c +++ b/src/picture.c @@ -51,6 +51,7 @@ #include "autoconfig.h" static VAStatus codec_store_buffer(struct request_data *driver_data, + struct object_context *context, VAProfile profile, struct object_surface *surface_object, struct object_buffer *buffer_object) @@ -63,6 +64,14 @@ static VAStatus codec_store_buffer(struct request_data *driver_data, * RenderPicture), we can't use a V4L2 buffer directly * and have to copy from a regular buffer. */ + if (context->h264_start_code) { + static const char start_code[3] = { 0x00, 0x00, 0x01 }; + + memcpy(surface_object->source_data + + surface_object->slices_size, + start_code, sizeof(start_code)); + surface_object->slices_size += sizeof(start_code); + } memcpy(surface_object->source_data + surface_object->slices_size, buffer_object->data, @@ -184,16 +193,15 @@ static VAStatus codec_set_controls(struct request_data *driver_data, case VAProfileH264ConstrainedBaseline: case VAProfileH264MultiviewHigh: case VAProfileH264StereoHigh: - rc = h264_set_controls(driver_data, context, surface_object); + rc = h264_set_controls(driver_data, context, profile, + surface_object); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; break; case VAProfileHEVCMain: - rc = h265_set_controls(driver_data, context, surface_object); - if (rc < 0) - return VA_STATUS_ERROR_OPERATION_FAILED; - break; + /* Fourier-local: HEVC stripped, no HW support on RK3566. */ + return VA_STATUS_ERROR_UNSUPPORTED_PROFILE; default: return VA_STATUS_ERROR_UNSUPPORTED_PROFILE; @@ -255,7 +263,8 @@ VAStatus RequestRenderPicture(VADriverContextP context, VAContextID context_id, if (buffer_object == NULL) return VA_STATUS_ERROR_INVALID_BUFFER; - rc = codec_store_buffer(driver_data, config_object->profile, + rc = codec_store_buffer(driver_data, context_object, + config_object->profile, surface_object, buffer_object); if (rc != VA_STATUS_SUCCESS) return rc; diff --git a/src/surface.c b/src/surface.c index a6abb9b..478f0cc 100644 --- a/src/surface.c +++ b/src/surface.c @@ -46,6 +46,8 @@ #include "v4l2.h" #include "video.h" +bool SET_FORMAT_OF_OUTPUT_ONCE = false; + VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format, unsigned int width, unsigned int height, VASurfaceID *surfaces_ids, @@ -68,10 +70,34 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format, bool found; int rc; + //////////// HACK: this portion of the code should get cleaned up. + + // v4l2_set_format needs to be called BEFORE we create any buffers + // + // we originally did this for the output stream in context.c, but + // RequestCreateSurfaces2 gets called multiple times before RequestCreateContext + // to allocate & map buffers. this doesn't seem to work in recent kernel versions. + // + // we declare SET_FORMAT_OF_OUTPUT_ONCE to ensure v4l2_set_format only gets called once + // (in the first RequestCreateSurfaces2 call BEFORE any buffers are created later on) + unsigned int pixelformat = V4L2_PIX_FMT_H264_SLICE; + unsigned int output_type = v4l2_type_video_output(false); + + if (!SET_FORMAT_OF_OUTPUT_ONCE) { + rc = v4l2_set_format(driver_data->video_fd, output_type, pixelformat, + width, height); + if (rc < 0) { + return VA_STATUS_ERROR_OPERATION_FAILED; + } + + SET_FORMAT_OF_OUTPUT_ONCE = true; + } + + /////////// ENDHACK + if (format != VA_RT_FORMAT_YUV420) return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; - if (!driver_data->video_format) { found = v4l2_find_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, diff --git a/src/surface.h b/src/surface.h index 41007f8..a9be915 100644 --- a/src/surface.h +++ b/src/surface.h @@ -40,7 +40,7 @@ struct object_surface { struct object_base base; - VAStatus status; + VASurfaceStatus status; int width; int height; diff --git a/src/tiled_yuv.S b/src/tiled_yuv.S index c6fa833..4bce33f 100644 --- a/src/tiled_yuv.S +++ b/src/tiled_yuv.S @@ -27,7 +27,7 @@ .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */ #endif -#ifndef __aarch64__ +#ifdef __arm__ .text .syntax unified diff --git a/src/v4l2.c b/src/v4l2.c index d5000ac..3addb33 100644 --- a/src/v4l2.c +++ b/src/v4l2.c @@ -428,37 +428,71 @@ int v4l2_export_buffer(int video_fd, unsigned int type, unsigned int index, return 0; } -int v4l2_set_control(int video_fd, int request_fd, unsigned int id, void *data, - unsigned int size) +static int v4l2_ioctl_controls(int video_fd, int request_fd, unsigned long ioc, + struct v4l2_ext_control *control_array, + unsigned int num_controls) { - struct v4l2_ext_control control; struct v4l2_ext_controls controls; - int rc; - memset(&control, 0, sizeof(control)); memset(&controls, 0, sizeof(controls)); - control.id = id; - control.ptr = data; - control.size = size; - - controls.controls = &control; - controls.count = 1; + controls.controls = control_array; + controls.count = num_controls; if (request_fd >= 0) { controls.which = V4L2_CTRL_WHICH_REQUEST_VAL; controls.request_fd = request_fd; } - rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &controls); + return ioctl(video_fd, ioc, &controls); +} + +int v4l2_get_controls(int video_fd, int request_fd, + struct v4l2_ext_control *control_array, + unsigned int num_controls) +{ + int rc; + + rc = v4l2_ioctl_controls(video_fd, request_fd, VIDIOC_G_EXT_CTRLS, + control_array, num_controls); if (rc < 0) { - request_log("Unable to set control: %s\n", strerror(errno)); + request_log("Unable to get control(s): %s\n", strerror(errno)); return -1; } return 0; } +int v4l2_set_controls(int video_fd, int request_fd, + struct v4l2_ext_control *control_array, + unsigned int num_controls) +{ + int rc; + + rc = v4l2_ioctl_controls(video_fd, request_fd, VIDIOC_S_EXT_CTRLS, + control_array, num_controls); + if (rc < 0) { + request_log("Unable to set control(s): %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +int v4l2_set_control(int video_fd, int request_fd, unsigned int id, void *data, + unsigned int size) +{ + struct v4l2_ext_control control; + + memset(&control, 0, sizeof(control)); + + control.id = id; + control.ptr = data; + control.size = size; + + return v4l2_set_controls(video_fd, request_fd, &control, 1); +} + int v4l2_set_stream(int video_fd, unsigned int type, bool enable) { enum v4l2_buf_type buf_type = type; diff --git a/src/v4l2.h b/src/v4l2.h index 73e9a42..24c12a0 100644 --- a/src/v4l2.h +++ b/src/v4l2.h @@ -54,6 +54,12 @@ int v4l2_dequeue_buffer(int video_fd, int request_fd, unsigned int type, int v4l2_export_buffer(int video_fd, unsigned int type, unsigned int index, unsigned int flags, int *export_fds, unsigned int export_fds_count); +int v4l2_get_controls(int video_fd, int request_fd, + struct v4l2_ext_control *controls, + unsigned int num_controls); +int v4l2_set_controls(int video_fd, int request_fd, + struct v4l2_ext_control *controls, + unsigned int num_controls); int v4l2_set_control(int video_fd, int request_fd, unsigned int id, void *data, unsigned int size); int v4l2_set_stream(int video_fd, unsigned int type, bool enable); diff --git a/src/video.c b/src/video.c index 3ccbb29..9fae332 100644 --- a/src/video.c +++ b/src/video.c @@ -45,6 +45,8 @@ static struct video_format formats[] = { .planes_count = 2, .bpp = 16, }, +// Code to handle this DRM_FORMAT is __arm__ only +#ifdef __arm__ { .description = "Sunxi tiled NV12 YUV", .v4l2_format = V4L2_PIX_FMT_SUNXI_TILED_NV12, @@ -55,6 +57,7 @@ static struct video_format formats[] = { .planes_count = 2, .bpp = 16 }, +#endif }; static unsigned int formats_count = sizeof(formats) / sizeof(formats[0]);