Skip to content

Commit

Permalink
[video_player] Make video player avfoundation seek to async (flutter#…
Browse files Browse the repository at this point in the history
…3299)

[video_player] Make video player avfoundation seek to async
  • Loading branch information
gabrielgarciagava authored Mar 15, 2023
1 parent 8972499 commit 55515f6
Show file tree
Hide file tree
Showing 11 changed files with 365 additions and 340 deletions.
4 changes: 4 additions & 0 deletions packages/video_player/video_player_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.4.2

* Makes seekTo async and only complete when AVPlayer.seekTo completes.

## 2.4.1

* Clarifies explanation of endorsement in README.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ void main() {

await controller.seekTo(const Duration(seconds: 3));

// TODO(stuartmorgan): Switch to _controller.position once seekTo is
// fixed on the native side to wait for completion, so this is testing
// the native code rather than the MiniController position cache.
expect(controller.value.position, const Duration(seconds: 3));
expect(await controller.position, const Duration(seconds: 3));
});

testWidgets('can be paused', (WidgetTester tester) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@interface FLTVideoPlayer : NSObject <FlutterStreamHandler>
@property(readonly, nonatomic) AVPlayer *player;
@property(readonly, nonatomic) AVPlayerLayer *playerLayer;
@property(readonly, nonatomic) int64_t position;
@end

@interface FLTVideoPlayerPlugin (Test) <FLTAVFoundationVideoPlayerApi>
Expand Down Expand Up @@ -106,10 +107,30 @@ - (void)testSeekToInvokesTextureFrameAvailableOnTextureRegistry {
OCMStub([partialRegistrar textures]).andReturn(mockTextureRegistry);
FLTVideoPlayerPlugin *videoPlayerPlugin =
(FLTVideoPlayerPlugin *)[[FLTVideoPlayerPlugin alloc] initWithRegistrar:partialRegistrar];
FLTPositionMessage *message = [FLTPositionMessage makeWithTextureId:@101 position:@0];

FlutterError *error;
[videoPlayerPlugin seekTo:message error:&error];
[videoPlayerPlugin initialize:&error];
XCTAssertNil(error);
FLTCreateMessage *create = [FLTCreateMessage
makeWithAsset:nil
uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8"
packageName:nil
formatHint:nil
httpHeaders:@{}];
FLTTextureMessage *textureMessage = [videoPlayerPlugin create:create error:&error];
NSNumber *textureId = textureMessage.textureId;

XCTestExpectation *initializedExpectation = [self expectationWithDescription:@"seekTo completes"];
FLTPositionMessage *message = [FLTPositionMessage makeWithTextureId:textureId position:@1234];
[videoPlayerPlugin seekTo:message
completion:^(FlutterError *_Nullable error) {
[initializedExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:30.0 handler:nil];
OCMVerify([mockTextureRegistry textureFrameAvailable:message.textureId.intValue]);

FLTVideoPlayer *player = videoPlayerPlugin.playersByTextureId[textureId];
XCTAssertEqual([player position], 1234);
}

- (void)testDeregistersFromPlayer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,13 +403,11 @@ - (int64_t)duration {
return FLTCMTimeToMillis([[[_player currentItem] asset] duration]);
}

- (void)seekTo:(int)location {
// TODO(stuartmorgan): Update this to use completionHandler: to only return
// once the seek operation is complete once the Pigeon API is updated to a
// version that handles async calls.
- (void)seekTo:(int)location completionHandler:(void (^)(BOOL))completionHandler {
[_player seekToTime:CMTimeMake(location, 1000)
toleranceBefore:kCMTimeZero
toleranceAfter:kCMTimeZero];
toleranceBefore:kCMTimeZero
toleranceAfter:kCMTimeZero
completionHandler:completionHandler];
}

- (void)setIsLooping:(BOOL)isLooping {
Expand Down Expand Up @@ -636,10 +634,16 @@ - (FLTPositionMessage *)position:(FLTTextureMessage *)input error:(FlutterError
return result;
}

- (void)seekTo:(FLTPositionMessage *)input error:(FlutterError **)error {
- (void)seekTo:(FLTPositionMessage *)input
completion:(void (^)(FlutterError *_Nullable))completion {
FLTVideoPlayer *player = self.playersByTextureId[input.textureId];
[player seekTo:input.position.intValue];
[self.registry textureFrameAvailable:input.textureId.intValue];
[player seekTo:input.position.intValue
completionHandler:^(BOOL finished) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.registry textureFrameAvailable:input.textureId.intValue];
completion(nil);
});
}];
}

- (void)pause:(FLTTextureMessage *)input error:(FlutterError **)error {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v2.0.1), do not edit directly.
// Autogenerated from Pigeon (v8.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon

#import <Foundation/Foundation.h>

@protocol FlutterBinaryMessenger;
@protocol FlutterMessageCodec;
@class FlutterError;
Expand Down Expand Up @@ -97,7 +99,7 @@ NSObject<FlutterMessageCodec> *FLTAVFoundationVideoPlayerApiGetCodec(void);
/// @return `nil` only when `error != nil`.
- (nullable FLTPositionMessage *)position:(FLTTextureMessage *)msg
error:(FlutterError *_Nullable *_Nonnull)error;
- (void)seekTo:(FLTPositionMessage *)msg error:(FlutterError *_Nullable *_Nonnull)error;
- (void)seekTo:(FLTPositionMessage *)msg completion:(void (^)(FlutterError *_Nullable))completion;
- (void)pause:(FLTTextureMessage *)msg error:(FlutterError *_Nullable *_Nonnull)error;
- (void)setMixWithOthers:(FLTMixWithOthersMessage *)msg
error:(FlutterError *_Nullable *_Nonnull)error;
Expand Down
Loading

0 comments on commit 55515f6

Please sign in to comment.