diff --git a/src/media_processor.py b/src/media_processor.py index 09330b8..5349f6c 100644 --- a/src/media_processor.py +++ b/src/media_processor.py @@ -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, )