Skip to content

#407: extend the generated-PTS repair to AVI (measured XviD sample) - #517

Open
a1go3 wants to merge 1 commit into
superuser404notfound:mainfrom
a1go3:fix/avi-decode-order-pts
Open

#407: extend the generated-PTS repair to AVI (measured XviD sample)#517
a1go3 wants to merge 1 commit into
superuser404notfound:mainfrom
a1go3:fix/avi-decode-order-pts

Conversation

@a1go3

@a1go3 a1go3 commented Sep 8, 2026

Copy link
Copy Markdown

Fixes #516.

VFWDecodeOrderPTSRepair already describes this failure exactly; its gate was Matroska-only because no AVI had been measured:

Matroska only. AVI carries a FourCC on every track and is DTS-only as well, but the ms_compat/codec_tag equivalence is established in matroskadec and nowhere else, and a VC-1 AVI has not been measured. A gate that is exact on one container beats a guess on two.

Here is the measurement. A 2000s XviD rip — mpeg4 Advanced Simple Profile, tag XVID, 720x304, video_delay = 1, packed B-frames — takes the same transposition, and aetherctl swdecode reports it in the same words the Matroska case did:

before   0.042  0.083  0.167  0.125  0.209  0.292  0.250  0.334  0.417  0.375
         Steps backwards: 12 of 37
         VERDICT: the pictures are paired with the wrong timestamps. The container
                  withheld its PTS and something invented one from decode order (#407).

after    0.042  0.083  0.125  0.167  0.209  0.250  0.292  0.334  0.375  0.417
         Steps backwards: 0 of 37

Why AVI needs no equivalence of its own

avidec has no second mode. The container carries no presentation timestamps at all, every track carries a FourCC, and the demuxer puts the frame index on pkt->dts. So on an AVI input any PTS present was necessarily invented by +genpts — which makes codec_tag != 0 a tautology there rather than a signal, and leaves video_delay > 0 carrying the whole gate.

The Matroska branch keeps its tag condition untouched: there the tag is what separates the VFW-carried tracks that withhold PTS from the natively mapped ones that must keep theirs.

Both existing exclusions hold unchanged in AVI, and are pinned by tests:

  • zero reorder delay — decode order is presentation order, so the invented axis is the right one;
  • H.264 / HEVC / AV1 — they can stay on the native path, where the fMP4 muxer refuses a timestamp-less packet outright.

Ruling out the alternatives on this sample

So the diagnosis does not rest on the verdict alone:

  • Not interlacing. field_order=unknown, and interlaced_frame=0 / repeat_pict=0 on every frame of a mid-file 25-frame window. Toggling deinterlaceMode and deinterlaceFieldRate on device changed nothing, consistent with the deinterlacer correctly never engaging.
  • Not cadence or a damaged rate. best_effort_timestamp_time advances evenly at 0.0417 s with no gaps and no duplicates.
  • Not the decode path. Forcing preferredDecodePath = .software changed nothing.
  • Not the packed bitstream itself. It is the only unusual property of the file, but the pictures decode fine; libavcodec's mpeg4_unpack_bframes suggestion is left alone deliberately — a separate, independent improvement, out of scope for a gate change.

Tests

nonMatroskaContainer pinned the old decision that "avi" must not arm the repair. It becomes ptsCarryingContainer over the containers that genuinely supply timestamps (mov,mp4,…, asf, mpegts), and four AVI cases join the suite: the measured XviD shape, tag-independence, the two shared exclusions, and per-element name matching for isAVI.

Full suite on this branch: 2743 tests in 373 suites, all passing.

Scope

The gate can now arm only on AVI, and only where video_delay > 0 — files that today play with their pictures in the wrong order. Nothing that plays correctly changes behaviour.

Happy to adjust naming or split the test changes if you would rather keep VFW in the type name now that it covers a second carriage.

The gate was Matroska-only for want of a measured AVI. Here is one: a 2000s
XviD rip (mpeg4 ASP, tag XVID, 720x304, video_delay 1, packed B-frames) takes
the same transposition, and `aetherctl swdecode` says so in the same words:

    before   0.042  0.083  0.167  0.125  0.209  0.292  0.250  0.334  0.417
             Steps backwards: 12 of 37
    after    0.042  0.083  0.125  0.167  0.209  0.250  0.292  0.334  0.375
             Steps backwards: 0 of 37

AVI needs no ms_compat equivalence to establish the same fact, because avidec
has no other mode: the container carries no presentation timestamps at all,
every track carries a FourCC, and the demuxer puts the frame index on pkt->dts.
So on an AVI input any PTS present was necessarily invented by +genpts, which
makes codec_tag != 0 a tautology there rather than a signal. video_delay > 0
carries the whole gate; the Matroska branch keeps its tag condition untouched.

Both existing exclusions hold in AVI: zero reorder delay (decode order IS
presentation order) and the natively routable codecs whose packets reach the
fMP4 muxer.

The source is progressive (interlaced_frame 0 and repeat_pict 0 on every frame
of a mid-file window), its timestamps are evenly spaced at 0.0417 s with no
gaps or duplicates, and no deinterlacer is involved: the packed bitstream is
the only unusual property and it is not the cause. The invented axis is.

`nonMatroskaContainer` pinned the old decision that "avi" must not arm the
repair; it becomes `ptsCarryingContainer` over the containers that do supply
timestamps, and four AVI cases join it. Full suite: 2743 tests, 373 suites,
all passing.

Reported as superuser404notfound#516.
@a1go3

a1go3 commented Sep 8, 2026

Copy link
Copy Markdown
Author

Verified on device: iPhone 13 Pro / iOS 26.5, host app built against this branch. The sample that produced #516 now plays with no visible judder — so the fix holds beyond the headless swdecode verdict, on the file the report started from.

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.

AVI with packed B-frames: presentation timestamps derived from decode order (mpeg4/XviD)

1 participant