media: ingest fMP4 from MistServer instead of MKV
The Mist ingest bridge was MKV: an MKVExec process on the Mist side piped
the stream into `streamplace live`, which POSTed it to /live. Matroska
blocks carry only presentation timestamps, so ingest had to RECONSTRUCT
decode timestamps with h264timestamper — which needs to guess a reorder
window. For streams whose SPS declares none (VideoToolbox writes no
bitstream_restriction), it assumes the worst-case full DPB and mints a
constant spurious PTS-DTS offset on streams that never reorder, pushing
every GoP's presentation past its segment's declared window; WebRTC
playback (push-mode qtdemux in packetize clips to that window) dropped
the tail of every GoP — a visible jump at each keyframe. The earlier
B-frame fix (fc52def0) and this bug were two horns of the same dilemma:
with MKV you either trust a guessed window (stretch B-frame streams) or
guess harder (corrupt no-reorder streams).
Sidestep the whole class: never use MKV. MP4 track fragments carry real
decode timestamps (tfdt/trun + ctts), so nothing is reconstructed.
- On PUSH_REWRITE (already the auth point — it mints and caches the
signer), main now PULLS Mist's live fMP4 HTTP output for the stream it
just named (MistPullIngest). The GET is issued by hand so the raw
connection can be fd-passed to the detached worker with prebuf +
chunked flag — the exact contract the old hijacked POST provided, with
the connection pointing the other way. Zero-downtime detach/reattach,
watchdog, ban enforcement, manifest refresh all unchanged.
- buildMKVIngestPipeline -> buildMP4IngestPipeline: matroskademux ->
qtdemux, h264timestamper deleted. MKV*/RunMKV* identifiers renamed MP4*.
- docker/mistserver.json: MKVExec process removed (deploys must set
SP_MIST_HTTP_PORT to Mist's HTTP port, 28080 in this config). The
/live route and `streamplace live` CLI remain, now speaking fMP4.
- Tests ported to fMP4 synthesis (mp4mux fragment-duration=500). The
sparse-video wedge and B-frame regressions carry over; new
videoPTSDTSOffsets probe asserts the archival property directly:
TestMP4IngestMistRealSample runs a real VideoToolbox 720p Mist .mp4
capture (new remote fixture mist-vt-720p.mp4, the stream that repro'd
the bug) and requires PTS == DTS on every video sample of every signed
segment; TestMP4IngestBFramesValidate requires real reorder offsets
are PRESERVED for B-frame streams. MKV-specific nyc-* fixture tests
(M_JSON metadata track, matroskademux wedge cuts) retired with the
format.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
media: ingest fMP4 from MistServer instead of MKV
The Mist ingest bridge was MKV: an MKVExec process on the Mist side piped
the stream into `streamplace live`, which POSTed it to /live. Matroska
blocks carry only presentation timestamps, so ingest had to RECONSTRUCT
decode timestamps with h264timestamper — which needs to guess a reorder
window. For streams whose SPS declares none (VideoToolbox writes no
bitstream_restriction), it assumes the worst-case full DPB and mints a
constant spurious PTS-DTS offset on streams that never reorder, pushing
every GoP's presentation past its segment's declared window; WebRTC
playback (push-mode qtdemux in packetize clips to that window) dropped
the tail of every GoP — a visible jump at each keyframe. The earlier
B-frame fix (fc52def0) and this bug were two horns of the same dilemma:
with MKV you either trust a guessed window (stretch B-frame streams) or
guess harder (corrupt no-reorder streams).
Sidestep the whole class: never use MKV. MP4 track fragments carry real
decode timestamps (tfdt/trun + ctts), so nothing is reconstructed.
- On PUSH_REWRITE (already the auth point — it mints and caches the
signer), main now PULLS Mist's live fMP4 HTTP output for the stream it
just named (MistPullIngest). The GET is issued by hand so the raw
connection can be fd-passed to the detached worker with prebuf +
chunked flag — the exact contract the old hijacked POST provided, with
the connection pointing the other way. Zero-downtime detach/reattach,
watchdog, ban enforcement, manifest refresh all unchanged.
- buildMKVIngestPipeline -> buildMP4IngestPipeline: matroskademux ->
qtdemux, h264timestamper deleted. MKV*/RunMKV* identifiers renamed MP4*.
- docker/mistserver.json: MKVExec process removed (deploys must set
SP_MIST_HTTP_PORT to Mist's HTTP port, 28080 in this config). The
/live route and `streamplace live` CLI remain, now speaking fMP4.
- Tests ported to fMP4 synthesis (mp4mux fragment-duration=500). The
sparse-video wedge and B-frame regressions carry over; new
videoPTSDTSOffsets probe asserts the archival property directly:
TestMP4IngestMistRealSample runs a real VideoToolbox 720p Mist .mp4
capture (new remote fixture mist-vt-720p.mp4, the stream that repro'd
the bug) and requires PTS == DTS on every video sample of every signed
segment; TestMP4IngestBFramesValidate requires real reorder offsets
are PRESERVED for B-frame streams. MKV-specific nyc-* fixture tests
(M_JSON metadata track, matroskademux wedge cuts) retired with the
format.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>