Skip to content

[video_player_android] Report display size for anamorphic video - #12360

Merged
auto-submit[bot] merged 4 commits into
flutter:mainfrom
voledyaev:video-player-android-pixel-aspect-ratio
Sep 2, 2026
Merged

[video_player_android] Report display size for anamorphic video#12360
auto-submit[bot] merged 4 commits into
flutter:mainfrom
voledyaev:video-player-android-pixel-aspect-ratio

Conversation

@voledyaev

Copy link
Copy Markdown
Contributor

VideoSize.pixelWidthHeightRatio was never read, so videos stored with non-square pixels (anamorphic content) reported their coded size instead of their display size. VideoPlayerValue.size therefore carried the wrong aspect ratio and such videos rendered stretched.

Example of a real affected file: coded 1080x720 with a 3:8 pixel aspect ratio displays as 405x720, but size was reported as 1080x720 — a 2.67x horizontal stretch.

This scales the reported width by the pixel aspect ratio, which is what media3's own PlayerView does:

float videoAspectRatio = (height == 0 || width == 0) ? 0 : (width * videoSize.pixelWidthHeightRatio) / height;

Both event listeners are updated:

  • Texture path — ExoPlayer reports a pixelWidthHeightRatio that already accounts for any applied rotation (MediaCodecVideoRenderer inverts it for 90°/270°), so the ratio is applied to the reported width regardless of the rotation correction.
  • Platform view pathFormat.pixelWidthHeightRatio describes the unrotated frame, so the ratio is applied before the existing width/height swap.

The scaling is skipped unless the ratio is greater than 0 and not 1, so playback of ordinary square-pixel video is byte-for-byte unchanged.

Verified on a physical anamorphic sample (1080x720, SAR 3:8) on Android 15: previously stretched, now rendered at the correct 9:16 display aspect. iOS is unaffected — video_player_avfoundation already reports presentationSize, which is pixel-aspect corrected, which is why this bug is Android-only.

(No before/after screenshots: the sample videos available to me are private medical content and cannot be published.)

Fixes flutter/flutter#132934
Fixes flutter/flutter#94234

Pre-Review Checklist

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2

@google-cla

google-cla Bot commented Aug 4, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

`VideoSize.pixelWidthHeightRatio` (and `Format.pixelWidthHeightRatio` for the
platform view path) was ignored, so videos stored with non-square pixels
reported their coded size instead of their display size. Flutter then laid the
video out with the wrong aspect ratio and it rendered stretched.

Scale the reported width by the pixel aspect ratio, which is what media3's own
`PlayerView` does. ExoPlayer reports a ratio that already accounts for any
applied rotation, so the texture path needs no rotation-specific handling; the
platform view path applies the ratio before its manual width/height swap.

Fixes flutter/flutter#132934
Fixes flutter/flutter#94234
@voledyaev
voledyaev force-pushed the video-player-android-pixel-aspect-ratio branch from 074260a to 1bfb1c7 Compare August 4, 2026 08:49

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses an issue where anamorphic videos (with a pixel aspect ratio other than 1.0) are rendered stretched by scaling the coded width by the pixel aspect ratio in both PlatformViewExoPlayerEventListener and TextureExoPlayerEventListener. Unit tests have been added to verify this scaling behavior. The feedback suggests ensuring that the scaled width is at least 1 to prevent layout issues or division-by-zero errors in Flutter if the calculation rounds down to 0.

Comment on lines +37 to +39
if (pixelWidthHeightRatio > 0 && pixelWidthHeightRatio != 1f) {
width = Math.round(width * pixelWidthHeightRatio);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If width is a small positive integer and pixelWidthHeightRatio is very small, Math.round(width * pixelWidthHeightRatio) can evaluate to 0. A width of 0 is invalid and can cause layout issues or division-by-zero errors in Flutter. We should ensure that if the original width was positive, the scaled width is at least 1.

Suggested change
if (pixelWidthHeightRatio > 0 && pixelWidthHeightRatio != 1f) {
width = Math.round(width * pixelWidthHeightRatio);
}
if (pixelWidthHeightRatio > 0 && pixelWidthHeightRatio != 1f) {
int scaledWidth = Math.round(width * pixelWidthHeightRatio);
width = width > 0 ? Math.max(1, scaledWidth) : scaledWidth;
}

Comment on lines +39 to +41
if (pixelWidthHeightRatio > 0 && pixelWidthHeightRatio != 1f) {
width = Math.round(width * pixelWidthHeightRatio);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If width is a small positive integer and pixelWidthHeightRatio is very small, Math.round(width * pixelWidthHeightRatio) can evaluate to 0. Since width is guaranteed to be non-zero here, we should ensure the scaled width is at least 1 to prevent layout issues or division-by-zero errors in Flutter.

Suggested change
if (pixelWidthHeightRatio > 0 && pixelWidthHeightRatio != 1f) {
width = Math.round(width * pixelWidthHeightRatio);
}
if (pixelWidthHeightRatio > 0 && pixelWidthHeightRatio != 1f) {
width = Math.max(1, Math.round(width * pixelWidthHeightRatio));
}

A malformed pixel aspect ratio could otherwise round a positive width down to
zero, which is not a usable size. The platform view path additionally only
scales a width that is known, so that Format.NO_VALUE is passed through
unchanged instead of being turned into a scaled value.
@voledyaev

Copy link
Copy Markdown
Contributor Author

Thanks — addressed in 66f2dfb, with one deliberate difference from the suggested diff.

In TextureExoPlayerEventListener the width is guaranteed non-zero by the enclosing check, so a plain Math.max(1, ...) is enough.

In PlatformViewExoPlayerEventListener the width comes from Format, where an unknown value is Format.NO_VALUE (-1), not 0. Applying width > 0 ? Math.max(1, scaledWidth) : scaledWidth there would turn -1 into Math.round(-1 * ratio) == 0, i.e. silently convert "unknown" into "zero", which is the failure mode we are trying to avoid. Guarding the whole branch with width > 0 instead leaves NO_VALUE untouched:

if (width > 0 && pixelWidthHeightRatio > 0 && pixelWidthHeightRatio != 1f) {
  width = Math.max(1, Math.round(width * pixelWidthHeightRatio));
}

Both behaviours are now covered by tests (...ReportsAtLeastOnePixel_whenPixelAspectRatioIsDegenerate on both listeners, plus onPlaybackStateChangedReadyLeavesUnknownWidthUnscaled).

@stuartmorgan-g stuartmorgan-g added the triage-android Should be looked at in Android triage label Aug 4, 2026
@stuartmorgan-g
stuartmorgan-g requested a review from mboetger August 4, 2026 20:42
voledyaev and others added 2 commits August 28, 2026 07:25
Resolves the version collision with #12615, which landed 2.12.1 for the pigeon
dev_dependency bump while this branch was open. The anamorphic fix moves to
2.12.2 and 2.12.1 keeps upstream's entry.
@mboetger
mboetger requested review from a team and camsim99 and removed request for a team September 1, 2026 20:31

@camsim99 camsim99 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@camsim99 camsim99 added autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD labels Sep 2, 2026
@auto-submit
auto-submit Bot merged commit 80da2cf into flutter:main Sep 2, 2026
13 checks passed
@voledyaev
voledyaev deleted the video-player-android-pixel-aspect-ratio branch September 3, 2026 14:08
github-merge-queue Bot pushed a commit to flutter/flutter that referenced this pull request Sep 3, 2026
flutter/packages@18fe786...f9b3954

2026-09-03 ashutoshagarwal2014@gmail.com [image_picker] Fix android-16
not picking up file (flutter/packages#11320)
2026-09-02 jmccandless@google.com [material_ui] Migrate off of
flutter_test's find.byTooltip and on to the local findByTooltip
(flutter/packages#12492)
2026-09-02 32538273+ValentinVignal@users.noreply.github.com
[material_ui] Remove no shuffle from text field tests
(flutter/packages#12547)
2026-09-02 21270878+elliette@users.noreply.github.com Add Material style
variant enum (#12221) (flutter/packages#12717)
2026-09-02 brian.egan@verygood.ventures [go_router_builder] Report
duplicate route paths at build time (flutter/packages#12399)
2026-09-02 victor.orozco@cloudsufi.com [google_sign_in] PR 1/4
google_sign_in_ios SPM packaging (flutter/packages#12654)
2026-09-02 55357489+voledyaev@users.noreply.github.com
[video_player_android] Report display size for anamorphic video
(flutter/packages#12360)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD p: video_player platform-android triage-android Should be looked at in Android triage

Projects

None yet

4 participants