From a691628d800b3147e89347079c0f4a4fe5dc9ca2 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 24 Jul 2025 14:09:36 -0400 Subject: [PATCH 01/11] Consolidate asset path logic; prep for moving to Dart --- .../FVPTextureBasedVideoPlayer.m | 12 --- .../FVPVideoPlayer.m | 21 ----- .../FVPVideoPlayerPlugin.m | 80 ++++++++++--------- .../FVPTextureBasedVideoPlayer.h | 8 -- .../FVPVideoPlayer.h | 6 -- .../FVPVideoPlayer_Internal.h | 4 - .../video_player_avfoundation/messages.g.h | 4 + .../video_player_avfoundation/messages.g.m | 25 ++++++ .../lib/src/messages.g.dart | 31 +++++++ .../pigeons/messages.dart | 2 + 10 files changed, 104 insertions(+), 89 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m index 071518e36f24..d8ef40c456ef 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m @@ -31,18 +31,6 @@ @interface FVPTextureBasedVideoPlayer () @end @implementation FVPTextureBasedVideoPlayer -- (instancetype)initWithAsset:(NSString *)asset - frameUpdater:(FVPFrameUpdater *)frameUpdater - displayLink:(NSObject *)displayLink - avFactory:(id)avFactory - viewProvider:(NSObject *)viewProvider { - return [self initWithURL:[NSURL fileURLWithPath:[FVPVideoPlayer absolutePathForAssetName:asset]] - frameUpdater:frameUpdater - displayLink:displayLink - httpHeaders:@{} - avFactory:avFactory - viewProvider:viewProvider]; -} - (instancetype)initWithURL:(NSURL *)url frameUpdater:(FVPFrameUpdater *)frameUpdater diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m index 77a7195c8733..17d2a77cd08c 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m @@ -17,14 +17,6 @@ static void *rateContext = &rateContext; @implementation FVPVideoPlayer -- (instancetype)initWithAsset:(NSString *)asset - avFactory:(id)avFactory - viewProvider:(NSObject *)viewProvider { - return [self initWithURL:[NSURL fileURLWithPath:[FVPVideoPlayer absolutePathForAssetName:asset]] - httpHeaders:@{} - avFactory:avFactory - viewProvider:viewProvider]; -} - (instancetype)initWithURL:(NSURL *)url httpHeaders:(nonnull NSDictionary *)headers @@ -122,19 +114,6 @@ - (void)dispose { [_eventChannel setStreamHandler:nil]; } -+ (NSString *)absolutePathForAssetName:(NSString *)assetName { - NSString *path = [[NSBundle mainBundle] pathForResource:assetName ofType:nil]; -#if TARGET_OS_OSX - // See https://github.com/flutter/flutter/issues/135302 - // TODO(stuartmorgan): Remove this if the asset APIs are adjusted to work better for macOS. - if (!path) { - path = [NSURL URLWithString:assetName relativeToURL:NSBundle.mainBundle.bundleURL].path; - } -#endif - - return path; -} - - (void)addObserversForItem:(AVPlayerItem *)item player:(AVPlayer *)player { [item addObserver:self forKeyPath:@"loadedTimeRanges" diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 114bba8552a7..d34a402e630a 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -218,50 +218,30 @@ - (nullable FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: [frameUpdater displayLinkFired]; }]; - if (options.asset) { - NSString *assetPath = [self assetPathFromCreationOptions:options]; - return [[FVPTextureBasedVideoPlayer alloc] initWithAsset:assetPath - frameUpdater:frameUpdater - displayLink:displayLink - avFactory:self.avFactory - viewProvider:self.viewProvider]; - } else if (options.uri) { - return [[FVPTextureBasedVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] - frameUpdater:frameUpdater - displayLink:displayLink - httpHeaders:options.httpHeaders - avFactory:self.avFactory - viewProvider:self.viewProvider]; + NSString *stringURI = + options.asset != nil ? [self assetURLFromCreationOptions:options] : options.uri; + if (!stringURI) { + return nil; } - - return nil; + return [[FVPTextureBasedVideoPlayer alloc] initWithURL:[NSURL URLWithString:stringURI] + frameUpdater:frameUpdater + displayLink:displayLink + httpHeaders:options.httpHeaders + avFactory:self.avFactory + viewProvider:self.viewProvider]; } - (nullable FVPVideoPlayer *)platformViewPlayerWithOptions:(nonnull FVPCreationOptions *)options { // FVPVideoPlayer contains all required logic for platform views. - if (options.asset) { - NSString *assetPath = [self assetPathFromCreationOptions:options]; - return [[FVPVideoPlayer alloc] initWithAsset:assetPath - avFactory:self.avFactory - viewProvider:self.viewProvider]; - } else if (options.uri) { - return [[FVPVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] - httpHeaders:options.httpHeaders - avFactory:self.avFactory - viewProvider:self.viewProvider]; - } - - return nil; -} - -- (NSString *)assetPathFromCreationOptions:(nonnull FVPCreationOptions *)options { - NSString *assetPath; - if (options.packageName) { - assetPath = [self.registrar lookupKeyForAsset:options.asset fromPackage:options.packageName]; - } else { - assetPath = [self.registrar lookupKeyForAsset:options.asset]; + NSString *stringURI = + options.asset != nil ? [self assetURLFromCreationOptions:options] : options.uri; + if (!stringURI) { + return nil; } - return assetPath; + return [[FVPVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] + httpHeaders:options.httpHeaders + avFactory:self.avFactory + viewProvider:self.viewProvider]; } - (void)disposePlayer:(NSInteger)playerIdentifier error:(FlutterError **)error { @@ -286,4 +266,28 @@ - (void)setMixWithOthers:(BOOL)mixWithOthers #endif } +- (nullable NSString *)fileURLForAssetWithName:(NSString *)asset + package:(nullable NSString *)package + error:(FlutterError *_Nullable *_Nonnull)error { + NSString *resource = package == nil + ? [self.registrar lookupKeyForAsset:asset] + : [self.registrar lookupKeyForAsset:asset fromPackage:package]; + + NSString *path = [[NSBundle mainBundle] pathForResource:resource ofType:nil]; +#if TARGET_OS_OSX + // See https://github.com/flutter/flutter/issues/135302 + // TODO(stuartmorgan): Remove this if the asset APIs are adjusted to work better for macOS. + if (!path) { + path = [NSURL URLWithString:assetName relativeToURL:NSBundle.mainBundle.bundleURL].path; + } +#endif + + return [NSURL fileURLWithPath:path].absoluteString; +} + +- (NSString *)assetURLFromCreationOptions:(nonnull FVPCreationOptions *)options { + FlutterError *error; + return [self fileURLForAssetWithName:options.asset package:options.packageName error:&error]; +} + @end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h index 229fd78ca247..bae9105039e4 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h @@ -23,14 +23,6 @@ NS_ASSUME_NONNULL_BEGIN avFactory:(id)avFactory viewProvider:(NSObject *)viewProvider; -/// Initializes a new instance of FVPTextureBasedVideoPlayer with the given asset, frame updater, -/// display link, AV factory, and registrar. -- (instancetype)initWithAsset:(NSString *)asset - frameUpdater:(FVPFrameUpdater *)frameUpdater - displayLink:(NSObject *)displayLink - avFactory:(id)avFactory - viewProvider:(NSObject *)viewProvider; - /// Sets the texture Identifier for the frame updater. This method should be called once the texture /// identifier is obtained from the texture registry. - (void)setTextureIdentifier:(int64_t)textureIdentifier; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h index 9a18197ee24e..469dda24a613 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h @@ -35,12 +35,6 @@ NS_ASSUME_NONNULL_BEGIN /// A block that will be called when dispose is called. @property(nonatomic, nullable, copy) void (^onDisposed)(void); -/// Initializes a new instance of FVPVideoPlayer with the given asset, AV factory, and view -/// provider. -- (instancetype)initWithAsset:(NSString *)asset - avFactory:(id)avFactory - viewProvider:(NSObject *)viewProvider; - /// Initializes a new instance of FVPVideoPlayer with the given URL, HTTP headers, AV factory, and /// view provider. - (instancetype)initWithURL:(NSURL *)url diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h index 7b282be4c066..c03736e62f58 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h @@ -40,10 +40,6 @@ NS_ASSUME_NONNULL_BEGIN /// Updates the playing state of the video player. - (void)updatePlayingState; - -/// Returns the absolute file path for a given asset name. -/// This method attempts to locate the specified asset within the app bundle. -+ (NSString *)absolutePathForAssetName:(NSString *)assetName; @end NS_ASSUME_NONNULL_END diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h index 1f3966d6e77b..8249f08e2bd0 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h @@ -63,6 +63,10 @@ NSObject *FVPGetMessagesCodec(void); error:(FlutterError *_Nullable *_Nonnull)error; - (void)disposePlayer:(NSInteger)playerId error:(FlutterError *_Nullable *_Nonnull)error; - (void)setMixWithOthers:(BOOL)mixWithOthers error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSString *)fileURLForAssetWithName:(NSString *)asset + package:(nullable NSString *)package + error:(FlutterError *_Nullable *_Nonnull)error; @end extern void SetUpFVPAVFoundationVideoPlayerApi( diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m index 90519755c2e3..12e28d4e5552 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m @@ -284,6 +284,31 @@ void SetUpFVPAVFoundationVideoPlayerApiWithSuffix(id bin [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.video_player_avfoundation." + @"AVFoundationVideoPlayerApi.getAssetUrl", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FVPGetMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(fileURLForAssetWithName:package:error:)], + @"FVPAVFoundationVideoPlayerApi api (%@) doesn't respond to " + @"@selector(fileURLForAssetWithName:package:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_asset = GetNullableObjectAtIndex(args, 0); + NSString *arg_package = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + NSString *output = [api fileURLForAssetWithName:arg_asset package:arg_package error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } } void SetUpFVPVideoPlayerInstanceApi(id binaryMessenger, NSObject *api) { diff --git a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart index cc184ae7db07..b757b7caf81b 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart @@ -308,6 +308,37 @@ class AVFoundationVideoPlayerApi { return; } } + + Future getAssetUrl(String asset, String? package) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.getAssetUrl$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([asset, package]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as String?)!; + } + } } class VideoPlayerInstanceApi { diff --git a/packages/video_player/video_player_avfoundation/pigeons/messages.dart b/packages/video_player/video_player_avfoundation/pigeons/messages.dart index c01fc094f1f4..218d76286497 100644 --- a/packages/video_player/video_player_avfoundation/pigeons/messages.dart +++ b/packages/video_player/video_player_avfoundation/pigeons/messages.dart @@ -57,6 +57,8 @@ abstract class AVFoundationVideoPlayerApi { void dispose(int playerId); @ObjCSelector('setMixWithOthers:') void setMixWithOthers(bool mixWithOthers); + @ObjCSelector('fileURLForAssetWithName:package:') + String getAssetUrl(String asset, String? package); } @HostApi() From b609ed0d075f21aa3583f78ab236d611d4cf37a7 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 24 Jul 2025 15:51:18 -0400 Subject: [PATCH 02/11] Move asset logic to Dart --- .../FVPVideoPlayerPlugin.m | 17 +-------- .../video_player_avfoundation/messages.g.h | 14 +++----- .../video_player_avfoundation/messages.g.m | 24 +++++-------- .../lib/src/avfoundation_video_player.dart | 23 +++++++----- .../lib/src/messages.g.dart | 22 ++++-------- .../pigeons/messages.dart | 5 ++- .../test/avfoundation_video_player_test.dart | 19 +++++----- .../avfoundation_video_player_test.mocks.dart | 36 +++++++++++++++++++ 8 files changed, 83 insertions(+), 77 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index d34a402e630a..2f09dc666de4 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -218,12 +218,7 @@ - (nullable FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: [frameUpdater displayLinkFired]; }]; - NSString *stringURI = - options.asset != nil ? [self assetURLFromCreationOptions:options] : options.uri; - if (!stringURI) { - return nil; - } - return [[FVPTextureBasedVideoPlayer alloc] initWithURL:[NSURL URLWithString:stringURI] + return [[FVPTextureBasedVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] frameUpdater:frameUpdater displayLink:displayLink httpHeaders:options.httpHeaders @@ -233,11 +228,6 @@ - (nullable FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: - (nullable FVPVideoPlayer *)platformViewPlayerWithOptions:(nonnull FVPCreationOptions *)options { // FVPVideoPlayer contains all required logic for platform views. - NSString *stringURI = - options.asset != nil ? [self assetURLFromCreationOptions:options] : options.uri; - if (!stringURI) { - return nil; - } return [[FVPVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] httpHeaders:options.httpHeaders avFactory:self.avFactory @@ -285,9 +275,4 @@ - (nullable NSString *)fileURLForAssetWithName:(NSString *)asset return [NSURL fileURLWithPath:path].absoluteString; } -- (NSString *)assetURLFromCreationOptions:(nonnull FVPCreationOptions *)options { - FlutterError *error; - return [self fileURLForAssetWithName:options.asset package:options.packageName error:&error]; -} - @end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h index 8249f08e2bd0..7dabbb3c6b2d 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h @@ -39,15 +39,11 @@ typedef NS_ENUM(NSUInteger, FVPPlatformVideoViewType) { @interface FVPCreationOptions : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithAsset:(nullable NSString *)asset - uri:(nullable NSString *)uri - packageName:(nullable NSString *)packageName - formatHint:(nullable NSString *)formatHint - httpHeaders:(NSDictionary *)httpHeaders - viewType:(FVPPlatformVideoViewType)viewType; -@property(nonatomic, copy, nullable) NSString *asset; -@property(nonatomic, copy, nullable) NSString *uri; -@property(nonatomic, copy, nullable) NSString *packageName; ++ (instancetype)makeWithUri:(NSString *)uri + formatHint:(nullable NSString *)formatHint + httpHeaders:(NSDictionary *)httpHeaders + viewType:(FVPPlatformVideoViewType)viewType; +@property(nonatomic, copy) NSString *uri; @property(nonatomic, copy, nullable) NSString *formatHint; @property(nonatomic, copy) NSDictionary *httpHeaders; @property(nonatomic, assign) FVPPlatformVideoViewType viewType; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m index 12e28d4e5552..36f786dc14ef 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m @@ -77,16 +77,12 @@ + (nullable FVPPlatformVideoViewCreationParams *)nullableFromList:(NSArray * @end @implementation FVPCreationOptions -+ (instancetype)makeWithAsset:(nullable NSString *)asset - uri:(nullable NSString *)uri - packageName:(nullable NSString *)packageName - formatHint:(nullable NSString *)formatHint - httpHeaders:(NSDictionary *)httpHeaders - viewType:(FVPPlatformVideoViewType)viewType { ++ (instancetype)makeWithUri:(NSString *)uri + formatHint:(nullable NSString *)formatHint + httpHeaders:(NSDictionary *)httpHeaders + viewType:(FVPPlatformVideoViewType)viewType { FVPCreationOptions *pigeonResult = [[FVPCreationOptions alloc] init]; - pigeonResult.asset = asset; pigeonResult.uri = uri; - pigeonResult.packageName = packageName; pigeonResult.formatHint = formatHint; pigeonResult.httpHeaders = httpHeaders; pigeonResult.viewType = viewType; @@ -94,12 +90,10 @@ + (instancetype)makeWithAsset:(nullable NSString *)asset } + (FVPCreationOptions *)fromList:(NSArray *)list { FVPCreationOptions *pigeonResult = [[FVPCreationOptions alloc] init]; - pigeonResult.asset = GetNullableObjectAtIndex(list, 0); - pigeonResult.uri = GetNullableObjectAtIndex(list, 1); - pigeonResult.packageName = GetNullableObjectAtIndex(list, 2); - pigeonResult.formatHint = GetNullableObjectAtIndex(list, 3); - pigeonResult.httpHeaders = GetNullableObjectAtIndex(list, 4); - FVPPlatformVideoViewTypeBox *boxedFVPPlatformVideoViewType = GetNullableObjectAtIndex(list, 5); + pigeonResult.uri = GetNullableObjectAtIndex(list, 0); + pigeonResult.formatHint = GetNullableObjectAtIndex(list, 1); + pigeonResult.httpHeaders = GetNullableObjectAtIndex(list, 2); + FVPPlatformVideoViewTypeBox *boxedFVPPlatformVideoViewType = GetNullableObjectAtIndex(list, 3); pigeonResult.viewType = boxedFVPPlatformVideoViewType.value; return pigeonResult; } @@ -108,9 +102,7 @@ + (nullable FVPCreationOptions *)nullableFromList:(NSArray *)list { } - (NSArray *)toList { return @[ - self.asset ?: [NSNull null], self.uri ?: [NSNull null], - self.packageName ?: [NSNull null], self.formatHint ?: [NSNull null], self.httpHeaders ?: [NSNull null], [[FVPPlatformVideoViewTypeBox alloc] initWithValue:self.viewType], diff --git a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart index bd89408eeb7e..2bbc776fa140 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart @@ -74,29 +74,34 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { final DataSource dataSource = options.dataSource; final VideoViewType viewType = options.viewType; - String? asset; - String? packageName; String? uri; String? formatHint; - Map httpHeaders = {}; switch (dataSource.sourceType) { case DataSourceType.asset: - asset = dataSource.asset; - packageName = dataSource.package; + final String? asset = dataSource.asset; + if (asset == null) { + throw ArgumentError( + '"asset" must be non-null for an asset data source', + ); + } + uri = await _api.getAssetUrl( + asset, + dataSource.package, + ); case DataSourceType.network: uri = dataSource.uri; formatHint = _videoFormatStringMap[dataSource.formatHint]; - httpHeaders = dataSource.httpHeaders; case DataSourceType.file: uri = dataSource.uri; case DataSourceType.contentUri: uri = dataSource.uri; } + if (uri == null) { + throw ArgumentError('Unable to construct a video asset from $options'); + } final CreationOptions pigeonCreationOptions = CreationOptions( - asset: asset, - packageName: packageName, uri: uri, - httpHeaders: httpHeaders, + httpHeaders: dataSource.httpHeaders, formatHint: formatHint, viewType: _platformVideoViewTypeFromVideoViewType(viewType), ); diff --git a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart index b757b7caf81b..0b989df912aa 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart @@ -84,19 +84,13 @@ class PlatformVideoViewCreationParams { class CreationOptions { CreationOptions({ - this.asset, - this.uri, - this.packageName, + required this.uri, this.formatHint, required this.httpHeaders, required this.viewType, }); - String? asset; - - String? uri; - - String? packageName; + String uri; String? formatHint; @@ -106,9 +100,7 @@ class CreationOptions { List _toList() { return [ - asset, uri, - packageName, formatHint, httpHeaders, viewType, @@ -122,13 +114,11 @@ class CreationOptions { static CreationOptions decode(Object result) { result as List; return CreationOptions( - asset: result[0] as String?, - uri: result[1] as String?, - packageName: result[2] as String?, - formatHint: result[3] as String?, + uri: result[0]! as String, + formatHint: result[1] as String?, httpHeaders: - (result[4] as Map?)!.cast(), - viewType: result[5]! as PlatformVideoViewType, + (result[2] as Map?)!.cast(), + viewType: result[3]! as PlatformVideoViewType, ); } diff --git a/packages/video_player/video_player_avfoundation/pigeons/messages.dart b/packages/video_player/video_player_avfoundation/pigeons/messages.dart index 218d76286497..9474103862ec 100644 --- a/packages/video_player/video_player_avfoundation/pigeons/messages.dart +++ b/packages/video_player/video_player_avfoundation/pigeons/messages.dart @@ -34,13 +34,12 @@ class PlatformVideoViewCreationParams { class CreationOptions { CreationOptions({ + required this.uri, required this.httpHeaders, required this.viewType, }); - String? asset; - String? uri; - String? packageName; + String uri; String? formatHint; Map httpHeaders; PlatformVideoViewType viewType; diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart index 6862e9996166..29de5c74c045 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart @@ -75,6 +75,11 @@ void main() { const String asset = 'someAsset'; const String package = 'somePackage'; + const String assetUrl = 'file:///some/asset/path'; + when( + api.getAssetUrl(asset, package), + ).thenAnswer((_) async => assetUrl); + final int? playerId = await player.create( DataSource( sourceType: DataSourceType.asset, @@ -86,8 +91,7 @@ void main() { final VerificationResult verification = verify(api.create(captureAny)); final CreationOptions creationOptions = verification.captured[0] as CreationOptions; - expect(creationOptions.asset, asset); - expect(creationOptions.packageName, package); + expect(creationOptions.uri, assetUrl); expect(playerId, newPlayerId); expect(player.playerViewStates[newPlayerId], const VideoPlayerTextureViewState(textureId: newPlayerId)); @@ -114,9 +118,7 @@ void main() { final VerificationResult verification = verify(api.create(captureAny)); final CreationOptions creationOptions = verification.captured[0] as CreationOptions; - expect(creationOptions.asset, null); expect(creationOptions.uri, uri); - expect(creationOptions.packageName, null); expect(creationOptions.formatHint, 'dash'); expect(creationOptions.httpHeaders, {}); expect(playerId, newPlayerId); @@ -181,6 +183,10 @@ void main() { const String asset = 'someAsset'; const String package = 'somePackage'; + const String assetUrl = 'file:///some/asset/path'; + when( + api.getAssetUrl(asset, package), + ).thenAnswer((_) async => assetUrl); final int? playerId = await player.createWithOptions( VideoCreationOptions( dataSource: DataSource( @@ -195,8 +201,7 @@ void main() { final VerificationResult verification = verify(api.create(captureAny)); final CreationOptions creationOptions = verification.captured[0] as CreationOptions; - expect(creationOptions.asset, asset); - expect(creationOptions.packageName, package); + expect(creationOptions.uri, assetUrl); expect(playerId, newPlayerId); expect(player.playerViewStates[newPlayerId], const VideoPlayerTextureViewState(textureId: newPlayerId)); @@ -226,9 +231,7 @@ void main() { final VerificationResult verification = verify(api.create(captureAny)); final CreationOptions creationOptions = verification.captured[0] as CreationOptions; - expect(creationOptions.asset, null); expect(creationOptions.uri, uri); - expect(creationOptions.packageName, null); expect(creationOptions.formatHint, 'dash'); expect(creationOptions.httpHeaders, {}); expect(playerId, newPlayerId); diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart index 1e9968cf0d7c..3bd52e5d2ddf 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart @@ -81,6 +81,42 @@ class MockAVFoundationVideoPlayerApi extends _i1.Mock returnValue: _i4.Future.value(), returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); + + @override + _i4.Future getAssetUrl( + String? asset, + String? package, + ) => + (super.noSuchMethod( + Invocation.method( + #getAssetUrl, + [ + asset, + package, + ], + ), + returnValue: _i4.Future.value(_i3.dummyValue( + this, + Invocation.method( + #getAssetUrl, + [ + asset, + package, + ], + ), + )), + returnValueForMissingStub: + _i4.Future.value(_i3.dummyValue( + this, + Invocation.method( + #getAssetUrl, + [ + asset, + package, + ], + ), + )), + ) as _i4.Future); } /// A class which mocks [VideoPlayerInstanceApi]. From e8bfe13e52d7c903b64989cd65ade6fdcc154a1b Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 24 Jul 2025 16:32:36 -0400 Subject: [PATCH 03/11] Remove the unused format hint --- .../include/video_player_avfoundation/messages.g.h | 2 -- .../Sources/video_player_avfoundation/messages.g.m | 8 ++------ .../lib/src/avfoundation_video_player.dart | 11 ----------- .../video_player_avfoundation/lib/src/messages.g.dart | 9 ++------- .../video_player_avfoundation/pigeons/messages.dart | 1 - .../test/avfoundation_video_player_test.dart | 2 -- 6 files changed, 4 insertions(+), 29 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h index 7dabbb3c6b2d..9779c1d901ba 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h @@ -40,11 +40,9 @@ typedef NS_ENUM(NSUInteger, FVPPlatformVideoViewType) { /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; + (instancetype)makeWithUri:(NSString *)uri - formatHint:(nullable NSString *)formatHint httpHeaders:(NSDictionary *)httpHeaders viewType:(FVPPlatformVideoViewType)viewType; @property(nonatomic, copy) NSString *uri; -@property(nonatomic, copy, nullable) NSString *formatHint; @property(nonatomic, copy) NSDictionary *httpHeaders; @property(nonatomic, assign) FVPPlatformVideoViewType viewType; @end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m index 36f786dc14ef..13076be0e915 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m @@ -78,12 +78,10 @@ + (nullable FVPPlatformVideoViewCreationParams *)nullableFromList:(NSArray * @implementation FVPCreationOptions + (instancetype)makeWithUri:(NSString *)uri - formatHint:(nullable NSString *)formatHint httpHeaders:(NSDictionary *)httpHeaders viewType:(FVPPlatformVideoViewType)viewType { FVPCreationOptions *pigeonResult = [[FVPCreationOptions alloc] init]; pigeonResult.uri = uri; - pigeonResult.formatHint = formatHint; pigeonResult.httpHeaders = httpHeaders; pigeonResult.viewType = viewType; return pigeonResult; @@ -91,9 +89,8 @@ + (instancetype)makeWithUri:(NSString *)uri + (FVPCreationOptions *)fromList:(NSArray *)list { FVPCreationOptions *pigeonResult = [[FVPCreationOptions alloc] init]; pigeonResult.uri = GetNullableObjectAtIndex(list, 0); - pigeonResult.formatHint = GetNullableObjectAtIndex(list, 1); - pigeonResult.httpHeaders = GetNullableObjectAtIndex(list, 2); - FVPPlatformVideoViewTypeBox *boxedFVPPlatformVideoViewType = GetNullableObjectAtIndex(list, 3); + pigeonResult.httpHeaders = GetNullableObjectAtIndex(list, 1); + FVPPlatformVideoViewTypeBox *boxedFVPPlatformVideoViewType = GetNullableObjectAtIndex(list, 2); pigeonResult.viewType = boxedFVPPlatformVideoViewType.value; return pigeonResult; } @@ -103,7 +100,6 @@ + (nullable FVPCreationOptions *)nullableFromList:(NSArray *)list { - (NSArray *)toList { return @[ self.uri ?: [NSNull null], - self.formatHint ?: [NSNull null], self.httpHeaders ?: [NSNull null], [[FVPPlatformVideoViewTypeBox alloc] initWithValue:self.viewType], ]; diff --git a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart index 2bbc776fa140..df9af1388a6f 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart @@ -75,7 +75,6 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { final VideoViewType viewType = options.viewType; String? uri; - String? formatHint; switch (dataSource.sourceType) { case DataSourceType.asset: final String? asset = dataSource.asset; @@ -90,7 +89,6 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { ); case DataSourceType.network: uri = dataSource.uri; - formatHint = _videoFormatStringMap[dataSource.formatHint]; case DataSourceType.file: uri = dataSource.uri; case DataSourceType.contentUri: @@ -102,7 +100,6 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { final CreationOptions pigeonCreationOptions = CreationOptions( uri: uri, httpHeaders: dataSource.httpHeaders, - formatHint: formatHint, viewType: _platformVideoViewTypeFromVideoViewType(viewType), ); @@ -255,14 +252,6 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { return player ?? (throw StateError('No active player with ID $id.')); } - static const Map _videoFormatStringMap = - { - VideoFormat.ss: 'ss', - VideoFormat.hls: 'hls', - VideoFormat.dash: 'dash', - VideoFormat.other: 'other', - }; - DurationRange _toDurationRange(dynamic value) { final List pair = value as List; return DurationRange( diff --git a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart index 0b989df912aa..59c67cb13b9e 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart @@ -85,15 +85,12 @@ class PlatformVideoViewCreationParams { class CreationOptions { CreationOptions({ required this.uri, - this.formatHint, required this.httpHeaders, required this.viewType, }); String uri; - String? formatHint; - Map httpHeaders; PlatformVideoViewType viewType; @@ -101,7 +98,6 @@ class CreationOptions { List _toList() { return [ uri, - formatHint, httpHeaders, viewType, ]; @@ -115,10 +111,9 @@ class CreationOptions { result as List; return CreationOptions( uri: result[0]! as String, - formatHint: result[1] as String?, httpHeaders: - (result[2] as Map?)!.cast(), - viewType: result[3]! as PlatformVideoViewType, + (result[1] as Map?)!.cast(), + viewType: result[2]! as PlatformVideoViewType, ); } diff --git a/packages/video_player/video_player_avfoundation/pigeons/messages.dart b/packages/video_player/video_player_avfoundation/pigeons/messages.dart index 9474103862ec..ff8733e6bdd3 100644 --- a/packages/video_player/video_player_avfoundation/pigeons/messages.dart +++ b/packages/video_player/video_player_avfoundation/pigeons/messages.dart @@ -40,7 +40,6 @@ class CreationOptions { }); String uri; - String? formatHint; Map httpHeaders; PlatformVideoViewType viewType; } diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart index 29de5c74c045..360551e16ee0 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart @@ -119,7 +119,6 @@ void main() { final CreationOptions creationOptions = verification.captured[0] as CreationOptions; expect(creationOptions.uri, uri); - expect(creationOptions.formatHint, 'dash'); expect(creationOptions.httpHeaders, {}); expect(playerId, newPlayerId); expect(player.playerViewStates[newPlayerId], @@ -232,7 +231,6 @@ void main() { final CreationOptions creationOptions = verification.captured[0] as CreationOptions; expect(creationOptions.uri, uri); - expect(creationOptions.formatHint, 'dash'); expect(creationOptions.httpHeaders, {}); expect(playerId, newPlayerId); expect(player.playerViewStates[newPlayerId], From 1d6bfa4aad755033350ff803b19408022a3251e0 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 24 Jul 2025 16:33:14 -0400 Subject: [PATCH 04/11] Consolidate switches --- .../lib/src/avfoundation_video_player.dart | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart index df9af1388a6f..0aebcfb4c9a0 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart @@ -88,9 +88,7 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { dataSource.package, ); case DataSourceType.network: - uri = dataSource.uri; case DataSourceType.file: - uri = dataSource.uri; case DataSourceType.contentUri: uri = dataSource.uri; } @@ -168,37 +166,33 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { .receiveBroadcastStream() .map((dynamic event) { final Map map = event as Map; - switch (map['event']) { - case 'initialized': - return VideoEvent( + return switch (map['event']) { + 'initialized' => VideoEvent( eventType: VideoEventType.initialized, duration: Duration(milliseconds: map['duration'] as int), - size: Size((map['width'] as num?)?.toDouble() ?? 0.0, - (map['height'] as num?)?.toDouble() ?? 0.0), - ); - case 'completed': - return VideoEvent( + size: Size( + (map['width'] as num?)?.toDouble() ?? 0.0, + (map['height'] as num?)?.toDouble() ?? 0.0, + ), + ), + 'completed' => VideoEvent( eventType: VideoEventType.completed, - ); - case 'bufferingUpdate': - final List values = map['values'] as List; - - return VideoEvent( - buffered: values.map(_toDurationRange).toList(), + ), + 'bufferingUpdate' => VideoEvent( + buffered: (map['values'] as List) + .map(_toDurationRange) + .toList(), eventType: VideoEventType.bufferingUpdate, - ); - case 'bufferingStart': - return VideoEvent(eventType: VideoEventType.bufferingStart); - case 'bufferingEnd': - return VideoEvent(eventType: VideoEventType.bufferingEnd); - case 'isPlayingStateUpdate': - return VideoEvent( + ), + 'bufferingStart' => + VideoEvent(eventType: VideoEventType.bufferingStart), + 'bufferingEnd' => VideoEvent(eventType: VideoEventType.bufferingEnd), + 'isPlayingStateUpdate' => VideoEvent( eventType: VideoEventType.isPlayingStateUpdate, isPlaying: map['isPlaying'] as bool, - ); - default: - return VideoEvent(eventType: VideoEventType.unknown); - } + ), + _ => VideoEvent(eventType: VideoEventType.unknown), + }; }); } From b5d07e5b97990ad5e15311ea9577ad42a6915fbc Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 24 Jul 2025 16:55:24 -0400 Subject: [PATCH 05/11] Remove some duplicate state --- .../FVPVideoPlayerPlugin.m | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 2f09dc666de4..b2f2f2b1ebaf 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -43,8 +43,6 @@ @implementation FVPDefaultDisplayLinkFactory #pragma mark - @interface FVPVideoPlayerPlugin () -@property(readonly, weak, nonatomic) NSObject *registry; -@property(readonly, weak, nonatomic) NSObject *messenger; @property(readonly, strong, nonatomic) NSObject *registrar; @property(nonatomic, strong) id displayLinkFactory; @property(nonatomic, strong) id avFactory; @@ -79,8 +77,6 @@ - (instancetype)initWithAVFactory:(id)avFactory registrar:(NSObject *)registrar { self = [super init]; NSAssert(self, @"super init cannot be nil"); - _registry = [registrar textures]; - _messenger = [registrar messenger]; _registrar = registrar; _viewProvider = viewProvider; _displayLinkFactory = displayLinkFactory ?: [[FVPDefaultDisplayLinkFactory alloc] init]; @@ -108,13 +104,13 @@ - (int64_t)onPlayerSetup:(FVPVideoPlayer *)player { int64_t playerIdentifier; if (textureBasedPlayer) { - playerIdentifier = [self.registry registerTexture:textureBasedPlayer]; + playerIdentifier = [self.registrar.textures registerTexture:textureBasedPlayer]; [textureBasedPlayer setTextureIdentifier:playerIdentifier]; } else { playerIdentifier = self.nextNonTexturePlayerIdentifier--; } - NSObject *messenger = self.messenger; + NSObject *messenger = self.registrar.messenger; NSString *channelSuffix = [NSString stringWithFormat:@"%lld", playerIdentifier]; // Set up the player-specific API handler, and its onDispose unregistration. SetUpFVPVideoPlayerInstanceApiWithSuffix(messenger, player, channelSuffix); @@ -123,7 +119,7 @@ - (int64_t)onPlayerSetup:(FVPVideoPlayer *)player { player.onDisposed = ^() { SetUpFVPVideoPlayerInstanceApiWithSuffix(messenger, nil, channelSuffix); if (isTextureBased) { - [weakSelf.registry unregisterTexture:playerIdentifier]; + [weakSelf.registrar.textures unregisterTexture:playerIdentifier]; } }; // Set up the event channel. @@ -211,7 +207,8 @@ - (nullable NSNumber *)createWithOptions:(nonnull FVPCreationOptions *)options - (nullable FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: (nonnull FVPCreationOptions *)options { - FVPFrameUpdater *frameUpdater = [[FVPFrameUpdater alloc] initWithRegistry:_registry]; + FVPFrameUpdater *frameUpdater = + [[FVPFrameUpdater alloc] initWithRegistry:self.registrar.textures]; NSObject *displayLink = [self.displayLinkFactory displayLinkWithRegistrar:_registrar callback:^() { From fba9c60d81c3b0cd075276207e692f19a4596cc1 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 24 Jul 2025 17:00:59 -0400 Subject: [PATCH 06/11] Fix pre-existing race in example code --- .../video_player_avfoundation/example/lib/main.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/example/lib/main.dart b/packages/video_player/video_player_avfoundation/example/lib/main.dart index f98516b20032..c3b61debf303 100644 --- a/packages/video_player/video_player_avfoundation/example/lib/main.dart +++ b/packages/video_player/video_player_avfoundation/example/lib/main.dart @@ -269,9 +269,9 @@ class _BumbleBeeEncryptedLiveStreamState _controller.addListener(() { setState(() {}); }); - _controller.initialize(); - - _controller.play(); + _controller.initialize().then((_) { + _controller.play(); + }); } @override From cbf14f42f6c935b75bae78813fccfc32a25e0437 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 25 Jul 2025 11:20:09 -0400 Subject: [PATCH 07/11] Version bump --- packages/video_player/video_player_avfoundation/CHANGELOG.md | 4 ++++ packages/video_player/video_player_avfoundation/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index bccc6346903e..e98f438609fe 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.8.1 + +* Restructures internal logic to move more code to Dart. + ## 2.8.0 * Adds platform view support for macOS. diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 1482e8a54576..29e56655cacd 100644 --- a/packages/video_player/video_player_avfoundation/pubspec.yaml +++ b/packages/video_player/video_player_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avfoundation description: iOS and macOS implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.8.0 +version: 2.8.1 environment: sdk: ^3.6.0 From b25e91eda0944f418f5b1851c4594d6243d16bc3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 25 Jul 2025 11:41:20 -0400 Subject: [PATCH 08/11] Update tests --- .../darwin/RunnerTests/VideoPlayerTests.m | 135 +++++------------- .../FVPVideoPlayerPlugin.m | 3 + .../video_player_avfoundation/messages.g.h | 1 - .../lib/src/avfoundation_video_player.dart | 8 ++ .../lib/src/messages.g.dart | 9 +- .../pigeons/messages.dart | 2 +- .../test/avfoundation_video_player_test.dart | 25 ++++ .../avfoundation_video_player_test.mocks.dart | 27 +--- 8 files changed, 79 insertions(+), 131 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m index 0dd84c551497..58ad53674d01 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m @@ -168,32 +168,6 @@ - (instancetype)init { @implementation VideoPlayerTests -- (void)testCreateWithOptionsReturnsErrorForInvalidAssetPath { - NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); - OCMStub([registrar lookupKeyForAsset:[OCMArg any]]).andReturn(nil); - FVPVideoPlayerPlugin *videoPlayerPlugin = - [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; - - FlutterError *initializationError; - [videoPlayerPlugin initialize:&initializationError]; - XCTAssertNil(initializationError); - - FVPCreationOptions *create = - [FVPCreationOptions makeWithAsset:@"invalid/path/to/asset" - uri:nil - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; - - FlutterError *createError; - NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError]; - - XCTAssertNil(playerIdentifier); - XCTAssertNotNil(createError); - XCTAssertEqualObjects(createError.code, @"video_player"); -} - - (void)testBlankVideoBugWithEncryptedVideoStreamAndInvertedAspectRatioBugForSomeVideoStream { // 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 @@ -218,12 +192,9 @@ - (void)testBlankVideoBugWithEncryptedVideoStreamAndInvertedAspectRatioBugForSom XCTAssertNil(error); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error]; XCTAssertNil(error); XCTAssertNotNil(playerIdentifier); @@ -253,12 +224,9 @@ - (void)testPlayerForPlatformViewDoesNotRegisterTexture { [videoPlayerPlugin initialize:&initalizationError]; XCTAssertNil(initalizationError); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypePlatformView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypePlatformView]; FlutterError *createError; [videoPlayerPlugin createWithOptions:create error:&createError]; @@ -284,12 +252,9 @@ - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily { [videoPlayerPlugin initialize:&initalizationError]; XCTAssertNil(initalizationError); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; FlutterError *createError; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError]; FVPTextureBasedVideoPlayer *player = @@ -344,12 +309,9 @@ - (void)testInitStartsDisplayLinkTemporarily { [videoPlayerPlugin initialize:&initalizationError]; XCTAssertNil(initalizationError); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; FlutterError *createError; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError]; @@ -393,12 +355,9 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink { [videoPlayerPlugin initialize:&initalizationError]; XCTAssertNil(initalizationError); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; FlutterError *createError; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError]; FVPTextureBasedVideoPlayer *player = @@ -451,12 +410,9 @@ - (void)testPauseWhileWaitingForFrameDoesNotStopDisplayLink { [videoPlayerPlugin initialize:&initalizationError]; XCTAssertNil(initalizationError); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; FlutterError *createError; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError]; FVPTextureBasedVideoPlayer *player = @@ -481,12 +437,9 @@ - (void)testDeregistersFromPlayer { XCTAssertNil(error); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error]; XCTAssertNil(error); XCTAssertNotNil(playerIdentifier); @@ -513,12 +466,9 @@ - (void)testBufferingStateFromPlayer { XCTAssertNil(error); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error]; XCTAssertNil(error); XCTAssertNotNil(playerIdentifier); @@ -709,12 +659,9 @@ - (void)testDoesNotCrashOnRateObservationAfterDisposal { XCTAssertNil(error); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error]; XCTAssertNil(error); XCTAssertNotNil(playerIdentifier); @@ -763,12 +710,9 @@ - (void)testHotReloadDoesNotCrash { XCTAssertNil(error); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error]; XCTAssertNil(error); XCTAssertNotNil(playerIdentifier); @@ -830,13 +774,9 @@ - (void)testFailedToLoadVideoEventShouldBeAlwaysSent { [videoPlayerPlugin initialize:&error]; - FVPCreationOptions *create = - [FVPCreationOptions makeWithAsset:nil - uri:@"" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + FVPCreationOptions *create = [FVPCreationOptions makeWithUri:@"" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error]; FVPVideoPlayer *player = videoPlayerPlugin.playersByIdentifier[playerIdentifier]; XCTAssertNotNil(player); @@ -896,12 +836,9 @@ - (void)testPlayerShouldNotDropEverySecondFrame { [videoPlayerPlugin initialize:&error]; XCTAssertNil(error); FVPCreationOptions *create = [FVPCreationOptions - makeWithAsset:nil - uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" - packageName:nil - formatHint:nil - httpHeaders:@{} - viewType:FVPPlatformVideoViewTypeTextureView]; + makeWithUri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4" + httpHeaders:@{} + viewType:FVPPlatformVideoViewTypeTextureView]; NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error]; FVPTextureBasedVideoPlayer *player = (FVPTextureBasedVideoPlayer *)videoPlayerPlugin.playersByIdentifier[playerIdentifier]; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index b2f2f2b1ebaf..0e06586113c1 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -269,6 +269,9 @@ - (nullable NSString *)fileURLForAssetWithName:(NSString *)asset } #endif + if (!path) { + return nil; + } return [NSURL fileURLWithPath:path].absoluteString; } diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h index 9779c1d901ba..b895043931e2 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h @@ -57,7 +57,6 @@ NSObject *FVPGetMessagesCodec(void); error:(FlutterError *_Nullable *_Nonnull)error; - (void)disposePlayer:(NSInteger)playerId error:(FlutterError *_Nullable *_Nonnull)error; - (void)setMixWithOthers:(BOOL)mixWithOthers error:(FlutterError *_Nullable *_Nonnull)error; -/// @return `nil` only when `error != nil`. - (nullable NSString *)fileURLForAssetWithName:(NSString *)asset package:(nullable NSString *)package error:(FlutterError *_Nullable *_Nonnull)error; diff --git a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart index 0aebcfb4c9a0..431bf725b954 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart @@ -87,6 +87,14 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { asset, dataSource.package, ); + if (uri == null) { + // Throw a platform exception for compatibility with the previous + // implementation, which threw on the native side. + throw PlatformException( + code: 'video_player', + message: + 'Asset $asset not found in package ${dataSource.package}.'); + } case DataSourceType.network: case DataSourceType.file: case DataSourceType.contentUri: diff --git a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart index 59c67cb13b9e..ae5ec1d9f6c8 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart @@ -294,7 +294,7 @@ class AVFoundationVideoPlayerApi { } } - Future getAssetUrl(String asset, String? package) async { + Future getAssetUrl(String asset, String? package) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.getAssetUrl$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = @@ -315,13 +315,8 @@ class AVFoundationVideoPlayerApi { message: pigeonVar_replyList[1] as String?, details: pigeonVar_replyList[2], ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); } else { - return (pigeonVar_replyList[0] as String?)!; + return (pigeonVar_replyList[0] as String?); } } } diff --git a/packages/video_player/video_player_avfoundation/pigeons/messages.dart b/packages/video_player/video_player_avfoundation/pigeons/messages.dart index ff8733e6bdd3..4b336cca5e6f 100644 --- a/packages/video_player/video_player_avfoundation/pigeons/messages.dart +++ b/packages/video_player/video_player_avfoundation/pigeons/messages.dart @@ -56,7 +56,7 @@ abstract class AVFoundationVideoPlayerApi { @ObjCSelector('setMixWithOthers:') void setMixWithOthers(bool mixWithOthers); @ObjCSelector('fileURLForAssetWithName:package:') - String getAssetUrl(String asset, String? package); + String? getAssetUrl(String asset, String? package); } @HostApi() diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart index 360551e16ee0..cd581a5c3b0c 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart @@ -97,6 +97,31 @@ void main() { const VideoPlayerTextureViewState(textureId: newPlayerId)); }); + test('create with asset throws PlatformException for missing asset', + () async { + final ( + AVFoundationVideoPlayer player, + MockAVFoundationVideoPlayerApi api, + _, + ) = setUpMockPlayer(playerId: 1); + + const String asset = 'someAsset'; + const String package = 'somePackage'; + when( + api.getAssetUrl(asset, package), + ).thenAnswer((_) async => null); + + expect( + player.create( + DataSource( + sourceType: DataSourceType.asset, + asset: asset, + package: package, + ), + ), + throwsA(isA())); + }); + test('create with network', () async { final ( AVFoundationVideoPlayer player, diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart index 3bd52e5d2ddf..76199b56c02d 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart @@ -83,7 +83,7 @@ class MockAVFoundationVideoPlayerApi extends _i1.Mock ) as _i4.Future); @override - _i4.Future getAssetUrl( + _i4.Future getAssetUrl( String? asset, String? package, ) => @@ -95,28 +95,9 @@ class MockAVFoundationVideoPlayerApi extends _i1.Mock package, ], ), - returnValue: _i4.Future.value(_i3.dummyValue( - this, - Invocation.method( - #getAssetUrl, - [ - asset, - package, - ], - ), - )), - returnValueForMissingStub: - _i4.Future.value(_i3.dummyValue( - this, - Invocation.method( - #getAssetUrl, - [ - asset, - package, - ], - ), - )), - ) as _i4.Future); + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); } /// A class which mocks [VideoPlayerInstanceApi]. From 4f70486642f4397087c59a8087ca271d5be85d9d Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 28 Jul 2025 10:47:05 -0400 Subject: [PATCH 09/11] Remove nil player handling; creating a player can't return nil --- .../video_player_avfoundation/FVPVideoPlayerPlugin.m | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 0e06586113c1..2fc01b647b35 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -192,12 +192,6 @@ - (nullable NSNumber *)createWithOptions:(nonnull FVPCreationOptions *)options @try { FVPVideoPlayer *player = textureBased ? [self texturePlayerWithOptions:options] : [self platformViewPlayerWithOptions:options]; - - if (player == nil) { - *error = [FlutterError errorWithCode:@"video_player" message:@"not implemented" details:nil]; - return nil; - } - return @([self onPlayerSetup:player]); } @catch (NSException *exception) { *error = [FlutterError errorWithCode:@"video_player" message:exception.reason details:nil]; @@ -205,7 +199,7 @@ - (nullable NSNumber *)createWithOptions:(nonnull FVPCreationOptions *)options } } -- (nullable FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: +- (nonnull FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: (nonnull FVPCreationOptions *)options { FVPFrameUpdater *frameUpdater = [[FVPFrameUpdater alloc] initWithRegistry:self.registrar.textures]; @@ -223,7 +217,7 @@ - (nullable FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: viewProvider:self.viewProvider]; } -- (nullable FVPVideoPlayer *)platformViewPlayerWithOptions:(nonnull FVPCreationOptions *)options { +- (nonnull FVPVideoPlayer *)platformViewPlayerWithOptions:(nonnull FVPCreationOptions *)options { // FVPVideoPlayer contains all required logic for platform views. return [[FVPVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] httpHeaders:options.httpHeaders From ece0bb3a0af4f744bd1d38d6da7deb4949a09523 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 28 Jul 2025 10:57:17 -0400 Subject: [PATCH 10/11] macOS fix --- .../Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 2fc01b647b35..4c53923cd424 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -259,7 +259,7 @@ - (nullable NSString *)fileURLForAssetWithName:(NSString *)asset // See https://github.com/flutter/flutter/issues/135302 // TODO(stuartmorgan): Remove this if the asset APIs are adjusted to work better for macOS. if (!path) { - path = [NSURL URLWithString:assetName relativeToURL:NSBundle.mainBundle.bundleURL].path; + path = [NSURL URLWithString:resource relativeToURL:NSBundle.mainBundle.bundleURL].path; } #endif From a2af01db11c54e326d820d952047140a194885aa Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 29 Jul 2025 11:43:05 -0400 Subject: [PATCH 11/11] Move buffer duration transform logic --- .../Sources/video_player_avfoundation/FVPVideoPlayer.m | 6 ++++-- .../lib/src/avfoundation_video_player.dart | 6 ++++-- .../test/avfoundation_video_player_test.dart | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m index 17d2a77cd08c..acf5bf608050 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m @@ -229,8 +229,10 @@ - (void)observeValueForKeyPath:(NSString *)path NSMutableArray *> *values = [[NSMutableArray alloc] init]; for (NSValue *rangeValue in [object loadedTimeRanges]) { CMTimeRange range = [rangeValue CMTimeRangeValue]; - int64_t start = FVPCMTimeToMillis(range.start); - [values addObject:@[ @(start), @(start + FVPCMTimeToMillis(range.duration)) ]]; + [values addObject:@[ + @(FVPCMTimeToMillis(range.start)), + @(FVPCMTimeToMillis(range.duration)), + ]]; } _eventSink(@{@"event" : @"bufferingUpdate", @"values" : values}); } diff --git a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart index 431bf725b954..3558dccd67c9 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart @@ -256,9 +256,11 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { DurationRange _toDurationRange(dynamic value) { final List pair = value as List; + final int startMilliseconds = pair[0] as int; + final int durationMilliseconds = pair[1] as int; return DurationRange( - Duration(milliseconds: pair[0] as int), - Duration(milliseconds: pair[1] as int), + Duration(milliseconds: startMilliseconds), + Duration(milliseconds: startMilliseconds + durationMilliseconds), ); } } diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart index cd581a5c3b0c..fb367310ec17 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart @@ -576,7 +576,7 @@ void main() { ), DurationRange( const Duration(milliseconds: 1235), - const Duration(milliseconds: 4000), + const Duration(milliseconds: 1235 + 4000), ), ]), VideoEvent(eventType: VideoEventType.bufferingStart),