21 Commits

Author SHA1 Message Date
test0r e8c3937435 STUDY.md: replace with pointer to libva-multiplanar campaign Phase 0
The Phase 0 / Phase 2 substrate that lived here has been transformed
into ../phase0_findings.md as the campaign-level Phase 0 document.
This file is reduced to a pointer + a git-show recipe to recover the
prior content from commit e0acc33.
2026-05-04 08:08:32 +00:00
test0r e0acc33455 STUDY.md: phase 2 finding — libva surface stack works; Brave wall is chromeos pipeline
mpv --hwdec=vaapi successfully probes our driver end-to-end:
RequestQueryImageFormats, QueryConfigEntrypoints, CreateConfig,
QuerySurfaceAttributes, CreateSurfaces2, DeriveImage, CreateImage,
CreateBuffer, ExportSurfaceHandle all run clean across all seven enumerated
profiles. mpv then falls back to SW for actual decode (drops match the
SW baseline) because our decode-submission path isn't there yet — but
the libva entry-point surface is largely done.

Brave's "failed Initialize()ing the frame pool" turns out to be in
chromium's chromeos pipeline (PickDecoderOutputFormat → ImageProcessor
init in media/gpu/chromeos/video_decoder_pipeline.cc), not in our
driver. No more libva calls happen between our successful CreateContext
and the failure; chromium bails on the chromeos-specific V4L2
ImageProcessor it expects on real ChromeOS but doesn't find on a plain
Linux Wayland system. Fix is on the Chromium build side, not here.

Remaining real work in this library: decode submission path (Begin/
Render/EndPicture → V4L2 stateless queue/dequeue with controls
attached), and proper STREAMON ordering on hantro. STUDY.md now
documents both.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:41:54 +00:00
test0r 283df22748 WIP: log surfaces_count + flags + SUCCESS marker in CreateContext 2026-04-25 22:34:22 +00:00
test0r 4671f64479 WIP: ENTER traces in image.c + buffer.c entry points 2026-04-25 22:30:44 +00:00
test0r 07fd527114 WIP: more entry-point tracing (CreateConfig, GetConfigAttributes, QuerySurfaceAttributes, QueryConfigEntrypoints)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:25:36 +00:00
test0r 2737ff921d WIP: instrument surface.c (CreateSurfaces2, ExportSurfaceHandle) for tracing
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:21:44 +00:00
test0r f2c3a4c32f STUDY.md: checkpoint after first-day port work
Update with current state: library builds clean, vainfo enumerates
profiles, vaCreateContext succeeds on Brave (with STREAMON deferred as
WIP unblocker), next failure is frame pool initialization in
vaCreateSurfaces2. Documents the 12-step diff stack vs bootlin upstream
and what still needs to happen to actually decode a frame.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:10:11 +00:00
test0r 44a73271ae WIP: defer STREAMON in CreateContext (probe how far vaCreateContext gets)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:08:28 +00:00
test0r 0a3432ad64 Eager CAPTURE format probe in RequestInit
Chromium's vaapi_video_decoder may call vaCreateContext with surfaces=NULL,
surfaces_count=0 and then create surfaces afterwards via vaCreateSurfaces2.
In that order driver_data->video_format is still NULL when CreateContext
runs and our early `video_format == NULL` guard returns OPERATION_FAILED.
Confirmed via temporary request_log() — Brave hits exactly that path on
ohm.

Move the probe out of RequestCreateSurfaces into a new
video_format_probe() helper in video.c, and call it eagerly from
RequestInit. RequestCreateSurfaces still re-probes if init came up NULL,
which preserves the original lazy behaviour for any caller that needs it.

Also small clean-up of surface.c since the probe block moved out: drop
the now-dead `bool found` local.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:03:38 +00:00
test0r ac674b84ec src/utils.c: tee request_log() to /tmp/libva-fourier.log
Sandboxed processes (Chromium GPU process etc.) redirect stderr, so
request_log() output never reaches our test harness. Add a lazy-open
append to /tmp/libva-fourier.log so we can capture diagnostic logging
regardless of process sandboxing.

Will revert before final.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:59:57 +00:00
test0r 1458622729 src/context.c: temporary diagnostic logging in CreateContext
Added request_log() calls at every failure path inside RequestCreateContext
to identify exactly which guard fires when Brave's vaCreateContext fails on
ohm. Will revert these before final.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:57:33 +00:00
test0r 4d14ffb801 src/tiled_yuv.S: stub tiled_to_planar on aarch64
The whole body of tiled_yuv.S is wrapped in #ifndef __aarch64__ — the
ARMv7 NEON Thumb code doesn't assemble on aarch64. On 64-bit ARM the
.S object is therefore empty and tiled_to_planar comes out as an
undefined symbol in the .so, which dlopen rejects at vainfo time:

  libva error: dlopen ... failed: undefined symbol: tiled_to_planar

Runtime-wise, tiled_to_planar is only called when
video_format_is_linear() returns false, which only happens for the
sunxi-cedrus DRM_FORMAT_MOD_ALLWINNER_TILED NV12 entry — never on
hantro/rkvdec. So the right fix is a no-op stub on aarch64 just to
satisfy the linker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:54:19 +00:00
test0r 13e9b64bcf src/h264.c: drop num_slices field; kernel infers from queued controls
decode->num_slices was the last field on v4l2_ctrl_h264_decode_params
that didn't survive the upstream cleanup. The kernel now infers the
slice count from how many slice_params controls were queued via the
request API for the given OUTPUT buffer; no explicit count is needed.

This was the only remaining build error; library should now compile clean
against current linux-api-headers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:52:17 +00:00
test0r fc4bb1063f src/h264.c: track upstream UAPI shape for H.264 controls
The H.264 stateless control structs and CIDs were upstreamed and
reshaped during the journey from libva-v4l2-request's bundled headers
to the kernel's <linux/v4l2-controls.h>. Three breaking changes need
matching code-side updates:

1. struct v4l2_ctrl_h264_slice_params lost its .size field. The full
   slice byte length is now communicated via the OUTPUT buffer's
   m.planes[0].bytesused at QBUF time, which v4l2_queue_buffer already
   sets. Drop the assignment.

2. struct v4l2_h264_reference replaces the bare integer DPB index in
   ref_pic_list0[] / ref_pic_list1[]. The new struct is { __u8 fields,
   __u8 index } where `fields` is V4L2_H264_TOP_FIELD_REF (0x1) /
   BOTTOM_FIELD_REF (0x2) / FRAME_REF (0x3). Hantro G1 only does
   frame-based H.264, so use V4L2_H264_FRAME_REF unconditionally.

3. The pred_weight_table block moved out of slice_params into its own
   V4L2_CID_STATELESS_H264_PRED_WEIGHTS control with struct
   v4l2_ctrl_h264_pred_weights. Add it as a separate v4l2_set_control()
   call alongside SPS/PPS/SLICE_PARAMS/DECODE_PARAMS/SCALING_MATRIX, and
   thread the pred_weights pointer through h264_va_slice_to_v4l2().

Also: switch the v4l2_set_control() CID arguments from V4L2_CID_MPEG_VIDEO_H264_*
to V4L2_CID_STATELESS_H264_* directly. h264-ctrls.h still defines the
old names as aliases so external callers keep working, but using the
canonical names internally matches what the kernel actually expects and
avoids confusion when reading h264.c side-by-side with the kernel
source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:51:43 +00:00
test0r da9f2a55d2 include/h264-ctrls.h: passthrough to system header + CID aliases
H.264 stateless controls were upstreamed to the kernel some time after
this library went dormant. The struct names match exactly (the kernel
adopted v4l2_ctrl_h264_{sps,pps,scaling_matrix,pred_weights,slice_params,
decode_params} and v4l2_h264_{weight_factors,dpb_entry,reference}
verbatim) so the duplicated copies in include/h264-ctrls.h trigger
redefinition errors as soon as any source file pulls in
<linux/videodev2.h> (which transitively pulls in <linux/v4l2-controls.h>).

Same fix as hevc-ctrls.h in commit 4ccbfe9: replace the bundled struct
definitions with a passthrough to <linux/v4l2-controls.h>. The CID
prefix changed during upstreaming from V4L2_CID_MPEG_VIDEO_H264_* to
V4L2_CID_STATELESS_H264_*; provide compatibility aliases so h264.c keeps
compiling. V4L2_PIX_FMT_H264_SLICE is already in <linux/videodev2.h>
(same fourcc value, same name we renamed to in commit c1f5108) so no
need to redefine.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:49:26 +00:00
test0r 53999cd154 The real multiplanar wedge: probe MPLANE in surface.c, add NV12 mplane
This is what was actually broken — and it's much smaller than the STUDY
guessed.

The library is in fact multiplanar-aware throughout the v4l2.c helpers
(v4l2_setup_format, v4l2_get_format, v4l2_query_buffer, v4l2_queue_buffer,
v4l2_dequeue_buffer all branch on v4l2_type_is_mplane). The whole
"context.c / picture.c are single-plane" hypothesis from STUDY.md was wrong —
they derive output_type and capture_type from
video_format->v4l2_mplane and pass them through.

The bug is upstream of all that: driver_data->video_format is set in
RequestCreateSurfaces only, and the probe there only tries
V4L2_BUF_TYPE_VIDEO_CAPTURE (single-plane). On hantro the single-plane
ENUM_FMT returns nothing, video_format stays NULL, and every subsequent
operation hits the `if (video_format == NULL) return OPERATION_FAILED`
guard at the top of context.c / buffer.c / image.c. That's exactly what
Brave's vaCreateContext failure was — not a downstream multiplanar fault,
just the format-detection short-circuit firing.

Three small changes:

- src/video.c: add an NV12 multi-plane entry next to the existing
  single-plane NV12 / Sunxi entries. Same pixelformat fourcc (S264 vs NV12
  has nothing to do with mplane), distinguished by the v4l2_mplane bit.
- src/video.h + src/video.c: video_format_find() takes a `bool mplane`
  parameter and matches both fields. Without this the single-plane and
  multi-plane NV12 entries collide on pixelformat.
- src/surface.c: the probe block now tries V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
  as a fallback after the single-plane probes return nothing. On a
  single-plane decoder the mplane probe is a no-op; on hantro it picks
  the new mplane NV12 entry, video_format gets set, and the rest of the
  library — already mplane-aware — does the right thing for OUTPUT
  S_FMT, REQBUFS, EXPBUF, QBUF, DQBUF.

Also: src/context.c: the H264 case still referenced V4L2_PIX_FMT_H264_SLICE_RAW
that we renamed in commit c1f5108. Caught now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:47:30 +00:00
test0r 294bdc24f6 STUDY.md: port plan + reference implementations + test fixtures
Cold-start dossier for the multiplanar port: goal, why-this-fork-exists,
state-today, port plan (v4l2.c / context.c / picture.c), reference impls
to read side-by-side (FFmpeg libavcodec/v4l2_request*, GStreamer
gst-plugins-bad/sys/v4l2codecs, Chromium media/gpu/v4l2), test fixtures
(ohm + bbb_1080p30_h264.mp4 + GStreamer ceiling at 6% CPU), out-of-scope
(HEVC/VP9/AV1).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:30:54 +00:00
test0r 2f54a8d9e8 src/config.c: probe both single- and multi-plane V4L2 buffer types
Bootlin's original probe assumed single-plane decoders (the sunxi-cedrus
target the library was originally written for). Rockchip's hantro VPU
on RK3566/RK3588 reports V4L2_CAP_VIDEO_M2M_MPLANE only — the single-
plane VIDIOC_ENUM_FMT path returns nothing, so vainfo prints an empty
"Supported profile and entrypoints" list and downstream apps fall back
to software.

Add an OUTPUT_MPLANE fallback to all three format probes (MPEG-2, H.264,
HEVC). On a single-plane decoder the second probe is a no-op; on a
multi-plane decoder it's what makes the profile list non-empty.

This is the *probe* fix only — it gets vainfo to enumerate profiles and
gets Brave's GPU process to attempt vaCreateContext. The rest of the
multiplanar port (S_FMT / REQBUFS / EXPBUF / QBUF in context.c, picture.c,
v4l2.c) is the next phase; vaCreateContext currently fails because
those paths are still single-plane only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:27:46 +00:00
test0r 4ccbfe923f Strip HEVC build path
Three changes that together make the build compile cleanly against a
current linux-api-headers (>= 5.x post-HEVC-UAPI-rename):

- src/meson.build: comment h265.c + h265.h out of sources/headers.
- include/hevc-ctrls.h: replace bundled HEVC structs with a single
  #include <linux/v4l2-controls.h>. The bundled definitions were
  identical to what later landed in mainline as V4L2_CID_STATELESS_HEVC_*
  (renamed) and v4l2_ctrl_hevc_* (kept the field names but moved into
  the kernel public header). Keeping a duplicate copy now triggers
  redefinition errors. The header is kept as a passthrough rather than
  deleted so any downstream patch that says #include <hevc-ctrls.h>
  still compiles.
- src/picture.c: drop the four HEVC case blocks. Three of them were in
  switches that already had `default: break`, so removing them is
  functionally a no-op. The fourth was the only external reference to
  h265_set_controls — removing it lets the library link cleanly with
  h265.c excluded.

Why this is OK rather than the more ambitious "fix HEVC properly":
RK3566 has no HW HEVC at all (the only decoder block is the Hantro G1
which speaks H.264 / MPEG-2 / VP8). HEVC can come back as a separate
effort once we're on RK3588 silicon AND the library is updated to the
renamed kernel CIDs. For Fourier's first port milestone (H.264 multi-
plane on RK3566 hantro) HEVC is dead weight.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:26:28 +00:00
test0r 1b02c9b476 src/h264.c: include utils.h for request_log() prototype
GCC's -Wimplicit-function-declaration is fatal in current toolchains
(GCC 14+) but was a warning when this code was written. h264.c uses
request_log() in two places without including utils.h; the build was
quietly relying on an implicit declaration that recent compilers reject.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:16:35 +00:00
test0r c1f5108ac3 include/h264-ctrls.h, src/config.c: rename to V4L2_PIX_FMT_H264_SLICE
Kernel mainline renamed V4L2_PIX_FMT_H264_SLICE_RAW → V4L2_PIX_FMT_H264_SLICE
some time after this library went dormant (the 'S264' fourcc value is
unchanged; only the C identifier moved). The two definitions have the same
value so this is purely cosmetic at runtime, but keeping the name aligned
with linux/videodev2.h matches downstream patches (e.g. bootlin PR #38)
and avoids confusion when reading kernel + library side-by-side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:13:11 +00:00
16 changed files with 317 additions and 458 deletions
+9
View File
@@ -0,0 +1,9 @@
# STUDY.md → moved
The Phase 0 / Phase 2 substrate that previously lived here has been transformed into the campaign-level Phase 0 document at:
- [`../phase0_findings.md`](../phase0_findings.md)
That document also points at the remaining open questions for Phase 1 lock and the verification gate at Phase 7. Read it together with the campaign README at [`../README.md`](../README.md).
The git commit that this file points back to (the last commit while STUDY.md still held the substrate content) is `e0acc33``git show e0acc33:STUDY.md` recovers the historical content if needed.
+35 -186
View File
@@ -1,197 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* These are the H.264 state controls for use with stateless H.264
* codec drivers.
* Fourier-local: H.264 stateless controls and structs were upstreamed to
* the kernel some time after this library went dormant. Defer all of:
*
* 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.
* struct v4l2_ctrl_h264_sps / pps / scaling_matrix / pred_weights /
* slice_params / decode_params
* struct v4l2_h264_weight_factors / dpb_entry / reference
* enum v4l2_*_h264_*
*
* to <linux/v4l2-controls.h>, where they now live with the same field
* names. The duplicated definitions in the original bootlin
* include/h264-ctrls.h conflict at compile time on any current kernel.
*
* The CID prefix was also renamed from V4L2_CID_MPEG_VIDEO_H264_* to
* V4L2_CID_STATELESS_H264_*. Provide compatibility aliases so h264.c
* keeps compiling without an invasive sed across that file.
*
* V4L2_PIX_FMT_H264_SLICE itself lives in <linux/videodev2.h> on current
* kernels, so no need to redefine it here.
*/
#ifndef _H264_CTRLS_H_
#define _H264_CTRLS_H_
#include <linux/videodev2.h>
#include <linux/v4l2-controls.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_* */
};
#ifndef V4L2_CID_MPEG_VIDEO_H264_SPS
#define V4L2_CID_MPEG_VIDEO_H264_SPS \
V4L2_CID_STATELESS_H264_SPS
#define V4L2_CID_MPEG_VIDEO_H264_PPS \
V4L2_CID_STATELESS_H264_PPS
#define V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX \
V4L2_CID_STATELESS_H264_SCALING_MATRIX
#define V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS \
V4L2_CID_STATELESS_H264_SLICE_PARAMS
#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS \
V4L2_CID_STATELESS_H264_DECODE_PARAMS
#define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE \
V4L2_CID_STATELESS_H264_DECODE_MODE
#define V4L2_CID_MPEG_VIDEO_H264_START_CODE \
V4L2_CID_STATELESS_H264_START_CODE
#endif
#endif /* _H264_CTRLS_H_ */
+12 -178
View File
@@ -1,185 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* These are the HEVC state controls for use with stateless HEVC
* codec drivers.
* Fourier-local: HEVC support stripped from this build. The bundled
* HEVC controls structs and CIDs (V4L2_CID_MPEG_VIDEO_HEVC_*) were
* upstreamed and renamed to V4L2_CID_STATELESS_HEVC_* in mainline
* linux/v4l2-controls.h, making the original duplicated definitions
* conflict on any current kernel. RK3566 has no HW HEVC anyway, so the
* port is starting from H.264 + MPEG-2 only; HEVC can come back as a
* separate effort once a) the host has HEVC silicon (RK3588 hantro/
* VDPU381) and b) the library is updated to the renamed CIDs.
*
* 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.
* h265.c and h265.h are excluded from src/meson.build; this header is
* left as a placeholder so any stray '#include <hevc-ctrls.h>' from a
* downstream patch keeps compiling.
*/
#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];
};
#include <linux/v4l2-controls.h>
#endif
+8
View File
@@ -49,6 +49,7 @@ VAStatus RequestCreateBuffer(VADriverContextP context, VAContextID context_id,
unsigned int count, void *data,
VABufferID *buffer_id)
{
request_log("ENTER RequestCreateBuffer\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object = NULL;
void *buffer_data;
@@ -109,6 +110,7 @@ complete:
VAStatus RequestDestroyBuffer(VADriverContextP context, VABufferID buffer_id)
{
request_log("ENTER RequestDestroyBuffer\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object;
@@ -128,6 +130,7 @@ VAStatus RequestDestroyBuffer(VADriverContextP context, VABufferID buffer_id)
VAStatus RequestMapBuffer(VADriverContextP context, VABufferID buffer_id,
void **data_map)
{
request_log("ENTER RequestMapBuffer\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object;
@@ -143,6 +146,7 @@ VAStatus RequestMapBuffer(VADriverContextP context, VABufferID buffer_id,
VAStatus RequestUnmapBuffer(VADriverContextP context, VABufferID buffer_id)
{
request_log("ENTER RequestUnmapBuffer\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object;
@@ -158,6 +162,7 @@ VAStatus RequestUnmapBuffer(VADriverContextP context, VABufferID buffer_id)
VAStatus RequestBufferSetNumElements(VADriverContextP context,
VABufferID buffer_id, unsigned int count)
{
request_log("ENTER RequestBufferSetNumElements\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object;
@@ -177,6 +182,7 @@ VAStatus RequestBufferInfo(VADriverContextP context, VABufferID buffer_id,
VABufferType *type, unsigned int *size,
unsigned int *count)
{
request_log("ENTER RequestBufferInfo\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object;
@@ -195,6 +201,7 @@ VAStatus RequestAcquireBufferHandle(VADriverContextP context,
VABufferID buffer_id,
VABufferInfo *buffer_info)
{
request_log("ENTER RequestAcquireBufferHandle\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object;
struct object_surface *surface_object;
@@ -245,6 +252,7 @@ VAStatus RequestAcquireBufferHandle(VADriverContextP context,
VAStatus RequestReleaseBufferHandle(VADriverContextP context,
VABufferID buffer_id)
{
request_log("ENTER RequestReleaseBufferHandle\n");
struct request_data *driver_data = context->pDriverData;
struct object_buffer *buffer_object;
int export_fd;
+18 -1
View File
@@ -53,6 +53,9 @@ VAStatus RequestCreateConfig(VADriverContextP context, VAProfile profile,
VAConfigID id;
int i, index;
request_log("CreateConfig: profile=%d entrypoint=%d attrs=%d\n",
profile, entrypoint, attributes_count);
switch (profile) {
case VAProfileMPEG2Simple:
case VAProfileMPEG2Main:
@@ -120,6 +123,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 +134,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 +148,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;
@@ -153,6 +165,8 @@ VAStatus RequestQueryConfigEntrypoints(VADriverContextP context,
VAEntrypoint *entrypoints,
int *entrypoints_count)
{
request_log("QueryConfigEntrypoints: profile=%d\n", profile);
switch (profile) {
case VAProfileMPEG2Simple:
case VAProfileMPEG2Main:
@@ -212,6 +226,9 @@ VAStatus RequestGetConfigAttributes(VADriverContextP context, VAProfile profile,
{
unsigned int i;
request_log("GetConfigAttributes: profile=%d entrypoint=%d count=%d\n",
profile, entrypoint, attributes_count);
for (i = 0; i < attributes_count; i++) {
switch (attributes[i].type) {
case VAConfigAttribRTFormat:
+30 -13
View File
@@ -72,17 +72,26 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
int rc;
video_format = driver_data->video_format;
if (video_format == NULL)
if (video_format == NULL) {
request_log("CreateContext: video_format is NULL\n");
return VA_STATUS_ERROR_OPERATION_FAILED;
}
output_type = v4l2_type_video_output(video_format->v4l2_mplane);
capture_type = v4l2_type_video_capture(video_format->v4l2_mplane);
request_log("CreateContext: ENTER config=%u mplane=%d output_type=%u capture_type=%u surfaces_count=%d flags=0x%x\n",
config_id, video_format->v4l2_mplane, output_type,
capture_type, surfaces_count, flags);
config_object = CONFIG(driver_data, config_id);
if (config_object == NULL) {
request_log("CreateContext: config_object NULL for config_id %u\n",
config_id);
status = VA_STATUS_ERROR_INVALID_CONFIG;
goto error;
}
request_log("CreateContext: profile=%d width=%d height=%d\n",
config_object->profile, picture_width, picture_height);
id = object_heap_allocate(&driver_data->context_heap);
context_object = CONTEXT(driver_data, id);
@@ -104,7 +113,7 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
case VAProfileH264ConstrainedBaseline:
case VAProfileH264MultiviewHigh:
case VAProfileH264StereoHigh:
pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW;
pixelformat = V4L2_PIX_FMT_H264_SLICE;
break;
case VAProfileHEVCMain:
@@ -119,6 +128,8 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
rc = v4l2_set_format(driver_data->video_fd, output_type, pixelformat,
picture_width, picture_height);
if (rc < 0) {
request_log("CreateContext: S_FMT(OUTPUT) failed for pixelformat 0x%x\n",
pixelformat);
status = VA_STATUS_ERROR_OPERATION_FAILED;
goto error;
}
@@ -126,9 +137,13 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
rc = v4l2_create_buffers(driver_data->video_fd, output_type,
surfaces_count, &index_base);
if (rc < 0) {
request_log("CreateContext: CREATE_BUFS failed surfaces=%d\n",
surfaces_count);
status = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto error;
}
request_log("CreateContext: S_FMT + CREATE_BUFS ok, index_base=%u\n",
index_base);
/*
* The surface_ids array has been allocated by the caller and
@@ -155,6 +170,7 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
rc = v4l2_query_buffer(driver_data->video_fd, output_type,
index, &length, &offset, 1);
if (rc < 0) {
request_log("CreateContext: QUERYBUF idx=%u failed\n", index);
status = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto error;
}
@@ -162,6 +178,8 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
source_data = mmap(NULL, length, PROT_READ | PROT_WRITE,
MAP_SHARED, driver_data->video_fd, offset);
if (source_data == MAP_FAILED) {
request_log("CreateContext: mmap len=%u offset=%u failed\n",
length, offset);
status = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto error;
}
@@ -171,17 +189,14 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
surface_object->source_size = length;
}
rc = v4l2_set_stream(driver_data->video_fd, output_type, true);
if (rc < 0) {
status = VA_STATUS_ERROR_OPERATION_FAILED;
goto error;
}
rc = v4l2_set_stream(driver_data->video_fd, capture_type, true);
if (rc < 0) {
status = VA_STATUS_ERROR_OPERATION_FAILED;
goto error;
}
/* Fourier-local: defer STREAMON until first frame is actually queued.
* The V4L2 stateless protocol requires OUTPUT format + at least one
* queued slice with SPS/PPS controls attached before STREAMON will
* succeed on hantro. The bootlin library was written for sunxi-cedrus
* which used a different protocol with no such ordering constraint.
* Just being able to vaCreateContext() without erroring lets us see
* what the next stage of the call chain expects. */
request_log("CreateContext: deferred STREAMON until first QBUF\n");
context_object->config_id = config_id;
context_object->render_surface_id = VA_INVALID_ID;
@@ -193,6 +208,8 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
*context_id = id;
request_log("CreateContext: SUCCESS context_id=%u\n", id);
status = VA_STATUS_SUCCESS;
goto complete;
+33 -15
View File
@@ -36,6 +36,7 @@
#include <h264-ctrls.h>
#include "request.h"
#include "utils.h"
#include "surface.h"
#include "v4l2.h"
@@ -220,7 +221,9 @@ static void h264_va_picture_to_v4l2(struct request_data *driver_data,
{
h264_fill_dpb(driver_data, context, decode);
decode->num_slices = surface->slices_count;
/* num_slices is no longer carried by v4l2_ctrl_h264_decode_params; the
* kernel infers slice count from the number of slice_params controls
* queued (one per slice via the request API). */
decode->top_field_order_cnt = VAPicture->CurrPic.TopFieldOrderCnt;
decode->bottom_field_order_cnt = VAPicture->CurrPic.BottomFieldOrderCnt;
@@ -327,9 +330,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 *pred_weights)
{
slice->size = VASlice->slice_data_size;
/* Slice byte size is now communicated via the OUTPUT buffer's
* bytesused at QBUF time; the v4l2_ctrl_h264_slice_params struct
* was slimmed during upstreaming and no longer carries it. */
slice->header_bit_size = VASlice->slice_data_bit_offset;
slice->first_mb_in_slice = VASlice->first_mb_in_slice;
slice->slice_type = VASlice->slice_type;
@@ -356,7 +362,8 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data,
if (!entry)
continue;
slice->ref_pic_list0[i] = idx;
slice->ref_pic_list0[i].index = idx;
slice->ref_pic_list0[i].fields = V4L2_H264_FRAME_REF;
}
}
@@ -375,21 +382,24 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data,
if (!entry)
continue;
slice->ref_pic_list1[i] = idx;
slice->ref_pic_list1[i].index = idx;
slice->ref_pic_list1[i].fields = V4L2_H264_FRAME_REF;
}
}
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 =
/* Predicted weight table moved out of slice_params into its own
* V4L2_CID_STATELESS_H264_PRED_WEIGHTS control during upstreaming. */
pred_weights->chroma_log2_weight_denom =
VASlice->chroma_log2_weight_denom;
slice->pred_weight_table.luma_log2_weight_denom =
pred_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(&pred_weights->weight_factors[0],
slice->num_ref_idx_l0_active_minus1 + 1,
VASlice->luma_weight_l0,
VASlice->luma_offset_l0,
@@ -397,7 +407,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(&pred_weights->weight_factors[1],
slice->num_ref_idx_l1_active_minus1 + 1,
VASlice->luma_weight_l1,
VASlice->luma_offset_l1,
@@ -412,6 +422,7 @@ int h264_set_controls(struct request_data *driver_data,
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 pred_weights = { 0 };
struct v4l2_ctrl_h264_pps pps = { 0 };
struct v4l2_ctrl_h264_sps sps = { 0 };
struct h264_dpb_entry *output;
@@ -433,32 +444,39 @@ 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,
&pred_weights);
rc = v4l2_set_control(driver_data->video_fd, surface->request_fd,
V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, &decode,
V4L2_CID_STATELESS_H264_DECODE_PARAMS, &decode,
sizeof(decode));
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_SLICE_PARAMS, &slice,
V4L2_CID_STATELESS_H264_SLICE_PARAMS, &slice,
sizeof(slice));
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_PPS, &pps, sizeof(pps));
V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
&pred_weights, sizeof(pred_weights));
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));
V4L2_CID_STATELESS_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_SCALING_MATRIX, &matrix,
V4L2_CID_STATELESS_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_STATELESS_H264_SCALING_MATRIX, &matrix,
sizeof(matrix));
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;
+7
View File
@@ -40,6 +40,7 @@
VAStatus RequestCreateImage(VADriverContextP context, VAImageFormat *format,
int width, int height, VAImage *image)
{
request_log("ENTER RequestCreateImage\n");
struct request_data *driver_data = context->pDriverData;
unsigned int destination_sizes[VIDEO_MAX_PLANES];
unsigned int destination_bytesperlines[VIDEO_MAX_PLANES];
@@ -125,6 +126,7 @@ VAStatus RequestCreateImage(VADriverContextP context, VAImageFormat *format,
VAStatus RequestDestroyImage(VADriverContextP context, VAImageID image_id)
{
request_log("ENTER RequestDestroyImage\n");
struct request_data *driver_data = context->pDriverData;
struct object_image *image_object;
VAStatus status;
@@ -174,6 +176,7 @@ static VAStatus copy_surface_to_image (struct request_data *driver_data,
VAStatus RequestDeriveImage(VADriverContextP context, VASurfaceID surface_id,
VAImage *image)
{
request_log("ENTER RequestDeriveImage\n");
struct request_data *driver_data = context->pDriverData;
struct object_surface *surface_object;
struct object_buffer *buffer_object;
@@ -212,6 +215,7 @@ VAStatus RequestDeriveImage(VADriverContextP context, VASurfaceID surface_id,
VAStatus RequestQueryImageFormats(VADriverContextP context,
VAImageFormat *formats, int *formats_count)
{
request_log("ENTER RequestQueryImageFormats\n");
formats[0].fourcc = VA_FOURCC_NV12;
*formats_count = 1;
@@ -221,6 +225,7 @@ VAStatus RequestQueryImageFormats(VADriverContextP context,
VAStatus RequestSetImagePalette(VADriverContextP context, VAImageID image_id,
unsigned char *palette)
{
request_log("ENTER RequestSetImagePalette\n");
return VA_STATUS_ERROR_UNIMPLEMENTED;
}
@@ -228,6 +233,7 @@ VAStatus RequestGetImage(VADriverContextP context, VASurfaceID surface_id,
int x, int y, unsigned int width, unsigned int height,
VAImageID image_id)
{
request_log("ENTER RequestGetImage\n");
struct request_data *driver_data = context->pDriverData;
struct object_surface *surface_object;
struct object_image *image_object;
@@ -254,5 +260,6 @@ VAStatus RequestPutImage(VADriverContextP context, VASurfaceID surface_id,
int dst_x, int dst_y, unsigned int dst_width,
unsigned int dst_height)
{
request_log("ENTER RequestPutImage\n");
return VA_STATUS_ERROR_UNIMPLEMENTED;
}
+2 -2
View File
@@ -44,7 +44,7 @@ sources = [
'v4l2.c',
'mpeg2.c',
'h264.c',
'h265.c'
# 'h265.c' # Fourier-local: HEVC stripped (see commit log)
]
headers = [
@@ -64,7 +64,7 @@ headers = [
'v4l2.h',
'mpeg2.h',
'h264.h',
'h265.h'
# 'h265.h' # Fourier-local: HEVC stripped (see commit log)
]
includes = [
+3 -24
View File
@@ -91,12 +91,6 @@ static VAStatus codec_store_buffer(struct request_data *driver_data,
sizeof(surface_object->params.h264.picture));
break;
case VAProfileHEVCMain:
memcpy(&surface_object->params.h265.picture,
buffer_object->data,
sizeof(surface_object->params.h265.picture));
break;
default:
break;
}
@@ -114,12 +108,6 @@ static VAStatus codec_store_buffer(struct request_data *driver_data,
sizeof(surface_object->params.h264.slice));
break;
case VAProfileHEVCMain:
memcpy(&surface_object->params.h265.slice,
buffer_object->data,
sizeof(surface_object->params.h265.slice));
break;
default:
break;
}
@@ -145,13 +133,6 @@ static VAStatus codec_store_buffer(struct request_data *driver_data,
sizeof(surface_object->params.h264.matrix));
break;
case VAProfileHEVCMain:
memcpy(&surface_object->params.h265.iqmatrix,
buffer_object->data,
sizeof(surface_object->params.h265.iqmatrix));
surface_object->params.h265.iqmatrix_set = true;
break;
default:
break;
}
@@ -189,11 +170,9 @@ static VAStatus codec_set_controls(struct request_data *driver_data,
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;
/* HEVC stripped: kernel V4L2_CID_MPEG_VIDEO_HEVC_* CIDs were renamed
* to V4L2_CID_STATELESS_HEVC_* upstream, and ohm's hantro VPU has no
* HEVC support anyway. Falls through to the default case below. */
default:
return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
+14
View File
@@ -39,6 +39,7 @@
#include "request.h"
#include "utils.h"
#include "v4l2.h"
#include "video.h"
#include <assert.h>
#include <stdio.h>
@@ -179,6 +180,19 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
driver_data->video_fd = video_fd;
driver_data->media_fd = media_fd;
/* Probe the CAPTURE pixel format eagerly so vaCreateContext doesn't
* race ahead of vaCreateSurfaces. Fine if this returns NULL — we
* still let the driver init succeed and let surface creation try
* again later (preserves the original lazy behaviour for any caller
* that needs it). */
driver_data->video_format = video_format_probe(video_fd);
if (driver_data->video_format != NULL)
request_log("Init: detected CAPTURE format %s (mplane=%d)\n",
driver_data->video_format->description,
driver_data->video_format->v4l2_mplane);
else
request_log("Init: no CAPTURE format detected at probe time\n");
status = VA_STATUS_SUCCESS;
goto complete;
+67 -36
View File
@@ -65,54 +65,60 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
unsigned int index;
unsigned int i, j;
VASurfaceID id;
bool found;
int rc;
if (format != VA_RT_FORMAT_YUV420)
request_log("CreateSurfaces2: format=0x%x %dx%d count=%d\n",
format, width, height, surfaces_count);
if (format != VA_RT_FORMAT_YUV420) {
request_log("CreateSurfaces2: rejecting RT_FORMAT 0x%x\n", format);
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,
V4L2_PIX_FMT_SUNXI_TILED_NV12);
if (found)
video_format = video_format_find(V4L2_PIX_FMT_SUNXI_TILED_NV12);
found = v4l2_find_format(driver_data->video_fd,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_PIX_FMT_NV12);
if (found)
video_format = video_format_find(V4L2_PIX_FMT_NV12);
if (video_format == NULL)
if (!driver_data->video_format) {
/* Could happen if RequestInit's eager probe came back NULL —
* try one more time here in case the device only became
* format-enumerable after streaming setup. */
driver_data->video_format = video_format_probe(driver_data->video_fd);
if (driver_data->video_format == NULL) {
request_log("CreateSurfaces2: video_format probe still NULL\n");
return VA_STATUS_ERROR_OPERATION_FAILED;
}
}
driver_data->video_format = video_format;
video_format = driver_data->video_format;
capture_type = v4l2_type_video_capture(video_format->v4l2_mplane);
capture_type = v4l2_type_video_capture(video_format->v4l2_mplane);
rc = v4l2_set_format(driver_data->video_fd, capture_type,
video_format->v4l2_format, width, height);
if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED;
} else {
video_format = driver_data->video_format;
capture_type = v4l2_type_video_capture(video_format->v4l2_mplane);
/* Set the CAPTURE format on first surface creation so the size is
* pinned to the picture dimensions the caller passed in. */
rc = v4l2_set_format(driver_data->video_fd, capture_type,
video_format->v4l2_format, width, height);
if (rc < 0) {
request_log("CreateSurfaces2: S_FMT(CAPTURE) failed for fmt=0x%x %dx%d\n",
video_format->v4l2_format, width, height);
return VA_STATUS_ERROR_OPERATION_FAILED;
}
rc = v4l2_get_format(driver_data->video_fd, capture_type, &format_width,
&format_height, destination_bytesperlines,
destination_sizes, NULL);
if (rc < 0)
if (rc < 0) {
request_log("CreateSurfaces2: G_FMT(CAPTURE) failed\n");
return VA_STATUS_ERROR_OPERATION_FAILED;
}
request_log("CreateSurfaces2: G_FMT got %dx%d bpl[0]=%d size[0]=%d\n",
format_width, format_height,
destination_bytesperlines[0], destination_sizes[0]);
destination_planes_count = video_format->planes_count;
rc = v4l2_create_buffers(driver_data->video_fd, capture_type,
surfaces_count, &index_base);
if (rc < 0)
if (rc < 0) {
request_log("CreateSurfaces2: CREATE_BUFS(CAPTURE) failed\n");
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
request_log("CreateSurfaces2: CREATE_BUFS ok index_base=%u\n", index_base);
for (i = 0; i < surfaces_count; i++) {
index = index_base + i;
@@ -127,8 +133,10 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
surface_object->destination_map_lengths,
surface_object->destination_map_offsets,
video_format->v4l2_buffers_count);
if (rc < 0)
if (rc < 0) {
request_log("CreateSurfaces2: QUERYBUF idx=%u failed\n", index);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
for (j = 0; j < video_format->v4l2_buffers_count; j++) {
surface_object->destination_map[j] =
@@ -138,8 +146,13 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
driver_data->video_fd,
surface_object->destination_map_offsets[j]);
if (surface_object->destination_map[j] == MAP_FAILED)
if (surface_object->destination_map[j] == MAP_FAILED) {
request_log("CreateSurfaces2: mmap idx=%u plane=%u len=%u offset=%u failed\n",
index, j,
surface_object->destination_map_lengths[j],
surface_object->destination_map_offsets[j]);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
}
/*
@@ -177,6 +190,9 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
destination_bytesperlines[j];
}
} else {
request_log("CreateSurfaces2: buffers_count=%u planes_count=%u mismatch\n",
video_format->v4l2_buffers_count,
destination_planes_count);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
@@ -345,6 +361,9 @@ VAStatus RequestQuerySurfaceAttributes(VADriverContextP context,
int memory_types;
unsigned int i = 0;
request_log("QuerySurfaceAttributes: config=%u attrs=%p count=%p\n",
config, attributes, attributes_count);
attributes_list = malloc(attributes_list_size);
memset(attributes_list, 0, attributes_list_size);
@@ -469,16 +488,26 @@ VAStatus RequestExportSurfaceHandle(VADriverContextP context,
VAStatus status;
int rc;
video_format = driver_data->video_format;
if (video_format == NULL)
return VA_STATUS_ERROR_OPERATION_FAILED;
request_log("ExportSurfaceHandle: surface_id=%u mem_type=0x%x flags=0x%x\n",
surface_id, mem_type, flags);
if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)
video_format = driver_data->video_format;
if (video_format == NULL) {
request_log("ExportSurfaceHandle: video_format NULL\n");
return VA_STATUS_ERROR_OPERATION_FAILED;
}
if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) {
request_log("ExportSurfaceHandle: rejecting mem_type 0x%x (only DRM_PRIME_2)\n",
mem_type);
return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
}
surface_object = SURFACE(driver_data, surface_id);
if (surface_object == NULL)
if (surface_object == NULL) {
request_log("ExportSurfaceHandle: invalid surface_id\n");
return VA_STATUS_ERROR_INVALID_SURFACE;
}
export_fds_count = surface_object->destination_buffers_count;
export_fds = malloc(export_fds_count * sizeof(*export_fds));
@@ -489,6 +518,8 @@ VAStatus RequestExportSurfaceHandle(VADriverContextP context,
surface_object->destination_index, O_RDONLY,
export_fds, export_fds_count);
if (rc < 0) {
request_log("ExportSurfaceHandle: EXPBUF idx=%u count=%u failed\n",
surface_object->destination_index, export_fds_count);
status = VA_STATUS_ERROR_OPERATION_FAILED;
goto error;
}
+15
View File
@@ -182,4 +182,19 @@ thumb_function tiled_deinterleave_to_planar
b 7b
end_function tiled_deinterleave_to_planar
#else /* __aarch64__ */
/* Fourier-local: aarch64 stub. The body of this file is ARMv7 NEON Thumb
* assembly used by sunxi-cedrus (Allwinner-tiled NV12 linear NV12) and
* is never reached on aarch64 hosts because video_format_is_linear()
* returns true for our NV12 entries. Provide a stub so the shared object
* still resolves the symbol; if ever actually called, return immediately. */
.text
.global tiled_to_planar
.type tiled_to_planar, %function
.hidden tiled_to_planar
tiled_to_planar:
ret
.size tiled_to_planar, .-tiled_to_planar
#endif
+14
View File
@@ -33,10 +33,24 @@
void request_log(const char *format, ...)
{
va_list arguments;
static FILE *trace_fp;
fprintf(stderr, "%s: ", V4L2_REQUEST_STR_VENDOR);
va_start(arguments, format);
vfprintf(stderr, format, arguments);
va_end(arguments);
/* Fourier-local: also tee to /tmp/libva-fourier.log so messages are
* visible from sandboxed GPU processes (Chromium etc.) where stderr
* is redirected. Append-mode, lazy-open. */
if (trace_fp == NULL)
trace_fp = fopen("/tmp/libva-fourier.log", "a");
if (trace_fp != NULL) {
fprintf(trace_fp, "%s: ", V4L2_REQUEST_STR_VENDOR);
va_start(arguments, format);
vfprintf(trace_fp, format, arguments);
va_end(arguments);
fflush(trace_fp);
}
}
+48 -2
View File
@@ -32,6 +32,7 @@
#include <linux/videodev2.h>
#include "utils.h"
#include "v4l2.h"
#include "video.h"
static struct video_format formats[] = {
@@ -45,6 +46,16 @@ static struct video_format formats[] = {
.planes_count = 2,
.bpp = 16,
},
{
.description = "NV12 YUV (multi-plane)",
.v4l2_format = V4L2_PIX_FMT_NV12,
.v4l2_buffers_count = 1,
.v4l2_mplane = true,
.drm_format = DRM_FORMAT_NV12,
.drm_modifier = DRM_FORMAT_MOD_NONE,
.planes_count = 2,
.bpp = 16,
},
{
.description = "Sunxi tiled NV12 YUV",
.v4l2_format = V4L2_PIX_FMT_SUNXI_TILED_NV12,
@@ -59,17 +70,52 @@ static struct video_format formats[] = {
static unsigned int formats_count = sizeof(formats) / sizeof(formats[0]);
struct video_format *video_format_find(unsigned int pixelformat)
struct video_format *video_format_find(unsigned int pixelformat, bool mplane)
{
unsigned int i;
for (i = 0; i < formats_count; i++)
if (formats[i].v4l2_format == pixelformat)
if (formats[i].v4l2_format == pixelformat &&
formats[i].v4l2_mplane == mplane)
return &formats[i];
return NULL;
}
/*
* Probe the V4L2 video device for a supported CAPTURE pixel format and
* return the matching video_format entry. Tries single-plane CAPTURE first
* (the original sunxi-cedrus path: SUNXI_TILED_NV12 or NV12), then falls
* back to multi-plane CAPTURE (Rockchip hantro / RK3588 VDPU381). Returns
* NULL if no match.
*
* Centralised here so RequestInit can populate driver_data->video_format
* before any vaCreateContext call. The original library set it lazily in
* RequestCreateSurfaces, but Chromium's vaapi_video_decoder may call
* vaCreateContext first (with surfaces=NULL, surfaces_count=0) and only
* create surfaces afterwards via vaCreateSurfaces2.
*/
struct video_format *video_format_probe(int video_fd)
{
struct video_format *format = NULL;
if (v4l2_find_format(video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_PIX_FMT_SUNXI_TILED_NV12))
format = video_format_find(V4L2_PIX_FMT_SUNXI_TILED_NV12, false);
if (format == NULL &&
v4l2_find_format(video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_PIX_FMT_NV12))
format = video_format_find(V4L2_PIX_FMT_NV12, false);
if (format == NULL &&
v4l2_find_format(video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
V4L2_PIX_FMT_NV12))
format = video_format_find(V4L2_PIX_FMT_NV12, true);
return format;
}
bool video_format_is_linear(struct video_format *format)
{
if (format == NULL)
+2 -1
View File
@@ -38,7 +38,8 @@ struct video_format {
unsigned int bpp;
};
struct video_format *video_format_find(unsigned int pixelformat);
struct video_format *video_format_find(unsigned int pixelformat, bool mplane);
struct video_format *video_format_probe(int video_fd);
bool video_format_is_linear(struct video_format *format);
#endif