Skip to content

VFR: separate frame positions and durations - #591

Draft
MuhammadBilalKhan267 wants to merge 11 commits into
Breakthrough:mainfrom
MuhammadBilalKhan267:fix/569-vfr-inaccurate-frame-nums
Draft

MuhammadBilalKhan267 wants to merge 11 commits into
Breakthrough:mainfrom
MuhammadBilalKhan267:fix/569-vfr-inaccurate-frame-nums

Conversation

@MuhammadBilalKhan267

Copy link
Copy Markdown
Collaborator

Addresses #569. Targets 0.8.

This draft begins replacing FPS-based frame/time conversions with explicit frame positions and durations. FramePosition carries a frame’s ordinal and timestamp; FrameDuration carries a frame count and exact elapsed time.

Implemented so far:

  • Added the new types, shared frame-or-time input parsing, rational time calculations, and timecode formatting.
  • Centralized position tracking and RELATIVE/SOURCE frame numbering in VideoStream, removing duplicated backend position getters.
  • Updated PyAV, OpenCV, and MoviePy reads, resets, and seeks. Separated internal decoding from public reads so seek preroll can preserve numbering correctly.
  • Updated PyAV EOF recovery, fan-out position propagation, and concat position tracking, seeks, and source-span mapping.
  • Migrated StatsManager to integer frame keys with timestamp metadata for CSV export.
  • Migrated ThresholdDetector, retaining a local fade-position buffer to resolve split points to observed frames without a global frame index.

Remaining work includes FlashFilter, the other detectors, SceneManager, API/CLI integration, and outputs. Known backend timestamp limitations and final-frame duration handling remain deferred.

Focused timecode tests pass. Existing backend, detector, and integration tests still need porting, and end-to-end validation is pending.

Feedback on the types, numbering and seek semantics, and local buffer approach would help guide the remaining migration.

- Centralize frame numbering and position tracking in VideoStream.
- Update backend reads, seeks, resets, and stream wrappers.
- Migrate StatsManager and ThresholdDetector to FramePosition.
- Add shared input parsing, exact time calculations, and local fade buffering.
- Preserve frame/time minimum units through shared input parsing.
- Check frame counts or exact elapsed time without FPS conversion.
- Retain original frame positions for delayed cuts.
- Update the SceneDetector contract and related documentation.
@MuhammadBilalKhan267

Copy link
Copy Markdown
Collaborator Author

FlashFilter and the base SceneDetector interface are now ported to FramePosition. Minimum-length checks use FrameDuration, preserving whether the input specifies frames or elapsed time. FPS conversions have been removed from these checks, while the MERGE/SUPPRESS state transitions remain unchanged.

The existing 240-FPS estimate remains for callback-image buffering. It does not control cut-duration checks. Removing it requires coordinated changes to SceneManager and detector buffer handling, so that work is deferred until the SceneManager port.

- Replace FrameTimecode with FramePosition for detector inputs and returned cuts.
- Rename timecode parameters to position in ContentDetector and FlashFilter.
- Preserve frame positions in the rolling buffer, detected cuts and stats.
- Parse minimum scene lengths once and compare frames or exact elapsed time.
- Add SceneDetector.meets_minimum for frame and time comparisons.
- Preserve frame positions in detected cuts and stats.
- Parse minimum scene lengths once and use the inherited duration check.
- Preserve frame positions in detected cuts and stats.
- Parse minimum scene lengths once and use the inherited duration check.
- Preserve original frame positions through prediction buffers and detected cuts.
- Remove PTS/FPS-based timecode reconstruction.
- Run FlashFilter once per real prediction, including non-cut frames.
- Mark startup and EOF padding with None to exclude artificial frames from cut detection and filter state.
@MuhammadBilalKhan267

Copy link
Copy Markdown
Collaborator Author

Ported all detectors to FramePosition. Added SceneDetector.meets_minimum() to compare a duration against a parsed minimum in frames or seconds.

TransNet now passes every real prediction through FlashFilter, including non-cut frames needed to complete MERGE filtering.

- Use FramePosition for scene boundaries and callbacks.
- Add peek_timecode across backends and stream wrappers.
- Check frame/time limits before every read, including skipped frames.
- Report progress in frames or seconds.
- Forward detect() inputs directly and align position-pair aliases.
- Update documentation for the changed contracts.
@MuhammadBilalKhan267

Copy link
Copy Markdown
Collaborator Author

Ported SceneManager to FramePosition and added peek_timecode() across all backends and wrappers. Cutoff checks, progress reporting, and detect() are updated. CLI, outputs, and test migration are next.

This branch has not been deployed

No deployments
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