Fix VOD thumbnails on flat-MP4 blobs: let muxl resolve fragment offsets master
generateThumbnail read the midpoint segment at seg.Offset, but for the flat-MP4 VOD shape ([flat-header][fragments]) those offsets are fragment-relative. Every read landed a whole synthesized header early -- 5,112,085 bytes, inside the moov, on the blob this was found with -- and gstreamer reported only "This file is invalid and cannot be played." Metafile.FlatHeaderSize exists for exactly this, and the HLS byte-range generator was its only consumer; the thumbnail path was never updated when the flat-MP4 shape landed. Tests missed it because ProcessToDiscard (the vod-test engine) and TestGenerateThumbnail both store bare fragments, where FlatHeaderSize is 0 and the omission is invisible. Rather than add the header size at this call site -- the same arithmetic that was forgotten once already -- hand muxl the random-access handle and the segment's index coordinates and let it produce the bytes: muxl unwrap <blob> --offset <fragment offset> --count 1 muxl owns the layout it synthesized, so it owns the arithmetic. It also derives the segment's extent from its own uuid boundaries, so no length is passed, and an offset that misses a boundary is a loud error instead of a silent read of whatever bytes live there. Reads stay lazy: pulling one GoP out of the 1.6 GB blob reads 742,390 bytes to return 740,326. Which coordinate space the offsets are in stays the metafile's to declare -- FlatHeaderSize is set for the flat shape, and zero for legacy [init][segments] blobs whose offsets are already absolute -- so both shapes are handled, and both are covered by tests. Pins muxl to the merge of streamplace/muxl#5, which adds unwrap's --offset/--count and the ReadSegments/fs.FS binding this depends on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>