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

[video_player] Initialize player when size and duration become available #4438

Merged
merged 2 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/video_player/video_player/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.2.6

* Initialize player when size and duration become available on iOS

## 2.2.5

* Support to closed caption WebVTT format added.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 50;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -269,7 +269,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1100;
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "The Flutter Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,46 @@ - (void)setUp {
[self.app launch];
}

- (void)testTabs {
- (void)testPlayVideo {
XCUIApplication* app = self.app;

XCUIElement* remoteTab = [app.otherElements
elementMatchingPredicate:[NSPredicate predicateWithFormat:@"selected == YES"]];
if (![remoteTab waitForExistenceWithTimeout:30.0]) {
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
XCTFail(@"Failed due to not able to find selected Remote tab");
}
XCTAssertTrue([remoteTab waitForExistenceWithTimeout:30.0]);
XCTAssertTrue([remoteTab.label containsString:@"Remote"]);

XCUIElement* playButton = app.staticTexts[@"Play"];
XCTAssertTrue([playButton waitForExistenceWithTimeout:30.0]);
[playButton tap];

XCUIElement* chirpClosedCaption = app.staticTexts[@"[ Birds chirping ]"];
XCTAssertTrue([chirpClosedCaption waitForExistenceWithTimeout:30.0]);

XCUIElement* buzzClosedCaption = app.staticTexts[@"[ Buzzing ]"];
XCTAssertTrue([buzzClosedCaption waitForExistenceWithTimeout:30.0]);

XCUIElement* playbackSpeed1x = app.staticTexts[@"Playback speed\n1.0x"];
XCTAssertTrue([playbackSpeed1x waitForExistenceWithTimeout:30.0]);
[playbackSpeed1x tap];

XCUIElement* playbackSpeed5xButton = app.buttons[@"5.0x"];
XCTAssertTrue([playbackSpeed5xButton waitForExistenceWithTimeout:30.0]);
[playbackSpeed5xButton tap];

XCUIElement* playbackSpeed5x = app.staticTexts[@"Playback speed\n5.0x"];
XCTAssertTrue([playbackSpeed5x waitForExistenceWithTimeout:30.0]);

// Cycle through tabs.
for (NSString* tabName in @[ @"Asset", @"List example" ]) {
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"label BEGINSWITH %@", tabName];
XCUIElement* unselectedTab = [app.staticTexts elementMatchingPredicate:predicate];
if (![unselectedTab waitForExistenceWithTimeout:30.0]) {
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
XCTFail(@"Failed due to not able to find unselected %@ tab", tabName);
}
XCTAssertTrue([unselectedTab waitForExistenceWithTimeout:30.0]);
XCTAssertFalse(unselectedTab.isSelected);
[unselectedTab tap];

XCUIElement* selectedTab = [app.otherElements
elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label BEGINSWITH %@", tabName]];
if (![selectedTab waitForExistenceWithTimeout:30.0]) {
os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription);
XCTFail(@"Failed due to not able to find selected %@ tab", tabName);
}
XCTAssertTrue([selectedTab waitForExistenceWithTimeout:30.0]);
XCTAssertTrue(selectedTab.isSelected);
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/video_player/video_player/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ class _ControlsOverlay extends StatelessWidget {
Icons.play_arrow,
color: Colors.white,
size: 100.0,
semanticLabel: 'Play',
),
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ - (void)updatePlayingState;

static void* timeRangeContext = &timeRangeContext;
static void* statusContext = &statusContext;
static void* presentationSizeContext = &presentationSizeContext;
static void* durationContext = &durationContext;
static void* playbackLikelyToKeepUpContext = &playbackLikelyToKeepUpContext;
static void* playbackBufferEmptyContext = &playbackBufferEmptyContext;
static void* playbackBufferFullContext = &playbackBufferFullContext;
Expand All @@ -71,6 +73,14 @@ - (void)addObservers:(AVPlayerItem*)item {
forKeyPath:@"status"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:statusContext];
[item addObserver:self
forKeyPath:@"presentationSize"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:presentationSizeContext];
[item addObserver:self
forKeyPath:@"duration"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:durationContext];
[item addObserver:self
forKeyPath:@"playbackLikelyToKeepUp"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
Expand Down Expand Up @@ -282,10 +292,19 @@ - (void)observeValueForKeyPath:(NSString*)path
break;
case AVPlayerItemStatusReadyToPlay:
[item addOutput:_videoOutput];
[self sendInitialized];
[self setupEventSinkIfReadyToPlay];
[self updatePlayingState];
break;
}
} else if (context == presentationSizeContext || context == durationContext) {
AVPlayerItem* item = (AVPlayerItem*)object;
if (item.status == AVPlayerItemStatusReadyToPlay) {
// Due to an apparent bug, when the player item is ready, it still may not have determined
// its presentation size or duration. When these properties are finally set, re-check if
// all required properties and instantiate the event sink if it is not already set up.
[self setupEventSinkIfReadyToPlay];
[self updatePlayingState];
}
} else if (context == playbackLikelyToKeepUpContext) {
if ([[_player currentItem] isPlaybackLikelyToKeepUp]) {
[self updatePlayingState];
Expand Down Expand Up @@ -316,7 +335,7 @@ - (void)updatePlayingState {
_displayLink.paused = !_isPlaying;
}

- (void)sendInitialized {
- (void)setupEventSinkIfReadyToPlay {
if (_eventSink && !_isInitialized) {
CGSize size = [self.player currentItem].presentationSize;
CGFloat width = size.width;
Expand Down Expand Up @@ -425,7 +444,7 @@ - (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments
// This line ensures the 'initialized' event is sent when the event
// 'AVPlayerItemStatusReadyToPlay' fires before _eventSink is set (this function
// onListenWithArguments is called)
[self sendInitialized];
[self setupEventSinkIfReadyToPlay];
return nil;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/video_player/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for displaying inline video with other Flutter
widgets on Android, iOS, and web.
repository: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.2.5
version: 2.2.6

environment:
sdk: ">=2.14.0 <3.0.0"
Expand Down