Skip to content

IVTC: fallback deinterlace for leftover combing - #99

Open
StuartCameronCode wants to merge 1 commit into
update-trackingfrom
ivtc-fallback-deinterlace
Open

StuartCameronCode wants to merge 1 commit into
update-trackingfrom
ivtc-fallback-deinterlace

Conversation

@StuartCameronCode

Copy link
Copy Markdown
Owner

Summary

Implements the feature scoped earlier for a user bug report: an IVTC source with a broken 3:2 cadence at scene changes (and some field-blended dissolves) leaves residual combing after VFM/VDecimate alone, because those frames simply couldn't be cleanly field-matched.

  • New opt-in ivtcFallbackDeinterlace toggle (IVTC method only, default off): patches any frame VFM flagged as still combed with a QTGMC deinterlace of that same frame, instead of leaving it combed.
  • New ivtcFallbackPreset (default Fast, not the general Slower QTGMC default — this runs a full second QTGMC pass on top of an already-slow IVTC pass).
  • Applies to both the encode and preview scripts, so the preview shows what the real output will look like.

Mechanism

Before wiring anything up, I probed the actual bundled vivtc plugin (not assumed from memory or docs) to confirm the two behaviors this depends on:

  • VFM stamps a _Combed frame property on every frame — already true today, just unused elsewhere.
  • VDecimate accepts a clip2 kwarg: decimation decisions come from clip, output frames come from clip2. VFM itself already uses this exact idiom (its own 8-bit-metrics / full-depth-output split), so this isn't a new pattern for this codebase.

Script shape: VFM runs unchanged → a parallel QTGMC pass deinterlaces the full source at single rate → FrameEval builds a hybrid clip that swaps in the QTGMC frame wherever _Combed is set → VDecimate(clip, clip2=hybrid, ...) keeps its drop timing from the plain VFM clip but takes output frames from the hybrid. The preview template has no VDecimate call (single-frame), so the hybrid clip replaces clip directly there instead.

With the toggle off (default), the generated script is byte-for-byte what it was before this feature existed.

Test plan

  • Probed the real bundled vivtc.dylib directly via vspipe (not just documentation) to confirm VDecimate's clip2 parameter and VFM's _Combed property both exist as expected
  • cargo test — full suite green (161/161 in filter_integration_test.rs; the one pre-existing failure elsewhere, test_subtitle_generation_srt_file, is a local missing-whisper-addon environment gap, unrelated)
  • 4 new Rust tests: fallback script shape, custom preset/TFF, preview-path parity, and the off-by-default byte-identical guard
  • 2 new Flutter script-generation tests in integration_filter_parameters_test.dart
  • flutter analyze clean on every touched file
  • flutter test --exclude-tags heavy — 942 passed, 0 failed

Base branch is update-tracking (this branches off it, per the parent conversation) rather than main — rebase onto main once that one merges.

🤖 Generated with Claude Code

https://claude.ai/code/session_014GLXdGLfPwgYjW1AkonGqN

Implements the feature scoped for Rob's bug report (broken 3:2 cadence
at scene changes, field-blended dissolves): a new opt-in
ivtcFallbackDeinterlace toggle patches frames VFM couldn't cleanly
field-match with a QTGMC deinterlace of that frame, instead of leaving
them combed. Off by default (roughly doubles the pass's cost).

Mechanism, probed against the actual bundled vivtc plugin before
wiring up (not assumed from memory, per house rule):
- VFM already stamps a _Combed frame property on every frame; this
  reads it, doesn't add it.
- VDecimate accepts a clip2 kwarg — its drop decisions come from
  `clip`, its output frames come from `clip2`. VFM itself already uses
  this exact idiom for its own 8-bit-metrics/full-depth-output split.
- A parallel QTGMC pass + FrameEval builds the hybrid clip that
  VDecimate's clip2 then draws from. The preview template has no
  VDecimate call (single frame), so the hybrid replaces `clip` there
  directly instead.

ivtcFallbackPreset defaults to Fast rather than QTGMCPreset's general
Slower default, since this pass runs on top of an already-slow IVTC
pass.

Touches: Rust model + script generator + both templates (encode and
preview, so the preview shows what the real encode will produce),
Dart model + converter, the deinterlace filter schema, a Rust
integration test, and a Flutter script-generation test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014GLXdGLfPwgYjW1AkonGqN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant