====== Brave 148 ARM64 + Mali-Bifrost / hantro VPU + libva-v4l2-request-fourier — definitive HW video decode wall ====== **Verdict**: Brave-bin on PineTab2 (and structurally on any RK3566/RK3568 Mali-Bifrost + hantro stack) **cannot** engage hardware video decode. The wall is **architectural in chromium**, not in our libva backend, not a flag-combination problem, not a "VAAPI not compiled in" problem. **Brave is unfixable on this hardware without source rebuild — which Brave (closed source) does not permit.** chromium-fourier (the open-source rebrand we maintain in marfrit-packages) IS fixable and DOES engage HW decode on the same hardware. This document supersedes iter11/iter12/iter14 of the panvk-bifrost campaign, all of which produced contradictory and partially-incorrect theories about this wall. ===== Substrate this was measured on ===== * Host: ohm (PineTab2, RK3566 Quad Cortex-A55, Mali-G52 r1 MC1) * OS: Arch Linux ARM, kernel ''linux-fresnel-fourier'' (hantro v4l2-stateless driver) * Brave: 148.1.90.124 (aarch64) * Mesa Vulkan ICD: mesa-panvk-bifrost r4-1 (''%%/usr/lib/panvk-bifrost/libvulkan_panfrost.so%%'') * libva: 2.23.0-1 + libva-v4l2-request-fourier 1:1.0.0.r390.c454618-1 * ''%%/etc/profile.d/libva-v4l2-request.sh%%'' sets ''LIBVA_DRIVER_NAME=v4l2_request'' system-wide * Test file: ''%%/home/mfritsche/fourier-test/bbb_1080p30_h264.mp4%%'' (725 MB, H.264 1080p30) * Measurement date: 2026-05-21 ===== What was measured (verbatim, not inferred) ===== ==== 1. Brave's GPU process loads libva and successfully completes VAAPI initialization ==== ''LIBVA_TRACE=/tmp/brave_libva.log brave ...'' (full launch command at the bottom of this doc) — the resulting trace files in ''%%/tmp/brave_libva.log.*.thd-*%%'' show: [3485.434262] vaInitialize ret = VA_STATUS_SUCCESS [3485.434538] entrypoint = 1, VAEntrypointVLD (H264Main + H264High + H264CB + VP8 + others) [3490.281730] vaInitialize ret = VA_STATUS_SUCCESS (second context, this time for actual decode) [3490.281803] entrypoint = 1, VAEntrypointVLD [3490.719527] [ctx 0x02000000] profile = 6,VAProfileH264Main entrypoint = 1,VAEntrypointVLD Every libva call up to and including decode-context creation returns SUCCESS. **This invalidates** the iter14 memory claim //"%%/proc//maps%%: NO libva libraries loaded at all"//. libva IS loaded; iter14's check (if it was even done) was wrong or measured a different state. ==== 2. Brave's chromium emits the decoder-selection sequence ==== From the brave stderr log: [VERBOSE2:media/gpu/chromeos/video_decoder_pipeline.cc:585] Initialize(): config: codec: h264, profile: h264 main, level: not available, coded size: [1920,1080], visible rect: [0,0,1920,1080], natural size: [1920,1080] ... [VERBOSE2:media/gpu/vaapi/vaapi_video_decoder.cc:136] VaapiVideoDecoder(): [VERBOSE2:media/gpu/vaapi/vaapi_video_decoder.cc:632] ApplyResolutionChange(): [VERBOSE2:media/gpu/vaapi/vaapi_video_decoder.cc:660] ApplyResolutionChangeWithScreenSizes(): **VaapiVideoDecoder is fully constructed and active**. The chromium decoder factory selects it for the H.264 stream. This invalidates iter11/12/14's various "VAAPI not in dispatch" / "VAAPI not compiled in" / "use_vaapi=false on ARM64" theories. VaapiVideoDecoder is in dispatch, is compiled in, and is selected. ==== 3. The libva backend emits a non-fatal probe error ==== v4l2-request: Unable to set control(s): Invalid argument (error_idx=2/2 ioctl-level) This is ''libva-v4l2-request-fourier''’s ''%%src/context.c:587-588%%'': struct v4l2_ext_control dev_ctrls[2] = { { .id = V4L2_CID_STATELESS_H264_DECODE_MODE, .value = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, }, { .id = V4L2_CID_STATELESS_H264_START_CODE, .value = V4L2_STATELESS_H264_START_CODE_ANNEX_B, }, }; (void)v4l2_set_controls(driver_data->video_fd, -1, dev_ctrls, 2); Note: **''(void)'' cast — the return value is intentionally ignored. The comment immediately above the call says "Errors here are not fatal: not every backing driver supports both controls."** This is a startup probe, the message is informational, and brave proceeds past it. Confirmed by the next observation. ==== 4. ffmpeg with the EXACT same backend on the EXACT same hardware decodes successfully ==== LIBVA_DRIVER_NAME=v4l2_request \ ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 \ -i /home/mfritsche/fourier-test/bbb_1080p30_h264.mp4 -t 3 -f null - Result: **decode at 1.56× realtime (frame=72 over 3s, speed=1.56x)**. The same probe error occurs in the ffmpeg trace (''Unable to set control(s): Invalid argument (error_idx=2/2 ioctl-level)'') but ffmpeg proceeds past it and completes the decode using the V4L2 stateless path through the same libva backend. This is the **identical** libva environment Brave just failed in. This conclusively proves that the libva-v4l2-request EINVAL is NOT the wall — same backend, same file, same hardware, same libva environment, ffmpeg decodes, Brave doesn't. The difference is **what each program does after libva**. ==== 5. The actual wall — measured in Brave's stderr ==== [VERBOSE2:media/gpu/chromeos/video_decoder_pipeline.cc:1263] PickDecoderOutputFormat(): Initializing ImageProcessor; max buffers: 16 [ERROR :media/gpu/vaapi/vaapi_video_decoder.cc:1224] failed Initialize()ing the frame pool [VERBOSE2:media/gpu/vaapi/vaapi_video_decoder.cc:144] ~VaapiVideoDecoder(): The chromium ''%%media/gpu/chromeos/video_decoder_pipeline.cc::PickDecoderOutputFormat%%'' path invokes ''%%ImageProcessor::Initialize()%%'' — a **ChromeOS-specific V4L2 m2m chip block** for color conversion / scaling. On a plain Linux + hantro system the ImageProcessor block does not exist, the init fails, and the frame pool that depends on it cannot be created. VaapiVideoDecoder destructs and the decoder factory falls back to FFmpegVideoDecoder (software). ffmpeg does not use the chromeos pipeline; it goes through ''libavcodec'''s direct VAAPI integration without ''ImageProcessor''. That's why ffmpeg succeeds where Brave fails on the identical libva backend. ===== Why this is unfixable in brave-bin ===== ''%%media/gpu/chromeos/video_decoder_pipeline.cc::PickDecoderOutputFormat%%'' is invoked by ''VaapiVideoDecoder'' unconditionally on Linux ARM64 because Brave's chromium build flags are: use_vaapi=true use_v4l2_codec=false The behavior is selected at **build time**, not runtime. There is no ''%%chrome://%%'' flag, no command-line switch, no ''%%--enable-features=*%%'' value that bypasses it. chromium-fourier (our own rebuild) fixes this with the build-flag change ''use_v4l2_codec=true'' plus patch ''enable-v4l2-decoder-default.patch'' (the ''kAcceleratedVideoDecodeLinux'' master-gate fix at ''%%media/base/media_switches.cc:750%%''). Those changes make V4L2VideoDecoder the selected decoder, which does NOT go through the chromeos pipeline and does NOT require ImageProcessor. chromium-fourier was operator-validated 2026-04-26 (see ''%%marfrit-packages/arch/chromium-fourier/NEXT.md%%'') and plays 1080p30 H.264 from BBB on PineTab2 with ''fuser /dev/video1'' confirming hantro engagement. **Brave is closed source.** The Brave organization ships pre-compiled binaries; there is no ''brave-build-from-source'' PKGBUILD that mfritsche maintains. The build-time choice that engages the chromeos pipeline is therefore baked into every brave-bin release. ===== Recommendation ===== - **For HW video decode in a chromium-family browser on PineTab2: use ''chromium-fourier'' instead of Brave.** The package is published to ''packages.reauktion.de'', installable via ''pacman -S chromium-fourier''. It has the patches and DOES engage HW decode end-to-end. - **Do NOT pursue a "make brave HW-decode" campaign.** This is structurally unfixable without rebuilding brave-bin from source, which the closed source license forbids and Brave's distribution model does not support. - **The ''project_brave_arm64_vaapi_wall'' memory is wrong.** It needs replacement with this finding's text. - **iter11/12/14 closes are also wrong** in their root-cause attribution. Don't read them as authoritative; this document is. ===== Future re-investigation triggers ===== This wall could change if: * Brave's upstream chromium drops ''use_v4l2_codec=false'' as a default and routes VaapiVideoDecoder without the chromeos pipeline on plain Linux. (No upstream signal of this as of 2026-05-21.) * Brave switches to a different chromium rebrand model that includes the source-modification capability we have for chromium-fourier. (Brave does not currently do this.) * chromium upstream provides a runtime ''%%--disable-chromeos-pipeline%%'' or equivalent flag. (No upstream signal.) * mfritsche pursues a build-from-Brave-source campaign (out of scope; closed source). Until any of those land, this finding is the campaign result. ===== Full launch command used for the measurements ===== ssh ohm ' export XDG_RUNTIME_DIR=/run/user/$(id -u) export WAYLAND_DISPLAY=wayland-0 XAUTHF=$(pgrep -fa Xwayland 2>/dev/null | grep -oE "/run/user/$(id -u)/xauth_[A-Za-z0-9]+" | head -1) [ -n "$XAUTHF" ] && export XAUTHORITY="$XAUTHF" export DISPLAY=:1 export LIBVA_DRIVER_NAME=v4l2_request export LIBVA_V4L2_REQUEST_VIDEO_PATH=/dev/video1 export LIBVA_V4L2_REQUEST_MEDIA_PATH=/dev/media0 export LIBVA_TRACE=/tmp/brave_libva.log export LIBVA_TRACE_BUFDATA=0 export VK_ICD_FILENAMES=/usr/lib/panvk-bifrost/icd.json export PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 export MESA_VK_VERSION_OVERRIDE=1.2 /opt/brave-bin/brave \ --no-sandbox --disable-gpu-sandbox \ --enable-logging=stderr --v=2 \ --vmodule="*vaapi*=2,*media*=2,*v4l*=2,*video_decoder*=2,*gpu_video*=2,*libva*=2" \ --enable-features=VaapiVideoDecoder,VaapiIgnoreDriverChecks,AcceleratedVideoDecoder \ --use-gl=angle --use-angle=gles \ --autoplay-policy=no-user-gesture-required \ file:///home/mfritsche/fourier-test/bbb_1080p30_h264.mp4 \ >> /tmp/brave_stderr.log 2>&1 & ' — claude-noether, 2026-05-21