Skip to content

saneSAR admits small-but-wrong ratios: bound the resulting display aspect, not just the components #290

Description

@kskchaitanya1993

saneSAR bounds each SAR component to 256, which catches the pathological values (the 1088:1 the comment mentions) but still admits small-but-wrong ratios that stretch the picture into an unwatchable strip.

Observed on a live 1080p H.264 IPTV channel that declared SAR 3:1, then 2:1 on a later run — both well inside the existing gate. 3:1 applied to 1920x1080 yields a 5.33:1 display aspect; 2:1 yields 3.55:1. The picture renders as a horizontally smeared band. The user-visible workaround is switching the aspect mode to Fill, which is a real tell that the ratio itself is wrong rather than the content being unusual.

The magnitude gate can't distinguish these, because the problem isn't the size of the numbers — it's the aspect they produce.

What we do locally

Bound the resulting display aspect rather than the component magnitudes, in the same helper:

static func saneSAR(_ sar: AVRational) -> AVRational? {
    guard sar.num > 0, sar.den > 0, sar.num <= 256, sar.den <= 256 else { return nil }
    // Reject an implausibly extreme pixel aspect (e.g. a bogus 3:1 that stretches 1920x1080 into a
    // 5760x1080 strip). No real PAR stretches a frame more than ~2.5x on either axis.
    let ratio = Double(sar.num) / Double(sar.den)
    guard ratio <= 2.5, ratio >= 1.0 / 2.5 else { return nil }
    return sar
}

Rejecting returns nil, which falls back to square pixels — for a stream lying about its SAR that is the correct picture, and for a stream telling the truth it's never reached, since no legitimate PAR is that extreme.

On the threshold

2.5 is a judgement call and I'd expect you to want a different one. The widest genuine PARs in circulation are the anamorphic DVD/broadcast set — 16:11 (~1.45), 12:11, 64:45, and the 4:3-into-16:9 cases around 1.8 — so 2.5 leaves a lot of headroom above anything real while still rejecting the 3:1 above. Verified on our side that legitimate anamorphic content is unaffected: a 720x576 PAL source at 16:11 still resolves to ~16:9 and renders correctly.

This refines the gate you added in #177 rather than replacing it — both checks are useful, they just catch different failures. Raising as an issue rather than a PR since the bound is a policy choice; happy to send it either way.


This issue was auto-generated by Claude on behalf of @kskchaitanya1993.

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