Decode clean-aperture sources at their full stored size, never resampled - #106
Open
StuartCameronCode wants to merge 1 commit into
Open
StuartCameronCode wants to merge 1 commit into
StuartCameronCode wants to merge 1 commit into
Conversation
pal-sd-25.mov is 720x576 per ffprobe but carries a QuickTime clean-aperture (clap) atom. FFmpeg 7.1+ applies container cropping by default, so it decoded at 702x576, and the decoder's `-s 720x576` (added to stop the resulting raw-stream desync) silently rescaled the crop back to 720: the source was cropped and resampled, 2.6% stretched, before any filter ran. - New worker/src/source_decode.rs builds both decoders (encode + preview): `-apply_cropping codec` before -i (drop container crop, keep the SPS crop ffprobe's width/height already include), no -s, and a size-guard crop filter that passes the probed size untouched and fails the decode on any other size, including a mid-stream resolution change. The worker reports that failure with an explanation ahead of vspipe/encoder errors. - The worker probes width/height when a job omits them, instead of the 720x480 fallback the guard would now reject (and -s used to squeeze to). - The app's before-frame and thumbnails decode the same full frame (PreviewGenerator.sourceDecodeOptions). - Tests: source_decode unit tests on the emitted args; heavy integration_clean_aperture_test.dart requires a passthrough FFV1 encode of the clap MOV (and an MKV PixelCrop remux) to be bit-identical to a full-frame decode, and a mid-stream size change to fail with the explanation. All three fail against the previous worker. - CLAUDE.md rule + dated write-up in docs/ENGINEERING_NOTES.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GLXdGLfPwgYjW1AkonGqN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
Since FFmpeg 7.1, ffmpeg applies container crop metadata by default.
pal-sd-25.mov(720×576 ProRes with a QuickTimeclapatom) decodes at 702×576; the decoder's-s 720x576then rescaled it back to 720. So every clean-aperture source was cropped and stretched 2.6% horizontally before any filter ran, still stamped with the source SAR. MatroskaPixelCropbehaves the same.Fix
-apply_cropping codecand no-s: the pipeline sees exactly ffprobe's size, and the user's Crop controls are the only crop. (nonewould be wrong — H.264 1080p decodes at 1920×1088.)claphint in the output; an 8/9 Crop gives the same picture.cropfilter is a no-op at the right size (bit-identical) and fails the decode otherwise. The worker reports the guard failure before the vspipe/encoder status, sincepipe_sourcewould otherwise pad a short stream into a "successful" job.fill_frame_size). The old 720×480 fallback plus-swas squeezing sources;integration_video_trimming_testhad been turning a 720×576 AVI into 720×480 and passing.PreviewGenerator.sourceDecodeOptions).Behaviour change: a source that changes resolution mid-stream (e.g. DVB 720→544 at an ad break) was silently rescaled and now fails the job with an explanation.
Tests
source_decodetests;preview_integration_testreference now decodes the full frame unscaled.integration_clean_aperture_test.dart: clap MOV and an MKVPixelCropremux come through bit-identical to a full-frame decode; a mid-stream 720→544 TS fails with the explanation. All three fail without the fix.cargo testgreen except the whisper test (add-on not installed); full heavy suite 391 pass (the 2 restart tests needVAPOURBOX_WORKER, then pass);--exclude-tags heavygreen exceptvapoursynth_integration_test, which can't finddeps/from a worktree.Not verified: Windows/Linux/macOS x64 (all pinned to FFmpeg 9.0, which has the option); no newly authored clean-aperture file (ffmpeg can't write the metadata).
Docs: new "Source Frame Size" rule in CLAUDE.md; dated write-up in docs/ENGINEERING_NOTES.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_014GLXdGLfPwgYjW1AkonGqN