Posting this because the symptoms look like three unrelated bugs, the error messages point nowhere useful, and I could not find a correct explanation anywhere. It took a while to track down.
Symptoms
The file plays perfectly in VLC, MPC-HC, PotPlayer, Windows Media Player. Then:
- ffprobe / ffplay reports a multi-gigabyte video as Input #0, png_pipe a 1x1 image, no duration
- NVDEC / PyNvVideoCodec: cuvidCreateVideoParser(...) returned error 300
- OpenCV: Could not find decoder for codec_id=61, then a missing-duration crash
Three toolchains, three unrelated-looking errors, one cause. Nobody searching for one of them ever finds the others, which is most of why this stays unexplained.
What is in the file
The video is intact nothing corrupt, nothing missing. There is a small image glued to the front:
The PNG is a 1x1 fully transparent pixel. It renders as nothing at all. Not a broken thumbnail no visual purpose whatsoever. That is the shape of a tracking beacon: something meant to be requested, not seen.Code:[ 70-byte PNG ][ ...valid MPEG-TS stream... ] ^ byte 0 ^ real video starts here
Some CDNs attach this to every segment response. Concatenating the segments, which is what every HLS downloader does, puts one copy at byte 0. I counted the PNG signatures across a 3.4 GB affected file and got 1188 one per segment. The other 1187 are harmless: an MPEG-TS demuxer resynchronizes on the next sync byte and skips straight over them. Only the copy at offset 0 breaks anything.
Sizes vary. Current samples are 70 bytes with no padding; files from early 2025 use about 120 bytes plus 85 bytes of 0xFF filler, so the payload starts at 205 rather than 70. Do not hardcode an offset.
Why the split behavior
Tolerant players scan forward looking for something they recognise, find the stream, and play it without ever mentioning the prefix. Strict parsers trust byte 0: ffprobe matches the PNG signature and reports an image, NVDEC gets bytes that are not a video stream, OpenCV asks for a PNG decoder (codec_id=61 is AV_CODEC_ID_PNG) and falls over.
Fixing it
Not a re-encode. The video was never damaged you locate where the real stream begins, copy from there to EOF, and rewrap. Runs at disk speed, no quality loss.
By hand, once you know the offset:
...but you still have to strip the prefix first, and the offset varies per file.Code:ffmpeg -fflags +genpts -i input.ts -map 0:v:0 -map 0:a:0 -c copy -movflags +faststart output.mp4
I wrote a tool that does the whole thing: CleanStreamTS (Windows, MIT, single installer, GUI and CLI). Point it at a folder; it queues anything repairable automatically and writes clean copies alongside. Originals are never modified.
Verified rather than assumed on a 1.3 GB file the video bitstream MD5 is identical before and after, with matching frame counts (119742 video / 187288 audio) and the same duration to the microsecond. The only structural change is moving the container index to the front, which also makes the result seek instantly instead of reading to EOF first.
It will not guess
MPEG-TS packets start with 0x47 every 188 bytes, but a single 0x47 occurs roughly once per 256 bytes of arbitrary data it proves nothing on its own. The tool only accepts a payload when the sync byte recurs at eight consecutive 188-byte-aligned positions. A decoy prefix over something unrecognised is reported and left alone, because writing a file from a guessed offset would turn a recoverable file into a broken one.
Two things worth separating
Removing the prefix fixes the parser failures. It does not give you a file an HTML5 <video> element can play browsers cannot play raw MPEG-TS regardless, so anything with a browser-based preview still needs the MP4 remux above. Those are independent problems and I spent a while conflating them.
Prevention
The cleaner path is not writing the prefix in the first place. liveDownload strips it from each segment at download time, so its output needs no repair. Validated rather than assumed: the same title downloaded raw with the strip active and repaired offline with CleanStreamTS both process end-to-end in lada with identical frame counts (119742), and the raw stripped file also passes a full NVDEC-based pipeline with zero decode errors. Other downloaders write exactly what the server sent which is the whole problem.
Reporting variants
The tool's scan output masks filenames by default (first ten characters plus a short hash) so it can be pasted publicly. If you get one reported as decoy_prefixed_unknown_payload, that is a variant I have not seen the scan line and, if you can capture it, the .m3u8 manifest would be useful.
Posting this because the symptoms look like three unrelated bugs, the error messages point nowhere useful, and I could not find a correct explanation anywhere. It took a while to track down.
+ Reply to Thread
Results 1 to 6 of 6
-
Last edited by gsadasivan; 27th Aug 2026 at 20:32.
-
Can you show some manifests where the media segments show this issue? Does it only concern HLS manifests, or also DASH mpds?
I have not understood why media publishers or CDNs would be doing this. They can use CMAF fragmented MP4 segments to share the same segments between HLS and DASH streams. If they still need to use MPEG-TS for old clients, I don't understand the point of the prefixed image data. -
this is common: https://github.com/nilaoda/N_m3u8DL-RE/blob/main/src/N_m3u8DL-RE/Util/ImageHeaderUtil.cs
also, another AI slop postBypass HMACs, One-time-tokens and Lic.Wrapping: https://github.com/DevLARLEY/WidevineProxy2 -
I haven't encountered this issue in developing dash-mpd-cli, perhaps because this isn't used for DASH streaming, but I'm curious and can't find any information on the motivation for this online. If anyone can share a public manifest or example media segments on a CDN I'd be interested.
-
@larley thanks for that link, genuinely. It is the best public evidence in this thread. For anyone who does not read C#: that file is N_m3u8DL-RE's segment handler for exactly this phenomenon. It detects four image types glued to the front of media segments (PNG, GIF, BMP, JPEG), and for PNG it carries four hardcoded decoy sizes 69, 120, 771 and 6102 bytes with a fallback that scans for the 0x47 TS sync byte recurring at 188-byte intervals when none of the known sizes match. My samples (70 bytes current, ~120 + 85 bytes of 0xFF padding from early 2025) sit right in that family, and the padded variant is why scanning beats fixed offsets: slice a known size off the front and the padding still lands at byte 0.
So yes common enough that the most-used m3u8 downloader ships a workaround with a list of known decoys in it. What I could not find anywhere is a written explanation of the failure signature why the same file plays in VLC, reports as a 1x1 image in ffprobe, kills NVDEC with error 300 and OpenCV with codec_id=61. Three toolchains, three vocabularies, no cross-reference. That gap is what this thread is for, and it being searchable is the point.
@pteque good questions, in order:
HLS only, or DASH too? Everything I have observed is HLS with MPEG-TS segments, and I think there is a structural reason it stays there. The trick is only free where players tolerate it: a TS demuxer (and hls.js's transmuxer) resynchronises on the next 0x47 and skips the junk, so real playback never breaks. Fragmented MP4 has no resync a parser walks box lengths from byte 0, so a prefixed image would break the site's own players via MSE. A publisher doing this on DASH/CMAF would DoS themselves. Your not encountering it in dash-mpd-cli is consistent with that, not a gap in your testing. You are right that CMAF would let a legitimate publisher unify HLS/DASH but the operators doing this are not standards-minded publishers; they are grey-market streaming hosts where TS is entrenched, and TS's resync tolerance is precisely what makes the trick invisible.
Why do it at all? I cannot prove intent, so here are the two explanations that fit the bytes, for whatever they are worth. (1) Content-type camouflage: the response carries genuine image magic bytes, so anything that sniffs content CDN rules, traffic classifiers, corporate proxies, hosting terms that treat video differently from images sees an image. Video riding image-classified paths is an old trick and this is a cheap way to survive magic-byte checks. (2) Scraper-breaking that costs players nothing: naive tooling that feeds segments or concatenated output to strict parsers falls over, while every real player scans past it. I will note honestly that my opening post leaned on the "tracking pixel" framing; having since established the image rides on every segment response rather than being fetched separately, camouflage fits better than tracking nothing extra is ever requested. I have updated my view; the repair is identical either way.
Can I share a manifest? Not usefully as links: the URLs are tokenised with ~24h validity, and the hosts serve adult content, which I am not going to link here. What I can give you is everything needed to reproduce the failure signature without any site involved. The current 70-byte decoy, byte-exact:
That is a complete, valid PNG: 1x1, RGBA, fully transparent, minimal chunk set (IHDR + IDAT + IEND). Reproduce the whole phenomenon in three commands:Code:89504e470d0a1a0a0000000d49484452000000010000000108060000 001f15c4890000000d49444154789c6360606060000000050001a5f6 45400000000049454e44ae426082
Then:Code:python -c "open('decoy.png','wb').write(bytes.fromhex('89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c4890000000d49444154789c6360606060000000050001a5f645400000000049454e44ae426082'))" ffmpeg -f lavfi -i testsrc=duration=5:size=320x240:rate=25 -c:v libx264 -f mpegts seg.ts python -c "open('poisoned.ts','wb').write(open('decoy.png','rb').read()+open('seg.ts','rb').read())"reports png_pipe, 1x1 a five-second test video the size of a movie, identified as a single pixel. VLC plays it fine. That is the entire bug in miniature.Code:ffprobe poisoned.ts
The manifests themselves are unremarkable, which is part of what took so long to see: a plain media playlist, ~400 #EXTINF entries of ~10s each, no EXT-X-MAP, every segment URI on one CDN host. Nothing in the manifest hints at anything the prefix is applied to the segment responses, which is why counting PNG signatures across a finished 3.4 GB file returns 1188, one per segment. Since the tokens expire quickly, if you like, I can PM you a link that a user sent me, upon request.
Similar Threads
-
Checking Proposed Reduction of Video Quality Using ffplay
By meeshu in forum Software PlayingReplies: 11Last Post: 29th Jun 2025, 09:46 -
Tool for automatic sync fix?
By eXtremeDevil in forum SubtitleReplies: 6Last Post: 13th Nov 2024, 15:33 -
Looking for a shader in MPC-HC like OpenCV's Background Subtractor
By SubtractionNonAction in forum Newbie / General discussionsReplies: 0Last Post: 24th Aug 2024, 13:42 -
MP4 files with QT Audio fail in Avidemux
By abeelandig in forum EditingReplies: 11Last Post: 9th Nov 2023, 06:50 -
Which tool can fix Youtube subtitles?
By Chetwood in forum SubtitleReplies: 1Last Post: 11th Apr 2023, 07:50


Quote