Frame-accurate preview + seeking (FrameMap frame-mapping seam)#45
Merged
Conversation
Add a FrameMap descriptor (Identity/Fanout/Decimate/Retime) in processing_pipeline.rs as the single source<->output frame-mapping seam: - output_count() drives the progress total, replacing the hardcoded double-rate/IVTC ladder in pipeline_executor.rs (behavior-preserving). - invert()/total_radius() drive the frame-accurate preview window. Worker: generate_preview now takes an integer source frame, decodes a window centred on it, and emits the exact output index it maps to (accounting for QTGMC double-rate) instead of the old "middle of 11" heuristic. Seeks land exactly via center-of-interval ((frame-0.5)/fps); the same fix makes start-frame trimming exact. Flutter: the preview is driven by an integer frame index end-to-end (no time round-trip). FrameMath does the pure position<->frame conversion; the view-model exposes currentFrameIndex/totalFrames/seekToFrame/ stepFrame; the preview panel gains step-by-frame buttons + a frame readout. Before/after now seek to the same source frame. Guard generateProcessedPreview against 0x0 (probe-pending) jobs so a slow first-run ffprobe no longer surfaces a misleading dimensions error. Tests: FrameMap + preview_window unit tests, integration tests 55/56, and FrameMath Dart round-trip tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
StuartCameronCode
added a commit
that referenced
this pull request
Jul 1, 2026
Add a FrameMap descriptor (Identity/Fanout/Decimate/Retime) in processing_pipeline.rs as the single source<->output frame-mapping seam: - output_count() drives the progress total, replacing the hardcoded double-rate/IVTC ladder in pipeline_executor.rs (behavior-preserving). - invert()/total_radius() drive the frame-accurate preview window. Worker: generate_preview now takes an integer source frame, decodes a window centred on it, and emits the exact output index it maps to (accounting for QTGMC double-rate) instead of the old "middle of 11" heuristic. Seeks land exactly via center-of-interval ((frame-0.5)/fps); the same fix makes start-frame trimming exact. Flutter: the preview is driven by an integer frame index end-to-end (no time round-trip). FrameMath does the pure position<->frame conversion; the view-model exposes currentFrameIndex/totalFrames/seekToFrame/ stepFrame; the preview panel gains step-by-frame buttons + a frame readout. Before/after now seek to the same source frame. Guard generateProcessedPreview against 0x0 (probe-pending) jobs so a slow first-run ffprobe no longer surfaces a misleading dimensions error. Tests: FrameMap + preview_window unit tests, integration tests 55/56, and FrameMath Dart round-trip tests.
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.
Summary
Makes the preview frame-accurate and adds frame-accurate seeking, built on a new
FrameMapdescriptor that becomes the single source↔output frame-mapping seam in the worker.FrameMap(worker/src/models/processing_pipeline.rs)enum FrameMap { Identity, Fanout, Decimate, Retime }withoutput_count()(forward) andinverse()(carrying anexactflag).ProcessingPipeline::{frame_maps, output_count, invert, total_radius}compose the per-pass maps. Today: QTGMC double-rate →Fanout{2}; IVTC/soft-telecine →Decimate{cycle, keep}; everything else identity.is_double_rate / is_ivtcprogress ladder inpipeline_executor.rswithpipeline.output_count(vspipe_total)— behavior-preserving (proven by test).Retimevariant with no new special-cases.Frame-accurate preview (worker + templates)
generate_previewtakes an integer source frame, decodes the window[target-radius ..= target+radius](radius =total_radius(), floored atMIN_PREVIEW_RADIUS), and emits the exact output indexoutput_count(local)— replacing the oldclip[num_frames // 2]"middle of 11" heuristic.(frame - 0.5)/fps(with-ssbefore-i), avoiding ±1 PTS-rounding ambiguity. The same fix makes start-frame trimming exact. Window geometry is the pure, unit-testedpreview_window().PREVIEW_INFO:frame=Nback. Stays inside thepipe_sourcestreaming model — no BestSource reintroduced.Flutter
FrameMath(lib/services/frame_math.dart) — pure, stable position⇄frame conversion.currentFrameIndex/totalFrames/seekToFrame/stepFrame; the preview panel gains ◀/▶ step-by-frame buttons + af N / totalreadout.generateProcessedPreviewnow guards against0×0(probe-pending) jobs — a slow first-run ffprobe no longer surfaces a misleading "Invalid video dimensions" error; it self-heals once probing completes.Testing
cargo test --libFrameMap+preview_windowedge cases)cargo test --test filter_integration_testtest_55_preview_selects_exact_frame,test_56_frame_count_mapping)flutter test test/frame_math_test.dartflutter analyze(changed files)Also built and launched the macOS debug app.
Notes
processing_pipeline.rsrow to the CLAUDE.md worker key-files table.🤖 Generated with Claude Code