The software Main 10 path narrowed HDR10 pictures to 8 bits as they were, so
PQ shown as SDR looked grey and BT.2020 colours dull. hdr_tonemap.h maps
brightness with BT.2390's EETF (203 cd/m2 reference white = SDR white,
highlights rolled off up to MaxCLL / the mastering peak / 1000 cd/m2) and
converts colour per chroma sample through linear light into BT.709, moving
out-of-gamut colours toward grey of the same luminance. The component then
prefers its bitstream colour aspects, so surfaces and its RGBA conversion see
BT.709. Bands run in the colour helper threads (about 10 ms per 1080p picture
on one big core). Decoder revision 10; artifacts rebuilt with build.py.
Iris on the Frame's kernel (6.18) offers HEVC Main 10 only into its
compressed Q10C capture format. The component always asks for NV12, and a
Main 10 stream in such a session returned no pictures: playback stayed at
0:00, the flush on leaving timed out (ACodec -110) and the next video hit
MediaCodec::reclaim, so every later decoder start in the app failed until it
restarted (seen in Bigscreen Beta with local files over DLNA).
- hevc_profile.h reads general_profile_idc from the parameter sets
(CODECCONFIG or the first access unit, Annex B or hvcC); streams beyond
Main never open Iris and decode in FFmpeg's software HEVC decoder, which
the component already contains.
- Its 10-bit planar pictures are rounded to 8-bit planar before the existing
outputs (no HDR tone mapping).
- The HEVC component lists Main 10 (level 5.1), so format-aware players
select it instead of reporting NoSupport and using it anyway.
- Decoder revision 9; artifacts rebuilt with native/hevc/build.py (the same
toolchain rebuilds revision 8 byte for byte).
Tested on a Steam Frame in Bigscreen Beta: 1080p and 4K Main 10 clips and a
real 1080p Main 10 episode play; 8-bit HEVC and H.264 afterwards play too.
FFmpeg's software HEVC decoder on the Frame's CPU, 4 threads as the
component uses: 1080p Main 10 episode 232 fps, synthetic 4K Main 10 72 fps.
Iris returns an empty capture buffer (bytesused 0, no LAST flag, time 0) for every VP9 frame that isn't shown
(alt-ref frames split from superframes). FFmpeg's V4L2 wrapper takes any empty capture buffer during a drain
for the end of the stream, so the first hidden frame decoded after EOS ended it and the pictures still in the
driver were lost (two-pass VP9 4K: 573/600 and 617/640, always the last frames); outside a drain the empty
buffers were returned as pictures, which the component then guessed away by counting hidden frames.
build.py now patches v4l2_context.c to requeue empty capture buffers without LAST/ERROR; the drain ends at the
LAST buffer, or after a skipped empty buffer at one silent second, so it can't block. The component's
hidden-frame counting is removed. Dev Frame (Batman's container): two-pass VP9 4K 600/600 and 640/640 in
hardware with the same Y hashes as OMX.google.vp9.decoder (seek phase too), VP9 without hidden frames,
H.264 4K and HEVC 4K 600/600, VP9 surface output 600/600. Two builds (different dirs and NDK copies) give the
same libstagefrighthw.so 141de01f.
- Opt-in per game: only launchers of games whose recipe has frame.hw_video_decode (install stage, no APK change;
suggested from analysis media_codec, ANALYSIS_VERSION 8) get the codec line (deployment.json hw_video_decode,
finalize + upgrade_launchers). Games that had agent 70's per-game codec (Batman) keep it; their old
<base>/frameport-codec folders are removed afterwards. Batman: catalog + migration batman_video_patches
(frame.hw_video_decode + the hidden adapter setting surface_native, no more package check); 4XVR catalog.
- Off switch: Settings -> Installing "Hardware video decoding" (library video.hw_decode, default on) -> agent
video_codec_switch (video-codec/disabled, checked by the launcher line and the wrapper); FRAMEPORT_NO_HW_VIDEO=1
for one game.
- Connection: the codec is checked once per connection, also after a failed install; a Frame keeps the same or a
newer revision built elsewhere (logged) instead of flip-flopping between PCs.
- Wrapper: the merged media_codecs.xml goes to $XDG_RUNTIME_DIR/frameport-video, never into the version directory.
- Decoder: refused (busy) Iris sessions retry until 20 s after the plugin loaded (SteamVR's link holds a session
~12 s at game start), else 2 s, before the software fallback; VP9 capped at 4096x2304 (XML + component, larger
decodes in software); hidden VP9 frames' pictures dropped. Manifest revision 7.
- build.py builds from paths with spaces and from freshly extracted FFmpeg sources. Artifacts rebuilt here, identical
from two trees (ext4 and the NTFS repo path, two NDK copies); PR #128's own sources rebuild to its binary.
- AGENT_VERSION 71 (matches the connection's gate); triage hw-video-decoder-busy, PLAYBOOK row, docs.