fourier-local: stateless control modernization + HEVC strip

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 <linux/v4l2-controls.h>
  (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) <noreply@anthropic.com>
This commit is contained in:
2026-05-04 09:40:14 +00:00
parent a3c2476de1
commit c45fea96e3
17 changed files with 274 additions and 485 deletions
-197
View File
@@ -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 <linux/videodev2.h>
/* 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
+7 -183
View File
@@ -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 <linux/v4l2-controls.h>
#endif
+15 -8
View File
@@ -35,7 +35,6 @@
#include <linux/videodev2.h>
#include <mpeg2-ctrls.h>
#include <h264-ctrls.h>
#include <hevc-ctrls.h>
#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;
+1
View File
@@ -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,
-33
View File
@@ -40,7 +40,6 @@
#include <linux/videodev2.h>
#include <mpeg2-ctrls.h>
#include <h264-ctrls.h>
#include <hevc-ctrls.h>
#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) {
+1
View File
@@ -50,6 +50,7 @@ struct object_context {
/* H264 only */
struct h264_dpb dpb;
bool h264_start_code;
};
VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
+141 -40
View File
@@ -33,9 +33,9 @@
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <h264-ctrls.h>
#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;
+3
View File
@@ -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
+4
View File
@@ -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;
+2 -2
View File
@@ -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 = [
+15 -6
View File
@@ -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;
+27 -1
View File
@@ -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,
+1 -1
View File
@@ -40,7 +40,7 @@
struct object_surface {
struct object_base base;
VAStatus status;
VASurfaceStatus status;
int width;
int height;
+1 -1
View File
@@ -27,7 +27,7 @@
.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
#endif
#ifndef __aarch64__
#ifdef __arm__
.text
.syntax unified
+47 -13
View File
@@ -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;
+6
View File
@@ -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);
+3
View File
@@ -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]);