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

Commit d3ccc34

Browse files
authored
[multiple] Improve video playback in image_picker example (#2819)
This change adds small bugfixes to the following packages: * video_player_web: * Prevent parsing Blob URLs so Safari can play from a PickedFile. * Allow users to 'mute' videos by setting their volume to 0.0 (this enables auto-play in most modern browsers) * video_player: * Fix an issue where aspect ratio calculations failed when some of the video sizes were zero (happened in web for incorrect videos) * image_picker (example app): * Start videos in web muted so they can auto-play * Dispose video controllers when they're really not needed. This fixes a fatal crash in Safari (not so fatal in other browsers).
1 parent 40db092 commit d3ccc34

10 files changed

Lines changed: 89 additions & 13 deletions

File tree

packages/image_picker/image_picker/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.6.7+3
2+
3+
* Fixes to the example app:
4+
* Make videos in web start muted. This allows auto-play across browsers.
5+
* Prevent the app from disposing of video controllers too early.
6+
17
## 0.6.7+2
28

39
* iOS: Fixes unpresentable album/image picker if window's root view controller is already presenting other view controller.

packages/image_picker/image_picker/example/lib/main.dart

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class _MyHomePageState extends State<MyHomePage> {
4242
dynamic _pickImageError;
4343
bool isVideo = false;
4444
VideoPlayerController _controller;
45+
VideoPlayerController _toBeDisposed;
4546
String _retrieveDataError;
4647

4748
final ImagePicker _picker = ImagePicker();
@@ -54,10 +55,16 @@ class _MyHomePageState extends State<MyHomePage> {
5455
await _disposeVideoController();
5556
if (kIsWeb) {
5657
_controller = VideoPlayerController.network(file.path);
58+
// In web, most browsers won't honor a programmatic call to .play
59+
// if the video has a sound track (and is not muted).
60+
// Mute the video so it auto-plays in web!
61+
// This is not needed if the call to .play is the result of user
62+
// interaction (clicking on a "play" button, for example).
63+
await _controller.setVolume(0.0);
5764
} else {
5865
_controller = VideoPlayerController.file(File(file.path));
66+
await _controller.setVolume(1.0);
5967
}
60-
await _controller.setVolume(1.0);
6168
await _controller.initialize();
6269
await _controller.setLooping(true);
6370
await _controller.play();
@@ -114,10 +121,11 @@ class _MyHomePageState extends State<MyHomePage> {
114121
}
115122

116123
Future<void> _disposeVideoController() async {
117-
if (_controller != null) {
118-
await _controller.dispose();
119-
_controller = null;
124+
if (_toBeDisposed != null) {
125+
await _toBeDisposed.dispose();
120126
}
127+
_toBeDisposed = _controller;
128+
_controller = null;
121129
}
122130

123131
Widget _previewVideo() {

packages/image_picker/image_picker/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: image_picker
22
description: Flutter plugin for selecting images from the Android and iOS image
33
library, and taking new pictures with the camera.
44
homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
5-
version: 0.6.7+2
5+
version: 0.6.7+3
66

77
flutter:
88
plugin:

packages/video_player/video_player/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.10.11+2
2+
3+
* Fix aspectRatio calculation when size.width or size.height are zero.
4+
15
## 0.10.11+1
26

37
* Post-v2 Android embedding cleanups.

packages/video_player/video_player/lib/video_player.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class VideoPlayerValue {
9797
/// Returns [size.width] / [size.height] when size is non-null, or `1.0.` when
9898
/// size is null or the aspect ratio would be less than or equal to 0.0.
9999
double get aspectRatio {
100-
if (size == null) {
100+
if (size == null || size.width == 0 || size.height == 0) {
101101
return 1.0;
102102
}
103103
final double aspectRatio = size.width / size.height;

packages/video_player/video_player/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter
44
# 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump
55
# the version to 2.0.0.
66
# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
7-
version: 0.10.11+1
7+
version: 0.10.11+2
88
homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player
99

1010
flutter:

packages/video_player/video_player/test/video_player_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,48 @@ void main() {
517517

518518
expect(exactCopy.toString(), original.toString());
519519
});
520+
521+
group('aspectRatio', () {
522+
test('640x480 -> 4:3', () {
523+
final value = VideoPlayerValue(
524+
size: Size(640, 480),
525+
duration: Duration(seconds: 1),
526+
);
527+
expect(value.aspectRatio, 4 / 3);
528+
});
529+
530+
test('null size -> 1.0', () {
531+
final value = VideoPlayerValue(
532+
size: null,
533+
duration: Duration(seconds: 1),
534+
);
535+
expect(value.aspectRatio, 1.0);
536+
});
537+
538+
test('height = 0 -> 1.0', () {
539+
final value = VideoPlayerValue(
540+
size: Size(640, 0),
541+
duration: Duration(seconds: 1),
542+
);
543+
expect(value.aspectRatio, 1.0);
544+
});
545+
546+
test('width = 0 -> 1.0', () {
547+
final value = VideoPlayerValue(
548+
size: Size(0, 480),
549+
duration: Duration(seconds: 1),
550+
);
551+
expect(value.aspectRatio, 1.0);
552+
});
553+
554+
test('negative aspect ratio -> 1.0', () {
555+
final value = VideoPlayerValue(
556+
size: Size(640, -480),
557+
duration: Duration(seconds: 1),
558+
);
559+
expect(value.aspectRatio, 1.0);
560+
});
561+
});
520562
});
521563

522564
test('VideoProgressColors', () {

packages/video_player/video_player_web/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.1.3+2
2+
3+
* Allow users to set the 'muted' attribute on video elements by setting their volume to 0.
4+
* Do not parse URIs on 'network' videos to not break blobs (Safari).
5+
16
## 0.1.3+1
27

38
* Remove Android folder from `video_player_web`.

packages/video_player/video_player_web/lib/video_player_web.dart

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ class VideoPlayerPlugin extends VideoPlayerPlatform {
6666
final int textureId = _textureCounter;
6767
_textureCounter++;
6868

69-
Uri uri;
69+
String uri;
7070
switch (dataSource.sourceType) {
7171
case DataSourceType.network:
72-
uri = Uri.parse(dataSource.uri);
72+
// Do NOT modify the incoming uri, it can be a Blob, and Safari doesn't
73+
// like blobs that have changed.
74+
uri = dataSource.uri;
7375
break;
7476
case DataSourceType.asset:
7577
String assetUrl = dataSource.asset;
@@ -79,7 +81,7 @@ class VideoPlayerPlugin extends VideoPlayerPlatform {
7981
// 'webOnlyAssetManager' is only in the web version of dart:ui
8082
// ignore: undefined_prefixed_name
8183
assetUrl = ui.webOnlyAssetManager.getAssetUrl(assetUrl);
82-
uri = Uri.parse(assetUrl);
84+
uri = assetUrl;
8385
break;
8486
case DataSourceType.file:
8587
return Future.error(UnimplementedError(
@@ -145,18 +147,21 @@ class _VideoPlayer {
145147
final StreamController<VideoEvent> eventController =
146148
StreamController<VideoEvent>();
147149

148-
final Uri uri;
150+
final String uri;
149151
final int textureId;
150152
VideoElement videoElement;
151153
bool isInitialized = false;
152154

153155
void initialize() {
154156
videoElement = VideoElement()
155-
..src = uri.toString()
157+
..src = uri
156158
..autoplay = false
157159
..controls = false
158160
..style.border = 'none';
159161

162+
// Allows Safari iOS to play the video inline
163+
videoElement.setAttribute('playsinline', 'true');
164+
160165
// TODO(hterkelsen): Use initialization parameters once they are available
161166
// ignore: undefined_prefixed_name
162167
ui.platformViewRegistry.registerViewFactory(
@@ -218,6 +223,12 @@ class _VideoPlayer {
218223
}
219224

220225
void setVolume(double value) {
226+
// TODO: Do we need to expose a "muted" API? https://github.com/flutter/flutter/issues/60721
227+
if (value > 0.0) {
228+
videoElement.muted = false;
229+
} else {
230+
videoElement.muted = true;
231+
}
221232
videoElement.volume = value;
222233
}
223234

packages/video_player/video_player_web/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/v
44
# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump
55
# the version to 2.0.0.
66
# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
7-
version: 0.1.3+1
7+
version: 0.1.3+2
88

99
flutter:
1010
plugin:

0 commit comments

Comments
 (0)