Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit ff13ad0

Browse files
committed
Return a copy of the last valid frame
1 parent 9e9aec7 commit ff13ad0

File tree

1 file changed

+32
-11
lines changed

1 file changed

+32
-11
lines changed

packages/video_player/video_player_macos/macos/Classes/FLTVideoPlayerPlugin.m

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ @interface FLTVideoPlayer : NSObject <FlutterTexture, FlutterStreamHandler>
4141
@property(readonly, nonatomic) AVPlayerItemVideoOutput* videoOutput;
4242
@property(readonly, nonatomic) CVDisplayLinkRef displayLink;
4343
@property(readonly, nonatomic) FLTFrameUpdater* frameUpdater;
44-
@property(readonly, nonatomic) CVPixelBufferRef _Nullable frame;
44+
@property(readonly, nonatomic) CVPixelBufferRef _Nullable lastValidFrame;
4545
@property(nonatomic) FlutterEventChannel* eventChannel;
4646
@property(nonatomic) FlutterEventSink eventSink;
4747
@property(nonatomic) CGAffineTransform preferredTransform;
@@ -170,10 +170,10 @@ - (void)notifyIfFrameAvailable {
170170
if (!_playerItem || _playerItem.status != AVPlayerItemStatusReadyToPlay || ![_videoOutput hasNewPixelBufferForItemTime:outputItemTime]) {
171171
return;
172172
} else {
173-
CVBufferRelease(_frame);
174-
_frame = [_videoOutput copyPixelBufferForItemTime:outputItemTime itemTimeForDisplay:NULL];
175-
if (_frame == NULL) {
176-
NSLog(@"copyPixelBufferForItemTime returned NULL");
173+
CVPixelBufferRef pixelBuffer = [_videoOutput copyPixelBufferForItemTime:outputItemTime itemTimeForDisplay:NULL];
174+
if (pixelBuffer != NULL) {
175+
CVBufferRelease(_lastValidFrame);
176+
_lastValidFrame = pixelBuffer;
177177
}
178178
[_frameUpdater notifyFrameAvailable];
179179
}
@@ -441,11 +441,32 @@ - (void)setPlaybackSpeed:(double)speed {
441441
}
442442

443443
- (CVPixelBufferRef)copyPixelBuffer {
444-
if (_frame == NULL) {
445-
NSLog(@"Returning NULL from copyPixelBuffer");
446-
}
447-
CVBufferRetain(_frame);
448-
return _frame;
444+
// Creates a memcpy of the last valid frame.
445+
//
446+
// Unlike on iOS, the macOS embedder does show the last frame when
447+
// we return NULL from `copyPixelBuffer`.
448+
CVPixelBufferLockBaseAddress(_lastValidFrame, kCVPixelBufferLock_ReadOnly);
449+
int bufferWidth = (int)CVPixelBufferGetWidth(_lastValidFrame);
450+
int bufferHeight = (int)CVPixelBufferGetHeight(_lastValidFrame);
451+
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(_lastValidFrame);
452+
uint8_t *baseAddress = CVPixelBufferGetBaseAddress(_lastValidFrame);
453+
NSDictionary* pixBuffAttributes = @{
454+
(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA),
455+
(id)kCVPixelBufferIOSurfacePropertiesKey : @{},
456+
(id)kCVPixelBufferOpenGLCompatibilityKey : @YES,
457+
(id)kCVPixelBufferMetalCompatibilityKey : @YES,
458+
};
459+
460+
CVPixelBufferRef pixelBufferCopy = NULL;
461+
CVPixelBufferCreate(kCFAllocatorDefault, bufferWidth, bufferHeight,kCVPixelFormatType_32BGRA,
462+
CFBridgingRetain(pixBuffAttributes), &pixelBufferCopy);
463+
CVPixelBufferLockBaseAddress(pixelBufferCopy, 0);
464+
uint8_t *copyBaseAddress = CVPixelBufferGetBaseAddress(pixelBufferCopy);
465+
memcpy(copyBaseAddress, baseAddress, bufferHeight * bytesPerRow);
466+
467+
CVPixelBufferUnlockBaseAddress(_lastValidFrame, kCVPixelBufferLock_ReadOnly);
468+
CVPixelBufferUnlockBaseAddress(pixelBufferCopy, 0);
469+
return pixelBufferCopy;
449470
}
450471

451472
- (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture {
@@ -476,7 +497,7 @@ - (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments
476497
/// so the channel is going to die or is already dead.
477498
- (void)disposeSansEventChannel {
478499
_disposed = true;
479-
CVBufferRelease(_frame);
500+
CVBufferRelease(_lastValidFrame);
480501
[self stopDisplayLink];
481502
[[_player currentItem] removeObserver:self forKeyPath:@"status" context:statusContext];
482503
[[_player currentItem] removeObserver:self

0 commit comments

Comments
 (0)