Fix mobile black-screen-in-fullscreen: normalize negative DTS on remux
The faststart fix (f8842f8) handled the moov-atom position but missed a
second issue in the same merged video+audio stream: the video track's first
packet has a slightly negative DTS (from B-frame reordering across the
merge), confirmed via ffprobe on the actual failing video (-0.083322s).
Reported symptom after the faststart fix was already live: preview thumbnail
fine, black screen on opening fullscreen on Telegram's mobile app, but
picture visible in PiP mode - consistent with the hardware-accelerated
fullscreen decoder path choking on it while PiP's path (apparently software)
tolerates it. Desktop played it fine regardless.
Adds -avoid_negative_ts make_zero to the same lossless -c copy remux pass
(no extra cost - it's the same command). Verified on the actual video:
first packet DTS goes from -0.083322 to -0.000322 (down to B-frame rounding
noise, not a real negative start anymore).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+13
-7
@@ -172,18 +172,24 @@ class MediaProcessor:
|
||||
|
||||
async def _apply_faststart(self, path: Path) -> Path:
|
||||
"""Moves the moov atom to the front with a fast, lossless remux (-c copy - no
|
||||
re-encode, just repositions the index). Needed because muxing a separate
|
||||
video+audio stream (see _select_format's "+bestaudio" case) leaves the moov atom
|
||||
at the end by default: confirmed on a real post where the result played audio
|
||||
with a black video, because streaming players (notably Telegram's mobile clients)
|
||||
can't render video without seeking to the index first. Falls back to the original
|
||||
file - rather than dropping the video - if ffmpeg fails for any reason."""
|
||||
re-encode, just repositions the index and timestamps). Needed because muxing a
|
||||
separate video+audio stream (see _select_format's "+bestaudio" case) leaves the
|
||||
moov atom at the end by default, AND leaves the video track starting at a
|
||||
slightly negative DTS (its first frame is a B-frame reordered before the
|
||||
keyframe's PTS) - confirmed on a real post where the result played audio with a
|
||||
black video on Telegram's mobile app in fullscreen (but rendered fine in PiP,
|
||||
which apparently tolerates it - a strong hint the hardware decoder path is what
|
||||
chokes on it) while desktop played it fine either way. -avoid_negative_ts
|
||||
make_zero fixes the second half; without it, moov-only faststart wasn't enough.
|
||||
Falls back to the original file - rather than dropping the video - if ffmpeg
|
||||
fails for any reason."""
|
||||
fixed_path = path.with_name(f"{path.stem}_fs.mp4")
|
||||
await register_active_path(fixed_path)
|
||||
proc = None
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
"ffmpeg", "-y", "-i", str(path), "-c", "copy", "-movflags", "+faststart",
|
||||
"ffmpeg", "-y", "-i", str(path), "-c", "copy",
|
||||
"-avoid_negative_ts", "make_zero", "-movflags", "+faststart",
|
||||
str(fixed_path),
|
||||
stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user