Real-corpus report: standard CompressedVideo MCAP cannot be canonicalized without AUD #149
Replies: 4 comments
|
Thanks for running this. Both your shapes assume a re-encode. I don't think you need one. An AUD is a NAL you insert into the Annex B stream, so the slice data is untouched: That changes the trade. The reason to keep the transform strict is that silently re-encoding changes pixels nobody asked to change. Inserting AUDs doesn't, so option 1 gets much easier to say yes to. One thing to know: AUD is one of four canonical constraints, and your file happens to satisfy the other three. A repair path still has to decide what it does about the rest. Try the lossless insert on this corpus and see whether doctor passes. If it does, the design question mostly answers itself. If you'd rather go straight at one of your two shapes, say so. You're right about the docs. "Any input MCAP in" is not true today whichever way this lands. I'll fix that separately. |
|
Checked this rather than leaving you to find out. I took a canonical episode, stripped the AUDs to imitate your file, and ran the stripped stream back through So the lossless path works and the concatenate-then-re-split shape does too. Caveat: that was 15 messages from our own encoder, not 24,689 from X-Plane. One shortcut if it helps: you already know your message boundaries from MCAP, so you may not need ffmpeg at all. One message is one access unit in your file, so prepending an AUD NAL to each payload gets you there directly. |
|
The lossless path works on the full X-Plane corpus. I implemented it in #184. On the exact 170,784,196-byte file from this discussion (matching SHA-256 The PR keeps all other constraints strict, leaves already-AUD-delimited messages byte-for-byte unchanged, covers protobuf and ROS2 CDR envelopes, and bumps the transform behavior version because canonical output bytes change. |
|
#184 is merged, so this is resolved. Transform now inserts a missing AUD losslessly and refuses everything else as before. One thing worth recording here rather than leaving in the PR: repairing a missing AUD quietly broke the multiple-access-unit check, because that check counted AUDs and a payload holding two frames read as one after repair. William fixed it by counting pictures from Thanks for running the corpus and measuring the round-trip rather than asserting it. That is what made this a small change instead of an argument. |
Uh oh!
There was an error while loading. Please reload this page.
Context
Following the steer in the review of #148, I ran HFlow against a public corpus rather than taking another starter issue. I checked the existing discussions and open PRs first; this is distinct from #48's WebDataset/LeRobot ingestion boundary.
Environment:
Corpus:
What is in the file
The MCAP is readable and indexed:
The first decoded video payload reports format h264 and has Annex B NAL types [6, 7, 8, 5] (SEI, SPS, PPS, IDR). The next two have [1]. There is no type 9 access-unit delimiter.
What breaks
A full doctor pass finishes quickly and diagnoses the file accurately:
Wall time: 0.67 s.
The transform cannot turn this otherwise readable standard MCAP into a canonical episode:
app.process()fails in 0.033 s on the first video message. This is expected from the implementation: CompressedImage is transcoded, while foxglove.CompressedVideo is validate-only pass-through.So the real-corpus boundary here is one level deeper than #48: the container and schema get through the door, but a common valid H.264 representation cannot cross the canonicalization boundary.
What is fast
The indexed MCAP summary and full doctor scan are fast. This is not a scanning-performance problem; it is a transform-capability/contract problem.
What is awkward
The module-level transform contract says "any input MCAP in", and the quickstart invites "any standard MCAP". A user with a standard foxglove.CompressedVideo MCAP can reasonably expect canonicalization to bridge HFlow's stricter H.264 requirements, but the existing path only explains after ingestion starts that re-encoding must happen upstream.
The useful part of the failure is that it is immediate and precise. The awkward part is that HFlow provides no preparation path for this already-MCAP case.
Design question before code
I see two honest shapes:
I have not started either implementation. Which boundary would you prefer? If the standalone-tool shape is preferred, I would start with this one corpus and prove that doctor passes after round-trip before generalizing.
All reactions