With ambient lighting enabled, ASS subtitles anchored to a corner (and PGS
bitmaps) rendered against the whole screen instead of the video: the effect
stretches mpv's frame to the window with video-aspect-override and lets the
shader composite the real picture inside it, and mpv places subtitles against
that stretched frame.
The pinned libmpv now carries --sub-video-rect-aspect (edde746/mpv-build
ec08018), which makes mpv derive its subtitle margins from the picture's real
aspect inside the displayed rect. AmbientLightingService hands it the video
aspect before overriding the frame, so a libmpv without the option refuses
cleanly with the frame untouched, and resets it on disable.
Verified on a Pixel 7 (2400x1080) with a 16:9 file whose OP credits are
\pos-anchored: subtitle extents are pixel-identical with ambient lighting on
and off, and mpv reports OSD borders l=240 r=240 for the overridden frame.
close#2120
High-bitrate HEVC episodes showed smeared frames and green flashes for the
first 10-15 seconds of playback on the Fire TV Stick 4K Max 2nd gen with the
mpv backend, while ExoPlayer played the same file cleanly (#2227). The
reporter's clip failed at exactly two timestamps on every run: the two IDR
frames larger than 1 MiB.
The FFmpeg mediacodec decoder never set "max-input-size" on the codec
format, so OMX.MTK.VIDEO.DECODER.HEVC allocated 1,052,672-byte input buffers
and FFmpeg split any larger packet across several queueInputBuffer calls.
The MediaTek VPU treats each buffer as a complete access unit, rejects the
remainder ("invalid u4BufferAccumulated"), fails the slice and conceals with
lost-picture references until the next IDR. ExoPlayer is unaffected because
media3 sizes HEVC input buffers at max(2 MiB, w*h*3/4) and never splits a
sample.
Move the native pin to edde746/mpv-build@83879375c9, which sizes the
buffers the same way ExoPlayer does for H.264, HEVC, MPEG-4, VP8, VP9 and
AV1 and logs a warning if a packet still does not fit. Verified on the
AFTKRT with the reporter's clip: zero VPU errors and no lost pictures across
repeated runs, and an H.264 file with ~1 MB keyframes still plays on the
MediaTek AVC decoder; both files also play on a Pixel 7 (Exynos C2). Apple,
Linux and Windows assets are unchanged (their content keys did not move).
close#2227
Playing lossless passthrough audio (TrueHD, DTS-HD MA) on an Nvidia Shield
running Android 9 dropped a video frame every ten to twenty seconds with the
mpv backend, while lossy passthrough and PCM were unaffected and A/V sync
never moved (#2202).
IEC 61937 and raw passthrough tracks in ao_audiotrack never use
AudioTimestamp; their clock is AudioTrack.getPlaybackHeadPosition() taken at
face value, which on a direct track is the HAL's render position and
advances in HAL-period steps - 8192 frames at 192 kHz (42.7 ms) for the HBR
output on the Shield, longer than a 24p frame. The AO thread samples it once
per chunk and feeds it straight into the end time mpv schedules video
against, so a forward snap larger than a frame's remaining lead makes mpv
drop that frame; lossy passthrough runs at 48 kHz where the period stays
below a frame.
Move the native pin to edde746/mpv-build@af74e1906e, which estimates the
passthrough position the way media3 does: a ten-sample average of
(head - clock) offsets taken at least 30 ms apart, so a period-sized step is
spread over the window instead of landing on one frame. PCM tracks keep
their AudioTimestamp path. Apple, Linux and Windows assets are unchanged
(their content keys did not move).
Dolby Vision profile 7 titles (UHD Blu-ray remuxes, typically TrueHD or
DTS-HD MA) never showed a frame on the Fire TV Stick 4K Max 2nd gen with the
mpv backend: the spinner stayed forever while audio came up. Profile 8.1
titles carrying HDR10+ on the same device went fully black, controls
included, with audio playing.
Both are the FFmpeg mediacodec DV packet filter. It emitted every rewritten
access unit with a five-byte "00 00 00 00 01" start code - the leading zero
was copied once as head bytes and again as part of the first NAL region -
and MediaTek's VPU rejects such units ("H265_decode invalid NALU"), so the
profile 7 conversion and strip paths both produced nothing. And the filter
never dropped in-band HDR10+ SEI, which these chipsets cannot take next to
the RPU on the native DV decoder (#1296 on the ExoPlayer path).
Move the native pin to edde746/mpv-build@0ad6388c, which counts that zero
once and strips the ST 2094-40 SEI whenever a video/dolby-vision decoder is
selected. Verified on an AFTKRT with the published armeabi-v7a asset: a
P7.6 remux sample decodes on both the HEVC (strip) and DVHE.STH (convert)
paths with no VPU errors, and a P8.1 + HDR10+ remux plays on the DV decoder
with a single output-format change. Apple, Linux and Windows assets are
unchanged (their content keys did not move).
close#2176
Enabling Deinterlacing had no effect on Android and Android TV for
interlaced MPEG-2 (and any other software-decoded stream): mpv asks
libavfilter for bwdif, and the pinned Android and Linux FFmpeg builds were
configured with --disable-filters, so the request failed with
"filter 'bwdif' not found" and the frame passed through combed. Windows
and Apple ship FFmpeg with the filter, which is why the same file
deinterlaced on Windows.
Move the native pin to edde746/mpv-build@9bfbcd69, which builds bwdif into
the Android and Linux FFmpeg. Apple and Windows assets are unchanged
(content-addressed keys did not move). Verified on a Shield TV Pro with the
published arm64 asset: 480i MPEG-2 now deinterlaces cleanly.
close#2224
AAC/AC3/EAC3 5.1 tracks at 44.1 kHz played as stereo through mpv on Android:
ao_audiotrack sized its buffer as 75 ms aligned to the sample size, which at
44.1 kHz is not a whole number of 6-channel frames, so AudioTrack refused it
("Invalid audio buffer size") and mpv fell back to the stereo-only OpenSL ES
output. 48 kHz sources (DTS, or audio-samplerate=48000) happened to align.
Pin mpv-build 1779135, which frame-aligns the audiotrack PCM buffer
(edde746/mpv-build@d89cfbb). Only the Android libmpv key moves.
close#1445
Plezy consumed mpv through four unrelated supply chains: an MPVKit fork
via SwiftPM for the Apple platforms, a libmpv-android fork's AAR for
Android, an in-CI from-source build for Linux, and an unpinned
sourceforge mpv-dev 7z for Windows. All four now consume the same
per-commit, content-addressed binaries from
https://github.com/edde746/mpv-build, pinned to one commit and built
from one set of pinned sources (mpv v0.41.0 on Apple/Android/Windows,
ffmpeg n8.0.1, our libass fork).
- Apple: the SwiftPM package moves from edde746/MPVKit to
edde746/mpv-build across the ios/macos/tvos projects;
scripts/set_mpvkit_revision.sh becomes set_native_revision.sh, writes
every pin site plus the new repo-root mpv-build.lock.json, and
tvos/scripts/wire_mpv.rb derives the package repo from the locks.
- Android: the mpv Kotlin API and JNI glue move in-app under
android/libmpv (repackaged com.edde746.plezy.libmpv, exports renamed,
shrinker rules covered), and the module downloads per-ABI native
tarballs (lib/*.so incl. libc++_shared.so + include/) driven entirely
by mpv-build.lock.json, with a PLEZY_LOCAL_MPV_DIR escape hatch for
locally built artifacts. The fork AAR and its Maven coordinates are
gone.
- Linux: CI downloads the prebuilt self-relocating libmpv prefix
(lock-driven, sha256-verified) instead of compiling mpv/ffmpeg/dav1d/
libplacebo/shaderc from source; linux/packaging/build-libmpv.sh and
its test are deleted and native-inputs.json shrinks to the simdutf
entry the CMake builds still fetch.
- Windows: both arches FetchContent the mpv-build dev zips with
URL_HASH enforcement, replacing the checksum-less sourceforge
download and its ARM64 7-Zip special case; guard scripts updated.
The lock plus the Apple pin sites all point at mpv-build commit
d7c3d559, whose manifest was verified asset-by-asset against the
published release digests (17/17 match). Verified locally: wire and
pin-script suites green, runtime-input checks green, all four Android
ABI tarballs downloaded/verified/extracted through the real Gradle
tasks, the Windows FetchContent block exercised end to end through
cmake, the Linux asset hash and layout checked against the workflow
contract, and xcodebuild resolved the flipped SwiftPM graph with
SwiftPM validating every binary checksum.
Some HEVC files carry a frame Apple's hardware decoder refuses to decode
(kVTVideoDecoderBadDataErr on an otherwise conformant P-frame). mpv fell
back to software decoding for the rest of the file after the first error,
and 4K HEVC software decode drops frames every few minutes on Apple TV.
MPVKit b8b922ec carries an mpv vd_lavc patch that keeps the configured
fast fallback while probing but lets a hardware decoder that has already
delivered frames ride out a mid-stream error burst: the burst one
undecodable frame causes ends at the next keyframe by construction, so
fallback now requires errors to survive two keyframe intervals. Verified
against the reporter's sample: playback logs "Hardware decoding
recovered after 90 errored frames" and stays on VideoToolbox instead of
switching to software.
close#2167
MPVKit publishes binaries for every commit on its main branch now, so a
version tag is no longer the only resolvable thing. Pinning the revision
means a fork fix is consumable as soon as its binaries land, with no release
ceremony there and no version bump here.
Pinned at 0097fea015fe, which carries the PiP subtitle fix: the iPadOS
Picture-in-Picture window no longer resizes when SRT subtitles appear and
disappear. Nine pin sites move together -- three project.pbxproj
requirements plus the six SwiftPM locks that check_apple_spm_locks.py keeps
in agreement.
tvos/scripts/wire_mpv.rb no longer hardcodes the version it writes; it reads
the revision out of the tvOS project's committed lock, so re-wiring the
tvOS target cannot silently revert the pin. Its test asserts the shape and
that all nine sites name one commit, rather than a literal sha, so moving
the pin stays one command:
scripts/set_mpvkit_revision.sh <40-char sha>
close#2078
With Audio Passthrough on, (E-)AC-3 Direct Play on Apple TV degraded
into a repeating buzz after roughly half an hour and never recovered
(a 31.25 Hz comb: one stale 32 ms frame looping). During preroll the
system's Dolby pipeline probes the fake endless resource at a fixed
~183 MiB offset; the AO satisfied it with fabricated copies of the
latest access unit, and CoreMedia cached that range by stream offset
and planned its sequential reads around it. Once playback reached the
cached bytes (33 min at 768 kb/s, 40 min at 640 kb/s) it played the
fabricated frames, and its next read landed past the write head, where
the loader kept fabricating frames forever. Seeks rebuild the item at
offset zero, which is why exit/resume bought another 30-40 minutes.
MPVKit 1.0.26 refuses loader reads past the write head instead of
fabricating data; the pipeline falls back to a plain sequential read
from the write head and prerolls normally with nothing poisonous
cached.
Verified on an Apple TV 4K gen 3 with an HDMI capture rig: the 1.0.25
sink audibly and loggably degrades at stream byte 0x0B770000 (8.3 min
into a 3072 kb/s accelerant stream, 40 min at 640 kb/s), while the
1.0.26 sink crosses the same byte with continuous audio on both the
accelerated stream and a full 40-minute 640 kb/s Plex Direct Play soak
through Plezy itself.
close#1776
With Audio Passthrough on, every (E-)AC-3 track on Apple TV dropped
100-220ms of audio every 1.79s. The system pipeline behind the
compressed AVPlayer path reads unboundedly far ahead of the playhead
and consumes its buffer in fixed ~1.8s quanta; the AO's 2s feed lead
meant each refill overran the write head and the renderer skipped the
missing audio to stay on clock. Bitrate- and route-independent, and
invisible to the AO: item status, time control, and the feed margin
all stayed clean while the sink output gapped (#1300, #1776).
MPVKit 1.0.25 feeds the elementary stream 8s ahead of the observed
playhead -- 4x the pipeline's refill quantum -- sizes the ES window
from the configured lead, exposes it as
--ao-avfoundation-compressed-lead, and keeps waiting during preroll
while a slow source (a realtime-pinned server transcode) is still
making priming progress instead of abandoning Atmos for PCM.
Verified on an Apple TV 4K gen 3 with an HDMI audio capture rig
against EAC3 768k and 640k streams: 21 dropouts/min on 2.15.0, zero
across 10.7 minutes with the new lead; a 997Hz sine encoded as EAC3
through the full passthrough path is statistically identical to
first-party AVKit playback of the same tone; a rate-limited server at
0.95x realtime now prerolls late on the compressed path instead of
downgrading, and once the lead is filled mpv's cache pauses absorb
the deficit with the margin intact.
Direct Play of any (E-)AC-3 track on Apple TV developed persistent
micro-stutter: mpv's audio clock was derived from es_pts on the
compressed path, which is credited a whole 32 ms burst the moment a
payload lands, sawtoothing the clock on a ~0.8 s cycle that video
retires as visible skip/hold pairs. AAC content was unaffected, which
is why the symptom tracked Dolby audio and survived every VO-side fix.
MPVKit 1.0.23 measures the clock from IEC samples actually handed to
ao_read_data instead. Verified with an HDMI capture rig against the
CI-built binary: EAC3 display cadence is now statistically identical
to AAC (was 47.6 skips/min plus 453 multi-frame holds over 38 min).
close#1776
Direct Play on Apple TV develops recurring micro-stutter that worsens
the longer playback runs and clears temporarily on pause/play
(issue #1776). Since 2.4 the avfoundation VO has presented frames
against a media-time CMTimebase anchored and rate-servoed to follow
mpv's audio-slaved schedule; clock skew between the two domains can
only be retired by rate slewing or a re-anchor snap that retimes every
queued frame at once. The media timebase exists for PiP, which tvOS
does not have.
Bump MPVKit to 1.0.22 and opt tvOS into its new
avfoundation-presentation=host mode: samples carry mpv's scheduled
display time against a free-running host-clock timebase, so drift is
absorbed per frame inside mpv and no timing state accumulates in the
VO. The queue lead returns to 128ms; 500ms only dampened media-mode
snaps and quadrupled their blast radius. 1.0.22 also paces the
compressed-passthrough feed off the most-advanced playhead reading,
fixing the periodic audio dropouts passthrough users reported on 2.14.
AC3/EAC3 playback could stutter after AVFoundation began handling compressed streams. Decline compressed formats in macOS AVFoundation so mpv falls through to CoreAudio, while retaining AVFoundation for PCM and the tvOS Dolby path.
close#1940
Picks up two vo_avfoundation fixes: keep the displayed frame across
seek resets, and refuse Core Image geometry rendering for Dolby
Vision passthrough frames (defense in depth - the app already keeps
mpv video-zoom at 0 on iOS/tvOS and zooms the display layer instead).
Brings in the AVFoundation audio output's bounded PCM lookahead, which
is compiled in on macOS only. AVSampleBufferAudioRenderer holds roughly
1.7s of audio there, and mpv multiplies --volume into the samples as it
hands them over, so a volume change stayed inaudible until that backlog
drained. The bound cuts the queue to about 450ms, measured; tvOS and
iOS preprocess to the source they had before the patch, so the deep
buffering their AirPlay path relies on is untouched.
Also carries the Dolby-conformant compressed EAC3 sink from 1.0.15.
Groundwork for #1300. Establishes the session, buffering and route
handling Dolby's application guide prescribes, and adds the diagnostic
arm needed to find out whether Apple's sample-buffer renderer can carry
Atmos objects at all.
Audio session, per the guide's sequence:
- Adopt the long-form playback profile in one atomic call at app launch
and activate the session there. The SDK only accepts that policy with
category Playback, a Default/MoviePlayback/SpokenAudio mode and no
options, so it cannot be assembled from separate calls.
- Report the resolved rendering mode in the player, hidden unless the
system resolves it. Apple only resolves it for CarPlay and AirPlay, so
an unresolved value means unknown, never "not Dolby".
Diagnostics (Apple TV only, Settings > Video Playback > Atmos Output Test):
- Add a sample-buffer arm. It reads the asset with AVAssetReader at
outputSettings nil and hands the untouched compressed buffers and the
untouched format description straight to the renderer, with a variant
that rebuilds the description the way playback builds it. Every
existing mode went through AVPlayer, so nothing exercised the path
playback actually uses; this is what tells us whether the renderer or
our construction is at fault.
- Add an AirPlay route picker. AirPlay is the only route where the system
resolves the rendering mode and the supported channel layouts, so it is
what makes those observations reachable at all, and the AVPlayer arms
now allow external playback so every arm can be compared on the same
destination.
- Add a session-mode toggle for the one profile difference between the
guide and previous playback behaviour.
- Report the session profile, supported layouts, both format
descriptions, the magic cookie and the renderer status, and release the
session on stop so a failed run cannot contaminate the next one.
Also bumps MPVKit to 1.0.14, which carries the matching audio output
work: the channel layout AVFoundation itself uses for Dolby content, a
renderer-failure observer so the fallback to PCM can actually run, the
prescribed feed ordering and preroll, flush recovery that re-supplies the
discarded audio instead of shifting later audio into its place, and
capability-driven fallback on route and capability changes.
This does not yet fix#1300. Whether the sample-buffer renderer can carry
JOC is still unknown; it removes every difference from the documented
setup that could explain the failure, and gives us the arm to answer it
on real hardware.
When the display/system sleeps with a video paused, the window server
stops completing CAMetalLayer presents and mpv's MoltenVK swapchain wedges,
pinning one core at 100% until the app exits. occlusionState does not
reliably change on display sleep, so observe NSWorkspace screensDidSleep/
Wake to hide the metal layer (and drop the playback activity) while dark,
restoring on wake with a forced redraw when paused to avoid a stale frame.
Pairs with MPVKit v1.0.10, which gates libmpv presentation on the layer's
hidden state (check_visible) so presents actually stop while hidden.
Routes all single-layer DV profile 8 (incl. compat 0) through the Apple
DV decode path, so VideoToolbox decodes it in hardware as true Dolby
Vision instead of failing over to software HDR10. Refs #1262.