-
Notifications
You must be signed in to change notification settings - Fork 3.3k
[video_player_avfoundation] iOS platform view support #8237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
FirentisTFW
merged 173 commits into
flutter:main
from
leancodepl:feature/video-player-platform-view-support
Feb 7, 2025
Merged
Changes from all commits
Commits
Show all changes
173 commits
Select commit
Hold shift + click to select a range
82d5333
Extract FVPFrameUpdater and FVPVideoPlayer from plugin file to separa…
FirentisTFW a2d3d9f
Add docs for FVPFrameUpdater and FVPVideoPlayer interfaces
FirentisTFW a74c720
Remove unused imports and #pragma statements
FirentisTFW 9092b71
Add empty lines at the end of files
FirentisTFW add5719
Bump version to 2.6.4 and update changelog
FirentisTFW 9587ad0
Move GLKit import from header file to source file
FirentisTFW 83cec0c
Add FVPVideoPlayerPlugin_Test import to plugin file
FirentisTFW 99123db
Fix parameter type in interface constructor
FirentisTFW 9545fda
Separate plugin and factory classes by pragma mark
FirentisTFW 75b5ab9
Add nullability type specifiers to FVPVideoPlayer interface
FirentisTFW 5ec766f
Make properties not needed in header of FVPVideoPlayer private
FirentisTFW c958a4a
Use nonnull macro for the whole header file
FirentisTFW 0a707a5
Make updatePlayingState private for FVPVideoPlayer
FirentisTFW 0055ea3
Make texture registry private for FVPFrameUpdater
FirentisTFW 717315e
Move code from Plugin_Test file to different files
FirentisTFW 489f2a9
Make changelog description more general
FirentisTFW 599adc8
Add a doc comment for FVPDefaultAVFactory
FirentisTFW 513961c
Make lastKnownAvailableTime property of FVPFrameUpdater readonly
FirentisTFW ff11b63
Add _Test.h file for FVPVideoPlayer
FirentisTFW 12efd58
Add FVPNativeVideoViewFactory and FVPNativeVideoView (everything in o…
FirentisTFW 42c3724
Use platform view in Dart Code (hardcoded)
FirentisTFW 968bbf1
Add PlatformVideoViewType enum to allow choosing between texture view…
FirentisTFW dc85756
Pass video view type to controller in iOS example project
FirentisTFW c9f27c5
Add two FVPVideoPlayer implementations - basic and texture-approach o…
FirentisTFW b3151e2
Split iOS native classes into multiple files
FirentisTFW db1a943
Only register native view factory for iOS, not MacOS
FirentisTFW 0e3b346
Use only textue view on MacOS in example app
FirentisTFW 6d317a5
Refactor imports
FirentisTFW 9bace40
Allow choosing between texture view and platform view in example app
FirentisTFW 3bf34f9
Remove redundant import
FirentisTFW 40996c4
Add some fixme comments for later
FirentisTFW 674f9d0
Add copyright to each native iOS file
FirentisTFW 3806bd2
Rename viewId to playerId in params
FirentisTFW 87e76ac
Unregister texture from registry only when using texture approach
FirentisTFW 4d11c11
Clean up code, add more context in comments
FirentisTFW d4dc7e5
Fix most of existing unit tests by creating a player with texture vie…
FirentisTFW 73564c7
Check platform view in UI test
FirentisTFW 30f65c0
Only allow choosing between texture view and platform view in example…
FirentisTFW 3cd5126
Only include native view files on iOS
FirentisTFW c96ca17
Make comments less ambiguous
FirentisTFW c26b210
Add unit tests for factory registration and lack of texture registrat…
FirentisTFW 45862e3
Make viewType an optional parameter and default to textureView
FirentisTFW 479dc37
Document new classes in native iOS code
FirentisTFW 7fe29f7
Document VideoViewType on Dart side
FirentisTFW 7f19bd1
Fix variable name
FirentisTFW f3eb9ea
Format files generated by pigeon
FirentisTFW a28b580
Use a class for platform view creation params
FirentisTFW da768fe
Remove unused param from method
FirentisTFW dd5637c
Fix failing unit test, prevent double factory registration
FirentisTFW 5214aa5
Format pigeon generated file
FirentisTFW 981eb8a
Use correct plugin key in test function
FirentisTFW 85d5ac6
Update dartdocs and comments
FirentisTFW 97490ae
Adjust FVPVideoPlayer interface after rebase
FirentisTFW fd777bd
Fix Xcode analysis issues
FirentisTFW bbf2efa
Split code into fiels and fix implementations to separate texture app…
FirentisTFW 39dd125
Adjust tests to use FVPVideoPlayerTextureApproach
FirentisTFW ad38f1c
Make video_player platform interface backwards compatible
FirentisTFW fd64cbe
Bump iOS package version to 2.7.0
FirentisTFW 5132b99
Add viewType parameter to VideoPlayerController and use it to display…
FirentisTFW 4df6449
Improve if statements readability
FirentisTFW a885632
Rename textureId to playerId in onPlayerSetup
FirentisTFW 3cb7389
Fix overriding create method from platform interface on iOS
FirentisTFW 5dc241e
Start non-texture player ids from a high number to avoid collisions
FirentisTFW fe61a20
Update comments
FirentisTFW 9c38562
Add viewType to FakeController in tests
FirentisTFW 6705387
Use correct view type to create data source in the main package
FirentisTFW fe88ebf
Add unit tests for passing view type correctly
FirentisTFW 85f088d
Throw an assertion if platform view is used on platform different tha…
FirentisTFW 04d0e8d
Adjust example app to allow changing view type on iOS
FirentisTFW 07874ee
Add missing doc comments
FirentisTFW eba2c36
Remove placeholder files which are not needed anymore
FirentisTFW c2defa6
Clean up player's properties after rebase
FirentisTFW 508a212
Remove code related to platform view from the app facing package
FirentisTFW 9a2934a
Merge branch 'main' into feature/video-player-platform-view-support
FirentisTFW 1ee5082
Adjust interfaces after merge
FirentisTFW d9bb76a
Replace hyphens with asterisks in Changelog
FirentisTFW cea9254
Update public_header_files path for iOS
FirentisTFW 9ef9355
Rename playersByTextureId to playersById
FirentisTFW 120e756
Move initWithPlayerItem from the public interface to class extension
FirentisTFW 5e8b820
Remove nullable and nonnull annotations from implementation file
FirentisTFW cfe51ab
Add empty lines at the end of files
FirentisTFW 1d21f18
Improve imports
FirentisTFW 6616a6a
Replace fixme comment with a regular comment
FirentisTFW a4d82b2
Update names and doc comments in platform interface
FirentisTFW b267d3d
Update changelogs
FirentisTFW b19ca86
Bump platform_interface version to 6.3.0
FirentisTFW f04ed06
Rename textureId to playerId in test file when using platform view
FirentisTFW c2117a8
Add local dependency overrides for platform interface
FirentisTFW e7404e3
Format generated iOS files
FirentisTFW d3f3873
Add native view factory import to test file
FirentisTFW 0ca8f80
Fix iOS source files path in podspec
FirentisTFW 5f31fc3
Add iOS include path to Package.swift
FirentisTFW b78b61e
Revert "Remove placeholder files which are not needed anymore"
FirentisTFW dbe39ba
Move header files related to platform views to the main directory
FirentisTFW 7bbf8bf
Add TargetConditionals.h import to FVPNativeVideoView.h
FirentisTFW 2dac440
Add TargetConditionals.h import to FVPNativeVideoViewFactory.h
FirentisTFW 1b77376
Update doc comments for FVPVideoPlayer constructors
FirentisTFW 277b805
Merge branch 'main' into feature/video-player-platform-view-support
FirentisTFW 404fad2
Merge branch 'main' into feature/video-player-platform-view-support
FirentisTFW d2778a1
Remove dependency overrides for packages that have no other changes
FirentisTFW 4a8d0bd
Remove redundant sentence from a comment
FirentisTFW b6f2e2c
Use INT_MAX as the initial non-texture player ID, and then decrement
FirentisTFW 6702c6f
Make viewType parameter in CreationOptions non-nullable
FirentisTFW 4d7ca15
Rename FVPVideoPlayerTextureApproach to FVPTextureBasedVideoPlayer
FirentisTFW 7bb4de3
Remove redeclaration of view method from the interface
FirentisTFW f753253
Use a block instead of passing a mutable dictionary
FirentisTFW 16fb48e
Do not use "we" in comments
FirentisTFW b1dd379
Inherit from NSView instead of NSWindow
FirentisTFW 7d7121a
Do not override dealloc in FVPNativeVideoView
FirentisTFW 3eddd81
Fix typo
FirentisTFW 97bd780
Remove "we" from comments
FirentisTFW 8fe7428
Fix initialization of viewType in test file
FirentisTFW 9b7f9ad
Fix (hopefully) a flaky test - wait for the assertion to happen inste…
FirentisTFW cacfd26
Add back license that was removed by mistake
FirentisTFW 576a005
Rename variables for better consistency
FirentisTFW b7b58e2
Do not use @synchronized when decrementing next player ID
FirentisTFW 8a71cfa
Introduce createWithOptions method
FirentisTFW fe409ed
Add a todo
FirentisTFW 057285f
Fix dartdoc
FirentisTFW 3610b34
Remove - unnecessary casts
FirentisTFW 93ec315
Convert static variable to an ivar
FirentisTFW 551e2b1
Add missing newline at the end of file
FirentisTFW 9fbc43d
Use private properties instead of ivars
FirentisTFW 2c1f5c4
Fix textureBased condition
FirentisTFW f78d7da
Reuse common code in seekTo method
FirentisTFW 65b2614
Add pragma sections to texture-based video player file
FirentisTFW a48f432
Merge branch 'main' into feature/video-player-platform-view-support
FirentisTFW 2915bad
Simplfy platform interface, do not expose internal details about play…
FirentisTFW af1d7eb
Adjust iOS implementation to the new platform interface
FirentisTFW 9453edc
Adjust example app's controller to the new platform interface
FirentisTFW 37c8dab
Test playerViewTypes in iOS implementation
FirentisTFW 4f09736
Merge branch 'main' into feature/video-player-platform-view-support
FirentisTFW 0045c27
Adjust new test's setup after merging main
FirentisTFW bdd5fd3
Introduce VideoPlayerViewState class
FirentisTFW cee36ce
Adjust unit tests to the new type
FirentisTFW 09e148e
Move throw-exception-on-invalid-asset test from Dart side to native i…
FirentisTFW cca3655
Rename variable
FirentisTFW af79cc0
Mock lookupKeyForAsset method
FirentisTFW e5c3c99
Pass onDisposed callback to FVPTextureBasedVideoPlayer
FirentisTFW 70e4215
Refactor players initialization in plugin file
FirentisTFW 80fffcf
Fix return type
FirentisTFW 5a85403
Merge branch 'main' into feature/video-player-platform-view-support
FirentisTFW 6d236b4
Bump platform interface dependency to 6.3.0
FirentisTFW 7cd5f14
Rename textureId to playerId in platform interace methods
FirentisTFW 3d3b59d
Rename textureId to playerId in iOS Dart files
FirentisTFW ebe123a
Move dispose guard to texture-based video player, simplify unregister…
FirentisTFW d486095
Rename textureId to playerId in iOS native code
FirentisTFW cdd1458
Bump platform interface dependency to 6.3.0 in example app
FirentisTFW f920a38
Remove outdated information from doc comment
FirentisTFW 84a0538
Rename FromOptions to WithOptions
FirentisTFW d1841b3
Use weak self to avoid retain cycles
FirentisTFW 29cddaf
Rename create-player methods
FirentisTFW db469b3
Comment on using FVPVideoPlayer
FirentisTFW 417e771
Fall back to texture view if platform view is requested on MacOS
FirentisTFW c1497d7
Describe missing support for MacOS platform views in readme
FirentisTFW b7dc9ff
Remove flutterViewLayer from FVPVideoPlayer interface
FirentisTFW ecfd81f
Add more details to comments in FVPTextureBasedVideoPlayer and FVPVid…
FirentisTFW a740fa2
Simplify version constraints in pubspec.yaml
FirentisTFW 7071a66
Clarify that the lack of macOS support is not a fundamental limitation
FirentisTFW 0a80da6
Put conditional imports at the end
FirentisTFW ec18e13
Extract common logic to a shared method
FirentisTFW 3b55eec
Move FVPVideoPlayer class extension to _Internal.h file
FirentisTFW c694d86
Rename Id to Identifier where possible
FirentisTFW b57d5f6
Rename method according to Objective-C convention
FirentisTFW c5b5170
Fix imports
FirentisTFW dae7fc4
Restructure code to avoid additional casting
FirentisTFW 2b22477
Use ternary operator
FirentisTFW d4c6d83
Remove verbs from naming in convenience constructors
FirentisTFW 91103eb
Import Foundation instead of TargetConditionals
FirentisTFW 615bad6
Document FVPVideoPlayer extension
FirentisTFW 31f0b1f
Rename parameter
FirentisTFW 3b4fdb4
Use class method instead of instance method for helper
FirentisTFW f1026ee
Format code
FirentisTFW File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
261 changes: 189 additions & 72 deletions
261
packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
198 changes: 198 additions & 0 deletions
198
.../video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#import "./include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h" | ||
#import "./include/video_player_avfoundation/FVPTextureBasedVideoPlayer_Test.h" | ||
|
||
@interface FVPTextureBasedVideoPlayer () | ||
FirentisTFW marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// The CALayer associated with the Flutter view this plugin is associated with, if any. | ||
@property(nonatomic, readonly) CALayer *flutterViewLayer; | ||
// The updater that drives callbacks to the engine to indicate that a new frame is ready. | ||
@property(nonatomic) FVPFrameUpdater *frameUpdater; | ||
// The display link that drives frameUpdater. | ||
@property(nonatomic) FVPDisplayLink *displayLink; | ||
// Whether a new frame needs to be provided to the engine regardless of the current play/pause state | ||
// (e.g., after a seek while paused). If YES, the display link should continue to run until the next | ||
// frame is successfully provided. | ||
@property(nonatomic, assign) BOOL waitingForFrame; | ||
@property(nonatomic, copy) void (^onDisposed)(int64_t); | ||
@end | ||
|
||
@implementation FVPTextureBasedVideoPlayer | ||
- (instancetype)initWithAsset:(NSString *)asset | ||
frameUpdater:(FVPFrameUpdater *)frameUpdater | ||
displayLink:(FVPDisplayLink *)displayLink | ||
avFactory:(id<FVPAVFactory>)avFactory | ||
registrar:(NSObject<FlutterPluginRegistrar> *)registrar | ||
onDisposed:(void (^)(int64_t))onDisposed { | ||
return [self initWithURL:[NSURL fileURLWithPath:[FVPVideoPlayer absolutePathForAssetName:asset]] | ||
frameUpdater:frameUpdater | ||
displayLink:displayLink | ||
httpHeaders:@{} | ||
avFactory:avFactory | ||
registrar:registrar | ||
onDisposed:onDisposed]; | ||
} | ||
|
||
- (instancetype)initWithURL:(NSURL *)url | ||
frameUpdater:(FVPFrameUpdater *)frameUpdater | ||
displayLink:(FVPDisplayLink *)displayLink | ||
httpHeaders:(nonnull NSDictionary<NSString *, NSString *> *)headers | ||
avFactory:(id<FVPAVFactory>)avFactory | ||
registrar:(NSObject<FlutterPluginRegistrar> *)registrar | ||
onDisposed:(void (^)(int64_t))onDisposed { | ||
NSDictionary<NSString *, id> *options = nil; | ||
if ([headers count] != 0) { | ||
options = @{@"AVURLAssetHTTPHeaderFieldsKey" : headers}; | ||
} | ||
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:url options:options]; | ||
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:urlAsset]; | ||
return [self initWithPlayerItem:item | ||
frameUpdater:frameUpdater | ||
displayLink:displayLink | ||
avFactory:avFactory | ||
registrar:registrar | ||
onDisposed:onDisposed]; | ||
} | ||
|
||
- (instancetype)initWithPlayerItem:(AVPlayerItem *)item | ||
frameUpdater:(FVPFrameUpdater *)frameUpdater | ||
displayLink:(FVPDisplayLink *)displayLink | ||
avFactory:(id<FVPAVFactory>)avFactory | ||
registrar:(NSObject<FlutterPluginRegistrar> *)registrar | ||
onDisposed:(void (^)(int64_t))onDisposed { | ||
self = [super initWithPlayerItem:item avFactory:avFactory registrar:registrar]; | ||
|
||
if (self) { | ||
_frameUpdater = frameUpdater; | ||
_displayLink = displayLink; | ||
_frameUpdater.videoOutput = self.videoOutput; | ||
_onDisposed = [onDisposed copy]; | ||
|
||
// This is to fix 2 bugs: 1. blank video for encrypted video streams on iOS 16 | ||
// (https://github.com/flutter/flutter/issues/111457) and 2. swapped width and height for some | ||
// video streams (not just iOS 16). (https://github.com/flutter/flutter/issues/109116). An | ||
// invisible AVPlayerLayer is used to overwrite the protection of pixel buffers in those streams | ||
// for issue #1, and restore the correct width and height for issue #2. | ||
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; | ||
[self.flutterViewLayer addSublayer:self.playerLayer]; | ||
} | ||
return self; | ||
} | ||
|
||
- (void)setTextureIdentifier:(int64_t)textureIdentifier { | ||
self.frameUpdater.textureIdentifier = textureIdentifier; | ||
} | ||
|
||
- (void)expectFrame { | ||
self.waitingForFrame = YES; | ||
|
||
_displayLink.running = YES; | ||
} | ||
|
||
#pragma mark - Private methods | ||
|
||
- (CALayer *)flutterViewLayer { | ||
#if TARGET_OS_OSX | ||
return self.registrar.view.layer; | ||
#else | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wdeprecated-declarations" | ||
// TODO(hellohuanlin): Provide a non-deprecated codepath. See | ||
// https://github.com/flutter/flutter/issues/104117 | ||
UIViewController *root = UIApplication.sharedApplication.keyWindow.rootViewController; | ||
#pragma clang diagnostic pop | ||
return root.view.layer; | ||
#endif | ||
} | ||
|
||
#pragma mark - Overrides | ||
|
||
- (void)updatePlayingState { | ||
[super updatePlayingState]; | ||
// If the texture is still waiting for an expected frame, the display link needs to keep | ||
// running until it arrives regardless of the play/pause state. | ||
_displayLink.running = self.isPlaying || self.waitingForFrame; | ||
} | ||
|
||
- (void)seekTo:(int64_t)location completionHandler:(void (^)(BOOL))completionHandler { | ||
FirentisTFW marked this conversation as resolved.
Show resolved
Hide resolved
|
||
CMTime previousCMTime = self.player.currentTime; | ||
[super seekTo:location | ||
completionHandler:^(BOOL completed) { | ||
if (CMTimeCompare(self.player.currentTime, previousCMTime) != 0) { | ||
// Ensure that a frame is drawn once available, even if currently paused. In theory a | ||
// race is possible here where the new frame has already drawn by the time this code | ||
// runs, and the display link stays on indefinitely, but that should be relatively | ||
// harmless. This must use the display link rather than just informing the engine that a | ||
// new frame is available because the seek completing doesn't guarantee that the pixel | ||
// buffer is already available. | ||
[self expectFrame]; | ||
} | ||
|
||
if (completionHandler) { | ||
completionHandler(completed); | ||
} | ||
}]; | ||
} | ||
|
||
- (void)disposeSansEventChannel { | ||
// This check prevents the crash caused by removing the KVO observers twice. | ||
// When performing a Hot Restart, the leftover players are disposed once directly | ||
// by [FVPVideoPlayerPlugin initialize:] method and then disposed again by | ||
// [FVPVideoPlayer onTextureUnregistered:] call leading to possible over-release. | ||
if (self.disposed) { | ||
return; | ||
} | ||
|
||
[super disposeSansEventChannel]; | ||
|
||
[self.playerLayer removeFromSuperlayer]; | ||
|
||
_displayLink = nil; | ||
} | ||
|
||
- (void)dispose { | ||
[super dispose]; | ||
|
||
_onDisposed(self.frameUpdater.textureIdentifier); | ||
} | ||
|
||
#pragma mark - FlutterTexture | ||
|
||
- (CVPixelBufferRef)copyPixelBuffer { | ||
FirentisTFW marked this conversation as resolved.
Show resolved
Hide resolved
|
||
CVPixelBufferRef buffer = NULL; | ||
CMTime outputItemTime = [self.videoOutput itemTimeForHostTime:CACurrentMediaTime()]; | ||
if ([self.videoOutput hasNewPixelBufferForItemTime:outputItemTime]) { | ||
buffer = [self.videoOutput copyPixelBufferForItemTime:outputItemTime itemTimeForDisplay:NULL]; | ||
} else { | ||
// If the current time isn't available yet, use the time that was checked when informing the | ||
// engine that a frame was available (if any). | ||
CMTime lastAvailableTime = self.frameUpdater.lastKnownAvailableTime; | ||
if (CMTIME_IS_VALID(lastAvailableTime)) { | ||
buffer = [self.videoOutput copyPixelBufferForItemTime:lastAvailableTime | ||
itemTimeForDisplay:NULL]; | ||
} | ||
} | ||
|
||
if (self.waitingForFrame && buffer) { | ||
self.waitingForFrame = NO; | ||
// If the display link was only running temporarily to pick up a new frame while the video was | ||
// paused, stop it again. | ||
if (!self.isPlaying) { | ||
self.displayLink.running = NO; | ||
} | ||
} | ||
|
||
return buffer; | ||
} | ||
|
||
- (void)onTextureUnregistered:(NSObject<FlutterTexture> *)texture { | ||
dispatch_async(dispatch_get_main_queue(), ^{ | ||
if (!self.disposed) { | ||
[self dispose]; | ||
} | ||
}); | ||
} | ||
|
||
@end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.