You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Android] Video with non-square SAR (pasp / VUI) is silently downscaled to display size — 3840×2160 SAR 1:2 produces a 1920×2160 texture; request option to ignore SAR #2490
Any other Media Player component configuration required to reproduce the issue.
Which output component(s) are you using?
No response
Any other component configuration required to reproduce the issue.
No response
The issue
Summary
When a video carries a non-square Sample Aspect Ratio, the Android player produces its output texture at the SAR-adjusted display size instead of the coded size. For a 3840×2160 file with SAR 1:2 the texture is 1920×2160 (3840 × ½ = 1920, height untouched). Half the horizontal pixels of every frame are discarded before the app can access them. There is no API to detect or disable this.
The OS-native player (Meta's media player) renders the same bytes at full 3840×2160 on the same devices.
Scope of reproduction: Quest 2 and Quest 3; Vulkan and OpenGLES 3; Texture and XRCompositionLayer output modes; VP9 Profile 0 (8-bit) and HEVC Main (8-bit). The only property that matters is SAR 1:2, carried in the mp4 pasp box and/or the HEVC VUI (aspect_ratio_idc = 255 / Extended_SAR, sar 1/2).
Steps to reproduce (self-contained — no file download needed)
Generate a bug file and a control file. Identical pixels; only the SAR tag differs:
:: BUG file — SAR 1:2 lands in BOTH the container pasp box and the HEVC VUI:
ffmpeg -f lavfi -i testsrc2=size=3840x2160:rate=30 -t 5 -vf setsar=1/2 -c:v libx265 -crf 28 -pix_fmt yuv420p -tag:v hvc1 repro_sar12.mp4
:: CONTROL file — same content, SAR 1:1:
ffmpeg -f lavfi -i testsrc2=size=3840x2160:rate=30 -t 5 -vf setsar=1/1 -c:v libx265 -crf 28 -pix_fmt yuv420p -tag:v hvc1 control_sar11.mp4
Play each with ExoPlayer + BGRA and log the produced texture size (e.g. TextureProducer.GetTexture().width).
Expected: both produce a 3840×2160 texture; SAR (if honored at all) applied at display time or exposed to the app.
Actual: the control produces 3840×2160; the SAR 1:2 file produces 1920×2160.
Evidence from our production app (Quest kiosk / 360 player)
File | Codec / bits | SAR | Texture produced
-- | -- | -- | --
3840×2160 (web-sourced) | VP9 P0, 8-bit | 1:2 (pasp) | 1920×2160
Same content re-encoded | HEVC Main, 8-bit | 1:2 (propagated into VUI by ffmpeg/x265) | 1920×2160
4096×2048 control (unrelated content) | HEVC, 8-bit | 1:1 | 4096×2048 (correct)
Same HEVC bytes, SAR rewritten to 1:1 losslessly (-c copy -bsf:v hevc_metadata=sample_aspect_ratio=1/1 -aspect 3840:2160; decoded-frame md5 stream verified bit-identical) | HEVC Main, 8-bit | 1:1 | 3840×2160
Applog lines from our device, unfixed vs fixed file:
[ORACLE-BUG] <-- paste the 1920x2160 line here
[ORACLE-FIXED] <-- paste the 3840x2160 line here
[ORACLE-Q3] <-- paste the Quest 3 line here
The last table row is the decisive experiment: not one pixel of the bitstream changed (framemd5-identical decode), only the SAR tag — and the texture width doubled. Since this reproduces across both graphics APIs, both output modes, and two different SoCs, the behavior sits in the shared native path below those splits (the C# side reports plane dimensions straight from AVPPlayerGetTexture).
We run the BGRA (non-OES) path; we have not tested whether the OES fast path is also affected.
Why we believe this needs a change
SAR-awareness is legitimate for flat video display, but the current implementation:
Is destructive — it downscales rather than applying aspect at draw time (or upscaling), permanently discarding detail.
Is silent — nothing in the API reports that the texture is not the coded resolution. This cost us a multi-week investigation across codecs, bit depths, graphics APIs and devices before we found the cause.
Is wrong for VR/360 content — the projection mapping defines geometry, so SAR must not resample the source. Web-sourced VR files not uncommonly carry incorrect pasp tags; ours implies a nonsensical 8:9 display aspect for equirectangular content, which the OS player ignores.
Diverges from the platform's native player on the same device and file.
Contradicts AVPro's own cross-platform design — when Windows/Media Foundation had the inverse PAR problem (Pixel Aspect Ratio not respected when using Media Foundation #1237), the fix kept the unscaled texture and rendered stretched to the correct DAR at display time via DisplayUGUI/DisplayIMGUI/ResolveToTexture. The Android path pre-bakes the aspect into the texture instead.
Request
Preferred: always produce the texture at coded resolution and expose SAR through the API so applications apply it at display time — matching ExoPlayer's own model (VideoSize.pixelWidthHeightRatio) and Unity's VideoPlayer. Alternatively a PlatformOptionsAndroid flag such as ignoreSampleAspectRatio. At minimum, if resampling stays the default for back-compat, make it non-destructive (upscale, never downscale) and emit a log line stating the texture was resized due to SAR.
Worth noting the plugin's own design already follows the model we're asking for: AVPPlayerVideoTrackInfo carries dimensions, transform, stereoMode, bitsPerComponent and yCbCrTransform — display-geometry metadata carried as data for the application to apply, rather than baked into pixels. A pixelAspectRatio field alongside transform would be a small, consistent extension rather than a new concept. (Related question: does dimensions report coded or SAR-adjusted size for these files? If it reports coded size while the texture is the adjusted size, that's an internal inconsistency in itself.)
There is also an asymmetry worth flagging: per #1945, on Android the container's rotation/display transform is not applied (users reported transform coming back as identity and had to supply ExoPlayer's matrix manually), yet the container's SAR is applied, destructively. Two members of the same metadata class treated in opposite ways.
Related existing issues (searched first — this does not appear to be a duplicate)
:: Audit a library:
ffprobe -v error -select_streams v:0 -show_entries stream=sample_aspect_ratio -of csv=p=0 file.mp4
:: anything other than 1:1 or N/A is affected
Comparing the Same Videos on 2 different players o2svrplayer(AVPro) & horizon
Screen captures: o2svrplayer(AVPro):
Tets_07_A-com.canopycreative.o2svrplayer-20260707-014309_g.jpg
Native horizon media player:
Tets_07_B-com.oculus.horizonmediaplayer-20260707-014643-g.jpg
Unity version
2022.3.60f1
Unity editor platform
Windows
AVPro Video edition
Core
AVPro Video version
3.4.0
Device hardware
Quest 2 & 3
Which Android OS version are you using?
14
Unity Graphics API
Vulkan, OpenGLES 3
Video API
media3/ExoPlayer
Texture format
BGRA
Audio output
System Direct
Any other Media Player component configuration required to reproduce the issue.
Which output component(s) are you using?
No response
Any other component configuration required to reproduce the issue.
No response
The issue
Summary
When a video carries a non-square Sample Aspect Ratio, the Android player produces its output texture at the SAR-adjusted display size instead of the coded size. For a 3840×2160 file with SAR 1:2 the texture is 1920×2160 (3840 × ½ = 1920, height untouched). Half the horizontal pixels of every frame are discarded before the app can access them. There is no API to detect or disable this.
The OS-native player (Meta's media player) renders the same bytes at full 3840×2160 on the same devices.
Scope of reproduction: Quest 2 and Quest 3; Vulkan and OpenGLES 3; Texture and XRCompositionLayer output modes; VP9 Profile 0 (8-bit) and HEVC Main (8-bit). The only property that matters is SAR 1:2, carried in the mp4
paspbox and/or the HEVC VUI (aspect_ratio_idc = 255 / Extended_SAR, sar 1/2).Steps to reproduce (self-contained — no file download needed)
Generate a bug file and a control file. Identical pixels; only the SAR tag differs:
Play each with ExoPlayer + BGRA and log the produced texture size (e.g.
TextureProducer.GetTexture().width).Evidence from our production app (Quest kiosk / 360 player)
Applog lines from our device, unfixed vs fixed file:
The last table row is the decisive experiment: not one pixel of the bitstream changed (framemd5-identical decode), only the SAR tag — and the texture width doubled. Since this reproduces across both graphics APIs, both output modes, and two different SoCs, the behavior sits in the shared native path below those splits (the C# side reports plane dimensions straight from
AVPPlayerGetTexture).We run the BGRA (non-OES) path; we have not tested whether the OES fast path is also affected.
Why we believe this needs a change
SAR-awareness is legitimate for flat video display, but the current implementation:
pasptags; ours implies a nonsensical 8:9 display aspect for equirectangular content, which the OS player ignores.Request
Preferred: always produce the texture at coded resolution and expose SAR through the API so applications apply it at display time — matching ExoPlayer's own model (
VideoSize.pixelWidthHeightRatio) and Unity's VideoPlayer. Alternatively aPlatformOptionsAndroidflag such asignoreSampleAspectRatio. At minimum, if resampling stays the default for back-compat, make it non-destructive (upscale, never downscale) and emit a log line stating the texture was resized due to SAR.Worth noting the plugin's own design already follows the model we're asking for:
AVPPlayerVideoTrackInfocarriesdimensions,transform,stereoMode,bitsPerComponentandyCbCrTransform— display-geometry metadata carried as data for the application to apply, rather than baked into pixels. ApixelAspectRatiofield alongsidetransformwould be a small, consistent extension rather than a new concept. (Related question: doesdimensionsreport coded or SAR-adjusted size for these files? If it reports coded size while the texture is the adjusted size, that's an internal inconsistency in itself.)There is also an asymmetry worth flagging: per #1945, on Android the container's rotation/display transform is not applied (users reported
transformcoming back as identity and had to supply ExoPlayer's matrix manually), yet the container's SAR is applied, destructively. Two members of the same metadata class treated in opposite ways.Related existing issues (searched first — this does not appear to be a duplicate)
Nothing in the Known Issues page covers SAR/PAR on any platform.
Workaround for anyone else hitting this (lossless, seconds per file)
Media information
Demo testing videos (use only for research)
Original (with SAR issue)
https://s3.ap-southeast-2.amazonaws.com/ccd.odysee/SparcVR/content/default/media/videos/full/Athens%2C%20Greece%20City%20Trip%20VR360%203D%20%5BydUQtOcX_xc%5D_original.mp4
Fixed( Slice of Original )
https://s3.ap-southeast-2.amazonaws.com/ccd.odysee/SparcVR/content/default/media/videos/full/Athens%2C%20Greece%20City%20Trip%20VR360%203D%20%5BydUQtOcX_xc%5D.mp4
Comparing the Same Videos on 2 different players o2svrplayer(AVPro) & horizon

Screen captures:
o2svrplayer(AVPro):
Tets_07_A-com.canopycreative.o2svrplayer-20260707-014309_g.jpg
Native horizon media player:

Tets_07_B-com.oculus.horizonmediaplayer-20260707-014643-g.jpg
Logcat output