Skip to content

fix(encode): derive png-seq frame index from task position, not a shared atomic #129

Description

@LeadcodeDev

Part of #123. File: crates/rustmotion/src/encode/video/formats.rs

The PNG sequence writer permutes frames

formats.rs:45:

let frame_num = counter.fetch_add(1, Ordering::Relaxed);

The index comes from a shared atomic in rayon's scheduling order, not the task's position, so frames are permuted within each batch by ±(2·ncores−1).

Verified: two runs of the same input differ on 114 frames (max mean-abs 12.4/255); --threads 1 output is byte-identical to the --frame N path; multi-threaded output is a strict permutation of it (identical multiset, 436/486 misplaced, displacement −19..+18). It raises the measured noise floor 9.4× and manufactures fake spikes around transitions — it corrupted an earlier analysis before being caught.

mp4 and gif are unaffected: those paths use the counter only for progress, and rayon's collect preserves order.

Fix: derive the frame index from the task's position (enumerate over the batch plus the batch base) rather than the atomic.

Acceptance

  • Two multi-threaded runs of the same input produce byte-identical sequences.
  • Multi-threaded output is byte-identical to --threads 1.
  • Prove both by hashing the sequences, not by inspection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions