From a75e9063ac3dcfc417121d756b74eadb79180959 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:31:18 +0200 Subject: [PATCH 1/7] fix playback speed resetting --- .../video_player_avfoundation/CHANGELOG.md | 3 +- .../darwin/RunnerTests/VideoPlayerTests.m | 37 ++++++++++++ .../FVPVideoPlayerPlugin.m | 58 ++++++++++++------- .../video_player_avfoundation/pubspec.yaml | 2 +- 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index e51f69fd6138..39566a2ab103 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.6.2 +* Fixes playback speed resetting. * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. ## 2.6.1 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 3ec96e78538a..312d1ca0c202 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m @@ -656,6 +656,8 @@ - (void)testSeekToleranceWhenSeekingToEnd { // Change playback speed. [videoPlayerPlugin setPlaybackSpeed:2 forPlayer:textureId.integerValue error:&error]; XCTAssertNil(error); + [videoPlayerPlugin playPlayer:textureId.integerValue error:&error]; + XCTAssertNil(error); XCTAssertEqual(avPlayer.rate, 2); XCTAssertEqual(avPlayer.timeControlStatus, AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate); @@ -790,6 +792,41 @@ - (void)testPublishesInRegistration { XCTAssertTrue([publishedValue isKindOfClass:[FVPVideoPlayerPlugin class]]); } +- (void)testUpdatePlayingStateShouldNotResetRate { + NSObject *registrar = + [GetPluginRegistry() registrarForPlugin:@"testUpdatePlayingStateShouldNotResetRate"]; + + FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] + initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:nil] + displayLinkFactory:nil + registrar:registrar]; + + FlutterError *error; + [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:@{}]; + NSNumber *textureId = [videoPlayerPlugin createWithOptions:create error:&error]; + FVPVideoPlayer *player = videoPlayerPlugin.playersByTextureId[textureId]; + + XCTestExpectation *initializedExpectation = [self expectationWithDescription:@"initialized"]; + [player onListenWithArguments:nil + eventSink:^(NSDictionary *event) { + if ([event[@"event"] isEqualToString:@"initialized"]) { + [initializedExpectation fulfill]; + } + }]; + [self waitForExpectationsWithTimeout:10 handler:nil]; + + [videoPlayerPlugin setPlaybackSpeed:2 forPlayer:textureId.integerValue error:&error]; + [videoPlayerPlugin playPlayer:textureId.integerValue error:&error]; + XCTAssertEqual(player.player.rate, 2); +} + #if TARGET_OS_IOS - (void)validateTransformFixForOrientation:(UIImageOrientation)orientation { AVAssetTrack *track = [[FakeAVAssetTrack alloc] initWithOrientation:orientation]; 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 14ee7ccefde2..d5cba56156dc 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 @@ -82,6 +82,8 @@ @interface FVPVideoPlayer () @property(nonatomic) CGAffineTransform preferredTransform; @property(nonatomic, readonly) BOOL disposed; @property(nonatomic, readonly) BOOL isPlaying; +// Playback speed when video is playing. +@property(nonatomic, readonly) NSNumber *playbackSpeed; @property(nonatomic) BOOL isLooping; @property(nonatomic, readonly) BOOL isInitialized; // The updater that drives callbacks to the engine to indicate that a new frame is ready. @@ -397,7 +399,15 @@ - (void)updatePlayingState { return; } if (_isPlaying) { - [_player play]; + // Calling play is the same as setting the rate to 1.0 (or to defaultRate depending on ios + // version) so last set playback speed must be set here if any instead. + // https://github.com/flutter/flutter/issues/71264 + // https://github.com/flutter/flutter/issues/73643 + if (_playbackSpeed) { + [self updateRate]; + } else { + [_player play]; + } } else { [_player pause]; } @@ -406,6 +416,29 @@ - (void)updatePlayingState { _displayLink.running = _isPlaying || self.waitingForFrame; } +- (void)updateRate { + // See https://developer.apple.com/library/archive/qa/qa1772/_index.html for an explanation of + // these checks. + // If status is not AVPlayerItemStatusReadyToPlay then both canPlayFastForward + // and canPlaySlowForward are always false and it is unknown whether video can + // be played at these speeds, updatePlayingState will be called again when + // status changes to AVPlayerItemStatusReadyToPlay. + float speed = _playbackSpeed.floatValue; + if (speed > 2.0 && !_player.currentItem.canPlayFastForward) { + if (_player.currentItem.status != AVPlayerItemStatusReadyToPlay) { + return; + } + speed = 2.0; + } + if (speed < 1.0 && !_player.currentItem.canPlaySlowForward) { + if (_player.currentItem.status != AVPlayerItemStatusReadyToPlay) { + return; + } + speed = 1.0; + } + _player.rate = speed; +} + - (void)setupEventSinkIfReadyToPlay { if (_eventSink && !_isInitialized) { AVPlayerItem *currentItem = self.player.currentItem; @@ -519,27 +552,8 @@ - (void)setVolume:(double)volume { } - (void)setPlaybackSpeed:(double)speed { - // See https://developer.apple.com/library/archive/qa/qa1772/_index.html for an explanation of - // these checks. - if (speed > 2.0 && !_player.currentItem.canPlayFastForward) { - if (_eventSink != nil) { - _eventSink([FlutterError errorWithCode:@"VideoError" - message:@"Video cannot be fast-forwarded beyond 2.0x" - details:nil]); - } - return; - } - - if (speed < 1.0 && !_player.currentItem.canPlaySlowForward) { - if (_eventSink != nil) { - _eventSink([FlutterError errorWithCode:@"VideoError" - message:@"Video cannot be slow-forwarded" - details:nil]); - } - return; - } - - _player.rate = speed; + _playbackSpeed = @(speed); + [self updatePlayingState]; } - (CVPixelBufferRef)copyPixelBuffer { diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index dad297f40207..63952af7c43e 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.6.1 +version: 2.6.2 environment: sdk: ^3.3.0 From 9de97006a0c17e6a50a88ed75c486d81d9c6ee33 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Sun, 13 Oct 2024 20:09:03 +0200 Subject: [PATCH 2/7] fetch status before canPlay calls --- packages/video_player/video_player_avfoundation/CHANGELOG.md | 2 +- .../Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m | 5 +++-- packages/video_player/video_player_avfoundation/pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index 39566a2ab103..6bb46518c5ae 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.6.2 +## 2.6.3 * Fixes playback speed resetting. * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. 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 d5cba56156dc..d876e5f35d05 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 @@ -424,14 +424,15 @@ - (void)updateRate { // be played at these speeds, updatePlayingState will be called again when // status changes to AVPlayerItemStatusReadyToPlay. float speed = _playbackSpeed.floatValue; + bool readyToPlay = _player.currentItem.status == AVPlayerItemStatusReadyToPlay; if (speed > 2.0 && !_player.currentItem.canPlayFastForward) { - if (_player.currentItem.status != AVPlayerItemStatusReadyToPlay) { + if (!readyToPlay) { return; } speed = 2.0; } if (speed < 1.0 && !_player.currentItem.canPlaySlowForward) { - if (_player.currentItem.status != AVPlayerItemStatusReadyToPlay) { + if (!readyToPlay) { return; } speed = 1.0; diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 63952af7c43e..0d04e93ed114 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.6.2 +version: 2.6.3 environment: sdk: ^3.3.0 From a1e0361b3814259ac5afcf752e320c45d64196d0 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:48:10 +0100 Subject: [PATCH 3/7] change few names and comments --- .../FVPVideoPlayerPlugin.m | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 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 d876e5f35d05..6b7a9865ed51 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 @@ -82,8 +82,8 @@ @interface FVPVideoPlayer () @property(nonatomic) CGAffineTransform preferredTransform; @property(nonatomic, readonly) BOOL disposed; @property(nonatomic, readonly) BOOL isPlaying; -// Playback speed when video is playing. -@property(nonatomic, readonly) NSNumber *playbackSpeed; +// The target playback speed requested by the plugin client. +@property(nonatomic, readonly) NSNumber *targetPlaybackSpeed; @property(nonatomic) BOOL isLooping; @property(nonatomic, readonly) BOOL isInitialized; // The updater that drives callbacks to the engine to indicate that a new frame is ready. @@ -399,11 +399,11 @@ - (void)updatePlayingState { return; } if (_isPlaying) { - // Calling play is the same as setting the rate to 1.0 (or to defaultRate depending on ios + // Calling play is the same as setting the rate to 1.0 (or to defaultRate depending on iOS // version) so last set playback speed must be set here if any instead. // https://github.com/flutter/flutter/issues/71264 // https://github.com/flutter/flutter/issues/73643 - if (_playbackSpeed) { + if (_targetPlaybackSpeed) { [self updateRate]; } else { [_player play]; @@ -416,6 +416,7 @@ - (void)updatePlayingState { _displayLink.running = _isPlaying || self.waitingForFrame; } +/// Synchronizes the player's playback rate with targetPlaybackSpeed, constrained by the playback rate capabilities of the player. - (void)updateRate { // See https://developer.apple.com/library/archive/qa/qa1772/_index.html for an explanation of // these checks. @@ -423,8 +424,8 @@ - (void)updateRate { // and canPlaySlowForward are always false and it is unknown whether video can // be played at these speeds, updatePlayingState will be called again when // status changes to AVPlayerItemStatusReadyToPlay. - float speed = _playbackSpeed.floatValue; - bool readyToPlay = _player.currentItem.status == AVPlayerItemStatusReadyToPlay; + float speed = _targetPlaybackSpeed.floatValue; + BOOL readyToPlay = _player.currentItem.status == AVPlayerItemStatusReadyToPlay; if (speed > 2.0 && !_player.currentItem.canPlayFastForward) { if (!readyToPlay) { return; @@ -553,7 +554,7 @@ - (void)setVolume:(double)volume { } - (void)setPlaybackSpeed:(double)speed { - _playbackSpeed = @(speed); + _targetPlaybackSpeed = @(speed); [self updatePlayingState]; } From ba861873a2371390236da4183cfaccc95c1792b9 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:50:19 +0100 Subject: [PATCH 4/7] update version --- packages/video_player/video_player_avfoundation/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 31d615dd8862..233a9b65e86b 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.6.3 +version: 2.6.4 environment: sdk: ^3.3.0 From 0c74a2026183dec0a0b287365941858c539f6638 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:51:16 +0100 Subject: [PATCH 5/7] update version --- packages/video_player/video_player_avfoundation/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index dae319fea351..51d7c625451d 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.6.3 +## 2.6.4 * Fixes playback speed resetting. From e9716fc10777eea471b9093b6649d20aec9c1ab7 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:37:17 +0100 Subject: [PATCH 6/7] change comment --- .../Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m | 3 ++- 1 file changed, 2 insertions(+), 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 34807cbb1b2a..4b19332c4da2 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 @@ -410,7 +410,8 @@ - (void)updatePlayingState { _displayLink.running = _isPlaying || self.waitingForFrame; } -/// Synchronizes the player's playback rate with targetPlaybackSpeed, constrained by the playback rate capabilities of the player. +/// Synchronizes the player's playback rate with targetPlaybackSpeed, constrained by the playback +/// rate capabilities of the player's current item. - (void)updateRate { // See https://developer.apple.com/library/archive/qa/qa1772/_index.html for an explanation of // these checks. From 45f49c3bc80b7ba5926a39a5a6ab85aa76dd2877 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 14 Jan 2025 16:25:41 -0500 Subject: [PATCH 7/7] Re-bump version --- packages/video_player/video_player_avfoundation/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index c20357d78044..c7f9dadb777b 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.6.6 +version: 2.6.7 environment: sdk: ^3.4.0