Repository navigation
Guard AV1 sample descriptions in MP4 - #12
Conversation
Check the profile, first operating-point level/tier and colour-sampling fields represented by av1C against every emitted Sequence Header. Reuse FFmpeg's extract_extradata BSF; let the first actual output sequence supply the MP4 description, including fully re-encoded selections. Keep compatible smart-rendered middles. If MP4's single stsd entry cannot describe a changed configuration, close the first attempt and retry the selected video fully re-encoded, once only. Explain in the log that this supersedes the initial copy plan. Audio and subtitle modes are unchanged. Only the mp4 output muxer enables the guard. MKV/WebM keep their existing logic; their sequence-header handling policy is left to the maintainer to decide separately. Do not include SAR, source-clock/VFR or M2TS changes. Add six guard unit tests and an 18-export suite registered in CI. On identical inputs, the new suite improves from 15/18 to 18/18, and the historical MP4 matrix from 38/55 to 45/55 without a new failure. Workspace tests: 576 passed, four known Windows baseline failures filtered; clippy workspace/all-targets exits 0 with the existing warnings.
|
Thank you, and for the FFmpeg 8/9 notes. I built this on Linux (Debian 13, FFmpeg 7.1) and ran What actually differs is only the level Looking at
Profile, tier, bit depth, monochrome and chroma position agree in every case, including the 10-bit libaom source. On this branch, two of the three ( I would rather not re-encode the whole video for that. The v0.8.39 output decodes strictly with no errors, and the copied pictures are the source's own bytes. Since only the level differs, could the boundary sequences be made to carry the source's level instead?
Level 31 means "no level constraint", so writing it over the boundary's 2.0 does not claim anything untrue. When the source states a real level that is lower than what the boundary encoder chose, the rewrite would be a lie, and that case, along with any profile / bit-depth / chroma mismatch, is where your guard and the full-video fallback make sense. So my proposal is: keep the extraction and the field check from this PR, align the level at the seams, and fall back to full re-encoding only for the mismatches that cannot be aligned. For those, the automatic fallback as you wrote it, with its log lines, is fine with me. On FFmpeg 8/9: agreed that this belongs in a separate change. Thank you for checking the 9.0.2 behaviour. |
An MP4 cut mixing a rav1e source with SVT-AV1 boundaries can keep its original pictures when only the boundary's declared level differs. Use the source or active sequence fields for mixed exports and promote a compatible boundary level, including the source's unconstrained index 31. Update both the extracted configuration and the sample OBU, including the conditional tier bit, trailing bits and OBU size. Preserve packet properties and copied access units. Keep the existing single retry for conflicting configurations, a lower target level, or finite promotions whose constraints cannot be established. Fully encoded selections use the encoder's actual configuration. Exercise both seam orders, a finite promotion, a real chroma mismatch, and the original rav1e partial and multi-range reproductions. Inspect each sequence with FFmpeg and compare the copied key packets and pixels.
|
Thanks for pinpointing the level mismatch. I implemented the Sequence Header rewrite you suggested in On the same fixtures, Mixed cuts still fall back to a full re-encode when the source specifies a lower finite level than the boundary encoder, or when fields such as bit depth or chroma position differ. I rebuilt with FFmpeg 7.1.1 on Windows and all 21 cases passed, including the three Matroska controls and a chroma mismatch that exercises the fallback. |
|
Thank you, this is exactly what I hoped for. I built Confirmed
One question on The 3.1 → 4.0 exclusion looks unnecessary to me. MinCR is MinCrBasis × (DecodedSampleRate ÷ MaxDisplayRate), and in Table A.3 MainCR ÷ MaxDisplayRate does not increase with the level anywhere: 2 ÷ 31,950,720 at 3.1, 4 ÷ 70,778,880 at 4.0, so the 4.0 bound is looser. Since the exclusion only makes such a cut fall back to a full re-encode, it isn't wrong, and I don't mind keeping it. If you had a different constraint in mind, a word on which one would help me keep the comment accurate; otherwise feel free to drop it. A tiny nit, no need to act on it: in the I'm happy to merge this as it is. If you'd rather adjust the |
|
A follow-up after the merge, so you know what changed in your code. Our review of In
Boundaries written by rav1e 4:4:4, 4:2:2 and 12-bit sources go to rav1e, because SVT-AV1 can't encode them. rav1e writes The full-video retry
With these, |
A mixed rav1e/SVT-AV1 MP4 cut now keeps 192 of 214 pictures for the partial selection and 144 of 195 for the two-range selection. Both used to retry with the whole selection re-encoded. The source declares level index 31 (no level-based constraints), while the boundary encoder declares index 0 (Level 2.0). Review reproducer and discussion
The FFmpeg 7.1 writer still extracts each Sequence Header and checks the fields shared by the single MP4 sample description. When the output mixes copied and encoded pictures, the writer can raise the level in an encoded boundary to match the copied configuration. It updates both in-band OBUs and packet extradata, handles the conditional tier bit and reduced still-picture syntax, and rewrites the trailing padding and OBU size when needed. Copied access units stay byte-identical. A wholly encoded selection uses the encoder's actual configuration.
A lower finite target, a change in profile, tier, bit depth or chroma, or conflicting copied sequences still triggers the existing logged full-video retry. Finite promotions must be provably compatible. Explicit decoder models and Level 3.1 → 4.0, which can tighten the minimum compression ratio, take the conservative retry path. AV1 levels
Validation on the final merged tree used an actual Windows x64/MSVC release build, Rust 1.98 and FFmpeg 7.1.1.
This is the AV1/MP4 split from #10. Matroska/WebM policy remains a separate maintainer decision. The branch includes current upstream main with #11 and retains both CI suite entries. Technical details
The FFmpeg 8.x/9.x upgrade remains a separate follow-up for incompatible configurations. Those MOV muxers support mapping packets with new extradata to different sample descriptions. In the earlier 214-packet remux, 9.0.2 selected entries 2 → 3 → 2 with zero mismatches and every packet preserved. FFmpeg 7.1.1 produced one description and two mismatches. The 8.x result comes from source inspection. FFmpeg 8.0 MOV writer · FFmpeg 9.0.2 MOV writer