Skip to content

Commit 8dde36b

Browse files
[video_player] Avoid returning no frame on macOS
While the display-link-driven frame updater will only inform the engine that a frame is available when the underlying player has a frame for the current time, there's no guarantee that the player will have a frame for the time that is current when the engine actually requests the frame. To avoid flickering from returning no frame, if a frame isn't available for the current time when it is requested, provide the frame that was known to be available when the request was triggered in the first place. Fixes flutter/flutter#135999
1 parent 5badf97 commit 8dde36b

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

packages/video_player/video_player_avfoundation/darwin/Classes/FVPVideoPlayerPlugin.m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ @interface FVPFrameUpdater : NSObject
2020
@property(nonatomic, weak, readonly) NSObject<FlutterTextureRegistry> *registry;
2121
// The output that this updater is managing.
2222
@property(nonatomic, weak) AVPlayerItemVideoOutput *videoOutput;
23+
// The last time that has been validated as avaliable according to hasNewPixelBufferForItemTime:.
24+
@property(nonatomic, assign) CMTime lastKnownAvailableTime;
2325
#if TARGET_OS_IOS
2426
- (void)onDisplayLink:(CADisplayLink *)link;
2527
#endif
@@ -30,6 +32,7 @@ - (FVPFrameUpdater *)initWithRegistry:(NSObject<FlutterTextureRegistry> *)regist
3032
NSAssert(self, @"super init cannot be nil");
3133
if (self == nil) return nil;
3234
_registry = registry;
35+
_lastKnownAvailableTime = kCMTimeInvalid;
3336
return self;
3437
}
3538

@@ -45,6 +48,7 @@ - (void)displayLinkFired {
4548
// Only report a new frame if one is actually available.
4649
CMTime outputItemTime = [self.videoOutput itemTimeForHostTime:CACurrentMediaTime()];
4750
if ([self.videoOutput hasNewPixelBufferForItemTime:outputItemTime]) {
51+
_lastKnownAvailableTime = outputItemTime;
4852
[_registry textureFrameAvailable:_textureId];
4953
}
5054
}
@@ -91,6 +95,7 @@ @interface FVPVideoPlayer : NSObject <FlutterTexture, FlutterStreamHandler>
9195
@property(nonatomic, readonly) BOOL isPlaying;
9296
@property(nonatomic) BOOL isLooping;
9397
@property(nonatomic, readonly) BOOL isInitialized;
98+
@property(nonatomic) FVPFrameUpdater *frameUpdater;
9499
// TODO(stuartmorgan): Extract and abstract the display link to remove all the display-link-related
95100
// ifdefs from this file.
96101
#if TARGET_OS_OSX
@@ -298,6 +303,7 @@ - (instancetype)initWithPlayerItem:(AVPlayerItem *)item
298303
NSAssert(self, @"super init cannot be nil");
299304

300305
_registrar = registrar;
306+
_frameUpdater = frameUpdater;
301307

302308
AVAsset *asset = [item asset];
303309
void (^assetCompletionHandler)(void) = ^{
@@ -562,6 +568,12 @@ - (CVPixelBufferRef)copyPixelBuffer {
562568
if ([_videoOutput hasNewPixelBufferForItemTime:outputItemTime]) {
563569
return [_videoOutput copyPixelBufferForItemTime:outputItemTime itemTimeForDisplay:NULL];
564570
} else {
571+
// If the current time isn't available yet, use the time that was checked when informing the
572+
// engine that a frame was available (if any).
573+
CMTime lastAvailableTime = self.frameUpdater.lastKnownAvailableTime;
574+
if (CMTIME_IS_VALID(lastAvailableTime)) {
575+
return [_videoOutput copyPixelBufferForItemTime:lastAvailableTime itemTimeForDisplay:NULL];
576+
}
565577
return NULL;
566578
}
567579
}

packages/video_player/video_player_avfoundation/example/macos/Runner.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6868
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
6969
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
70-
33683FF02ABCAC94007305E4 /* VideoPlayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VideoPlayerTests.m; path = ../../../darwin/RunnerTests/VideoPlayerTests.m; sourceTree = "<group>"; };
70+
33683FF02ABCAC94007305E4 /* VideoPlayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VideoPlayerTests.m; path = ../../darwin/RunnerTests/VideoPlayerTests.m; sourceTree = SOURCE_ROOT; };
7171
33CC10ED2044A3C60003C045 /* video_player_avfoundation_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = video_player_avfoundation_example.app; sourceTree = BUILT_PRODUCTS_DIR; };
7272
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7373
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };

0 commit comments

Comments
 (0)