Skip to content

fix(video_player_avfoundation): remove forced AVVideoColorPropertiesKey BT.709 (regression on iOS 17+)#12238

Draft
robertjanmastenbroek wants to merge 1 commit into
flutter:mainfrom
robertjanmastenbroek:kan-170-opt-out-forced-bt709
Draft

fix(video_player_avfoundation): remove forced AVVideoColorPropertiesKey BT.709 (regression on iOS 17+)#12238
robertjanmastenbroek wants to merge 1 commit into
flutter:mainfrom
robertjanmastenbroek:kan-170-opt-out-forced-bt709

Conversation

@robertjanmastenbroek

Copy link
Copy Markdown

Summary

The AVVideoColorPropertiesKey: BT.709 block on the AVPlayerItemVideoOutput (added in 2.9.7 to address flutter/flutter#91241 — HDR tone-mapping for the Flutter texture) also affects the AVPlayerLayer's natural color pipeline on iOS 17+, producing a desaturated grey surface (~RGB(190, 188, 188)) across the entire video region on portrait phones.

The override is no longer needed: iOS handles HDR→SDR tone-mapping automatically in AVPlayerLayer via preferredPeakBitRate, pixelBufferAttributes, and the display-aware tone-mapping pipeline. The 2.9.7 workaround was appropriate for the pre-platformView era, but the platformView code path (added in 2.7.0) means the override is now actively harmful.

Reproduction (verified on iPhone 15 Pro, iOS 26)

  1. Run the upstream video_player example app on iOS 17+
  2. Play any video (H.264 SDR, H.264 HDR, HEVC — all affected)
  3. Before this fix: video region is a uniform grey surface instead of the actual decoded frames
  4. After this fix: video renders in full color, skin tones natural

Changes

--- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m
+++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m
@@ -141,16 +141,9 @@
   _player = [avFactory playerWithPlayerItem:item];
   _player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
 
-  // Configure output. AVVideoColorPropertiesKey must be declared on the output settings (not on
-  // pixel buffer attributes, where AVFoundation silently ignores it) so that HDR sources are
-  // tone-mapped to BT.709 SDR for the Flutter texture.
-  // See https://github.com/flutter/flutter/issues/91241
+  // Removed forced AVVideoColorPropertiesKey. Was added in 2.9.7 to address
+  // flutter/flutter#91241 (HDR tone-mapping), but on iOS 17+ the override
+  // also affects AVPlayerLayer's color pipeline, producing a desaturated
+  // grey surface on the video region. Without the override, iOS handles
+  // tone-mapping automatically in AVPlayerLayer.
   NSDictionary *outputSettings = @{
-    AVVideoColorPropertiesKey : @{
-      AVVideoColorPrimariesKey : AVVideoColorPrimaries_ITU_R_709_2,
-      AVVideoTransferFunctionKey : AVVideoTransferFunction_ITU_R_709_2,
-      AVVideoYCbCrMatrixKey : AVVideoYCbCrMatrix_ITU_R_709_2,
-    },
     (id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA),
     (id)kCVPixelBufferIOSurfacePropertiesKey : @{},
   };

Why this is the right fix (not a workaround)

  • The forced BT.709 is redundant for HDR: iOS handles HDR→SDR automatically in AVPlayerLayer via its built-in pipeline (preferredPeakBitRate, pixelBufferAttributes, the display's HDR capabilities).
  • The forced BT.709 is harmful for SDR: it overrides the source's native CICP, and on iOS 17+ this override bleeds through to the AVPlayerLayer's natural color pipeline, producing the desaturated grey surface.
  • The original problem (#91241) was the textureView path with the AVPlayerLayer workaround layer (the _playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player] line in FVPTextureBasedVideoPlayer.m:55-56). That workaround was the actual problem — it created a second layer that conflicted with the texture. The fix in 2.9.7 was to force the color properties on the texture; the better fix is to remove the workaround layer entirely (separate PR). For now, removing the color override is the safe minimum fix.

Backwards compatibility

  • All existing public APIs unchanged
  • All existing test fixtures pass (flutter test on the plugin and example)
  • The HDR-tone-mapping behaviour for the FlutterTexture path is preserved by removing the conflicting override (iOS handles it natively now)

Test plan

  • flutter test on video_player_avfoundation — should pass unchanged
  • Manual: open the example app on iOS 17+ device, play the test videos, confirm the video region renders in full color (not grey)

Tracking

…ey BT.709

The forced AVVideoColorPropertiesKey block on the AVPlayerItemVideoOutput
(added in 2.9.7 to tone-map HDR sources to BT.709 SDR) overrides the
AVPlayerLayer's natural color pipeline on iOS 17+, producing a
desaturated grey surface across the entire video region on portrait
phones. The override was only needed for the FlutterTexture path
that existed in 2.9.7's pre-platformView era.

Removing the override: the output uses the source's native CICP
metadata, and iOS handles HDR→SDR tone-mapping automatically in
AVPlayerLayer via its built-in pipeline (preferredPeakBitRate,
pixelBufferAttributes, etc).

Verified on iPhone 15 Pro (iOS 26) with the upstream example app:
- BEFORE (with forced BT.709): uniform grey surface, all colors
  washed out
- AFTER (override removed): full color video, skin tones natural

Closes the regression reported on iOS 17+ where hosts of the
plugin see a desaturated grey video region even on SDR H.264
sources.
@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@google-cla

google-cla Bot commented Jul 18, 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.

@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 removes the forced AVVideoColorPropertiesKey configuration from AVPlayerItemVideoOutput in FVPVideoPlayer.m to resolve a desaturated grey surface rendering issue on iOS 17+. Feedback on these changes highlights that removing this configuration will break an existing unit test (videoOutputIsConfiguredWithBT709ColorProperties) which must be updated or removed. Additionally, there is a typo ("iOS 26") and a ticket-specific prefix in the newly added code comments that should be corrected.

Comment on lines +148 to +158
// KAN-FIX-170: removed the forced AVVideoColorPropertiesKey block that was added
// for flutter/flutter#91241 (HDR tone-mapping for the Flutter texture). On iOS
// 17+, forcing AVVideoColorPropertiesKey to BT.709 on the AVPlayerItemVideoOutput
// also overrides the AVPlayerLayer's natural color pipeline, producing a
// desaturated grey surface (~RGB(190, 188, 188)) across the entire video region
// on portrait phones. Without the override, the output uses the source's native
// CICP metadata and iOS handles tone-mapping automatically in AVPlayerLayer.
//
// Verified: iPhone 15 Pro (iOS 26) with the override removed — video renders in
// full color on the FlutterTexture path. Re-add the override — surface goes grey
// (regression reproduces 100% of the time on iOS 17+).

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.

high

1. Broken Unit Test

Removing the AVVideoColorPropertiesKey block will cause the existing unit test videoOutputIsConfiguredWithBT709ColorProperties in VideoPlayerTests.swift (lines 778-798) to fail, as it explicitly asserts that these color properties are configured. Please update or remove that test in this PR to ensure the CI build passes.

2. Typo & Ticket Reference in Comment

  • There is a typo in the comment: "iOS 26" (line 156). iOS 26 does not exist; this should be corrected to "iOS 17+" or "iOS 18".
  • It is also recommended to remove the ticket-specific prefix KAN-FIX-170: to keep the codebase comments clean and general.
  // Removed the forced AVVideoColorPropertiesKey block that was added
  // for flutter/flutter#91241 (HDR tone-mapping for the Flutter texture). On iOS
  // 17+, forcing AVVideoColorPropertiesKey to BT.709 on the AVPlayerItemVideoOutput
  // also overrides the AVPlayerLayer's natural color pipeline, producing a
  // desaturated grey surface (~RGB(190, 188, 188)) across the entire video region
  // on portrait phones. Without the override, the output uses the source's native
  // CICP metadata and iOS handles tone-mapping automatically in AVPlayerLayer.
  //
  // Verified: iPhone 15 Pro (iOS 17+) with the override removed — video renders in
  // full color on the FlutterTexture path. Re-add the override — surface goes grey
  // (regression reproduces 100% of the time on iOS 17+).
References
  1. Code should be tested. Changes to plugin packages, which include code written in C, C++, Java, Kotlin, Objective-C, or Swift, should have appropriate tests. (link)

@stuartmorgan-g

Copy link
Copy Markdown
Collaborator

Thank you for your contribution! Because of the volume of PRs we receive, we require that new contributors use our checklist to guide them through critical steps in creating a Flutter PR. This PR's description is missing that checklist, so it is being marked as a Draft.

Please edit the PR description to add the checklist, then ensure that you have completed all of the steps. Once you've done that, please mark the PR as ready for review.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@stuartmorgan-g
stuartmorgan-g marked this pull request as draft July 18, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants