From 677bf29ede867442d7ef7b7b083dc48baaf49ea6 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Fri, 22 Nov 2019 00:54:12 +0100 Subject: [PATCH 1/8] [video_player] Use platform interface --- .../video_player/video_player/CHANGELOG.md | 4 + .../video_player/lib/video_player.dart | 170 ++++++------------ .../video_player/video_player/pubspec.yaml | 4 +- .../video_player/test/video_player_test.dart | 1 + 4 files changed, 63 insertions(+), 116 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 1bac34f6649b..349307eec84c 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.4 + +* Port plugin code to use the federated Platform Interface, instead of a MethodChannel directly. + ## 0.10.3+2 * Update the homepage to point to the new plugin location diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index f1b0e7c9791d..379a3b9bd178 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -5,34 +5,16 @@ import 'dart:async'; import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; -final MethodChannel _channel = const MethodChannel('flutter.io/videoPlayer') - // This will clear all open videos on the platform when a full restart is - // performed. - ..invokeMethod('init'); +import 'package:video_player_platform_interface/video_player_platform_interface.dart'; -class DurationRange { - DurationRange(this.start, this.end); - - final Duration start; - final Duration end; - - double startFraction(Duration duration) { - return start.inMilliseconds / duration.inMilliseconds; - } - - double endFraction(Duration duration) { - return end.inMilliseconds / duration.inMilliseconds; - } - - @override - String toString() => '$runtimeType(start: $start, end: $end)'; -} - -enum VideoFormat { dash, hls, ss, other } +// This will clear all open videos on the platform when a full restart is +// performed. +final VideoPlayerPlatform _ = VideoPlayerPlatform.instance..init(); /// The duration, current position, buffering state, error state and settings /// of a [VideoPlayerController]. @@ -88,7 +70,9 @@ class VideoPlayerValue { final Size size; bool get initialized => duration != null; + bool get hasError => errorDescription != null; + double get aspectRatio => size != null ? size.width / size.height : 1.0; VideoPlayerValue copyWith({ @@ -130,8 +114,6 @@ class VideoPlayerValue { } } -enum DataSourceType { asset, network, file } - /// Controls a platform video player, and provides updates when the state is /// changing. /// @@ -198,75 +180,66 @@ class VideoPlayerController extends ValueNotifier { _lifeCycleObserver = _VideoAppLifeCycleObserver(this); _lifeCycleObserver.initialize(); _creatingCompleter = Completer(); - Map dataSourceDescription; + + DataSource dataSourceDescription; switch (dataSourceType) { case DataSourceType.asset: - dataSourceDescription = { - 'asset': dataSource, - 'package': package - }; + dataSourceDescription = DataSource( + sourceType: DataSourceType.asset, + asset: dataSource, + package: package, + ); break; case DataSourceType.network: - dataSourceDescription = { - 'uri': dataSource, - 'formatHint': _videoFormatStringMap[formatHint] - }; + dataSourceDescription = DataSource( + sourceType: DataSourceType.network, + uri: dataSource, + formatHint: formatHint, + ); break; case DataSourceType.file: - dataSourceDescription = {'uri': dataSource}; + dataSourceDescription = DataSource( + sourceType: DataSourceType.file, + uri: dataSource, + ); break; } - final Map response = - await _channel.invokeMapMethod( - 'create', - dataSourceDescription, - ); - _textureId = response['textureId']; + _textureId = + await VideoPlayerPlatform.instance.create(dataSourceDescription); _creatingCompleter.complete(null); final Completer initializingCompleter = Completer(); - DurationRange toDurationRange(dynamic value) { - final List pair = value; - return DurationRange( - Duration(milliseconds: pair[0]), - Duration(milliseconds: pair[1]), - ); - } - - void eventListener(dynamic event) { + void eventListener(VideoEvent event) { if (_isDisposed) { return; } - final Map map = event; - switch (map['event']) { - case 'initialized': + switch (event.eventType) { + case VideoEventType.initialized: value = value.copyWith( - duration: Duration(milliseconds: map['duration']), - size: Size(map['width']?.toDouble() ?? 0.0, - map['height']?.toDouble() ?? 0.0), + duration: event.duration, + size: event.size, ); initializingCompleter.complete(null); _applyLooping(); _applyVolume(); _applyPlayPause(); break; - case 'completed': + case VideoEventType.completed: value = value.copyWith(isPlaying: false, position: value.duration); _timer?.cancel(); break; - case 'bufferingUpdate': - final List values = map['values']; - value = value.copyWith( - buffered: values.map(toDurationRange).toList(), - ); + case VideoEventType.bufferingUpdate: + value = value.copyWith(buffered: event.buffered); break; - case 'bufferingStart': + case VideoEventType.bufferingStart: value = value.copyWith(isBuffering: true); break; - case 'bufferingEnd': + case VideoEventType.bufferingEnd: value = value.copyWith(isBuffering: false); break; + case VideoEventType.unknown: + break; } } @@ -276,16 +249,12 @@ class VideoPlayerController extends ValueNotifier { _timer?.cancel(); } - _eventSubscription = _eventChannelFor(_textureId) - .receiveBroadcastStream() + _eventSubscription = VideoPlayerPlatform.instance + .videoEventsFor(_textureId) .listen(eventListener, onError: errorListener); return initializingCompleter.future; } - EventChannel _eventChannelFor(int textureId) { - return EventChannel('flutter.io/videoPlayer/videoEvents$textureId'); - } - @override Future dispose() async { if (_creatingCompleter != null) { @@ -294,10 +263,7 @@ class VideoPlayerController extends ValueNotifier { _isDisposed = true; _timer?.cancel(); await _eventSubscription?.cancel(); - await _channel.invokeMethod( - 'dispose', - {'textureId': _textureId}, - ); + await VideoPlayerPlatform.instance.dispose(_textureId); } _lifeCycleObserver.dispose(); } @@ -324,10 +290,7 @@ class VideoPlayerController extends ValueNotifier { if (!value.initialized || _isDisposed) { return; } - _channel.invokeMethod( - 'setLooping', - {'textureId': _textureId, 'looping': value.isLooping}, - ); + VideoPlayerPlatform.instance.setLooping(_textureId, value.isLooping); } Future _applyPlayPause() async { @@ -335,10 +298,7 @@ class VideoPlayerController extends ValueNotifier { return; } if (value.isPlaying) { - await _channel.invokeMethod( - 'play', - {'textureId': _textureId}, - ); + VideoPlayerPlatform.instance.play(_textureId); _timer = Timer.periodic( const Duration(milliseconds: 500), (Timer timer) async { @@ -354,10 +314,7 @@ class VideoPlayerController extends ValueNotifier { ); } else { _timer?.cancel(); - await _channel.invokeMethod( - 'pause', - {'textureId': _textureId}, - ); + VideoPlayerPlatform.instance.pause(_textureId); } } @@ -365,10 +322,7 @@ class VideoPlayerController extends ValueNotifier { if (!value.initialized || _isDisposed) { return; } - await _channel.invokeMethod( - 'setVolume', - {'textureId': _textureId, 'volume': value.volume}, - ); + VideoPlayerPlatform.instance.setVolume(_textureId, value.volume); } /// The position in the current video. @@ -376,28 +330,20 @@ class VideoPlayerController extends ValueNotifier { if (_isDisposed) { return null; } - return Duration( - milliseconds: await _channel.invokeMethod( - 'position', - {'textureId': _textureId}, - ), - ); + return await VideoPlayerPlatform.instance.getPosition(_textureId); } - Future seekTo(Duration moment) async { + Future seekTo(Duration position) async { if (_isDisposed) { return; } - if (moment > value.duration) { - moment = value.duration; - } else if (moment < const Duration()) { - moment = const Duration(); + if (position > value.duration) { + position = value.duration; + } else if (position < const Duration()) { + position = const Duration(); } - await _channel.invokeMethod('seekTo', { - 'textureId': _textureId, - 'location': moment.inMilliseconds, - }); - value = value.copyWith(position: moment); + VideoPlayerPlatform.instance.seekTo(_textureId, position); + value = value.copyWith(position: position); } /// Sets the audio volume of [this]. @@ -408,14 +354,6 @@ class VideoPlayerController extends ValueNotifier { value = value.copyWith(volume: volume.clamp(0.0, 1.0)); await _applyVolume(); } - - static const Map _videoFormatStringMap = - { - VideoFormat.ss: 'ss', - VideoFormat.hls: 'hls', - VideoFormat.dash: 'dash', - VideoFormat.other: 'other', - }; } class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver { @@ -499,7 +437,9 @@ class _VideoPlayerState extends State { @override Widget build(BuildContext context) { - return _textureId == null ? Container() : Texture(textureId: _textureId); + return _textureId == null + ? Container() + : VideoPlayerPlatform.instance.buildView(_textureId); } } diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 32d1e98e586c..396cb64f0fac 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android and iOS. author: Flutter Team -version: 0.10.3+2 +version: 0.10.4 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: @@ -13,6 +13,8 @@ flutter: dependencies: meta: "^1.0.5" + video_player_platform_interface: ^1.0.0 + flutter: sdk: flutter diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index 9211f0c3a87c..68b3fc368e2f 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:video_player/video_player.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:video_player_platform_interface/video_player_platform_interface.dart'; class FakeController extends ValueNotifier implements VideoPlayerController { From 1343e5cee81e74adfc466ac5534361b1ed1107a3 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Fri, 22 Nov 2019 01:10:44 +0100 Subject: [PATCH 2/8] Move tests (leftover from part1) --- .../{ => video_player}/example/test_driver/video_player.dart | 0 .../{ => video_player}/example/test_driver/video_player_test.dart | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/video_player/{ => video_player}/example/test_driver/video_player.dart (100%) rename packages/video_player/{ => video_player}/example/test_driver/video_player_test.dart (100%) diff --git a/packages/video_player/example/test_driver/video_player.dart b/packages/video_player/video_player/example/test_driver/video_player.dart similarity index 100% rename from packages/video_player/example/test_driver/video_player.dart rename to packages/video_player/video_player/example/test_driver/video_player.dart diff --git a/packages/video_player/example/test_driver/video_player_test.dart b/packages/video_player/video_player/example/test_driver/video_player_test.dart similarity index 100% rename from packages/video_player/example/test_driver/video_player_test.dart rename to packages/video_player/video_player/example/test_driver/video_player_test.dart From d538948923544ab7109175ea6e3c54312d3c19e8 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Sat, 23 Nov 2019 00:05:33 +0100 Subject: [PATCH 3/8] Merge master --- .../lib/video_player_platform_interface.dart | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index 6c4ecaf58509..a61d0b56fe9b 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -134,17 +134,33 @@ class DataSource { final String package; } +/// The way in which the video was originally loaded. This has nothing to do +/// with the video's file type. It's just the place from which the video is +/// fetched from. enum DataSourceType { + /// The video was included in the app's asset files. asset, + + /// The video was downloaded from the internet. network, - file, + + /// The video was loaded off of the local filesystem. + file } +/// The file format of the given video. enum VideoFormat { + /// Dynamic Adaptive Streaming over HTTP, also known as MPEG-DASH. dash, + + /// HTTP Live Streaming. hls, + + /// Smooth Streaming. ss, - other, + + /// Any format other than the other ones defined in this enum. + other } class VideoEvent { @@ -170,16 +186,46 @@ enum VideoEventType { unknown, } +/// Describes a discrete segment of time within a video using a [start] and +/// [end] [Duration]. class DurationRange { + /// Trusts that the given [start] and [end] are actually in order. They should + /// both be non-null. DurationRange(this.start, this.end); + /// The beginning of the segment described relative to the beginning of the + /// entire video. Should be shorter than or equal to [end]. + /// + /// For example, if the entire video is 4 minutes long and the range is from + /// 1:00-2:00, this should be a `Duration` of one minute. final Duration start; + + /// The end of the segment described as a duration relative to the beginning of + /// the entire video. This is expected to be non-null and longer than or equal + /// to [start]. + /// + /// For example, if the entire video is 4 minutes long and the range is from + /// 1:00-2:00, this should be a `Duration` of two minutes. final Duration end; + /// Assumes that [duration] is the total length of the video that this + /// DurationRange is a segment form. It returns the percentage that [start] is + /// through the entire video. + /// + /// For example, assume that the entire video is 4 minutes long. If [start] has + /// a duration of one minute, this will return `0.25` since the DurationRange + /// starts 25% of the way through the video's total length. double startFraction(Duration duration) { return start.inMilliseconds / duration.inMilliseconds; } + /// Assumes that [duration] is the total length of the video that this + /// DurationRange is a segment form. It returns the percentage that [start] is + /// through the entire video. + /// + /// For example, assume that the entire video is 4 minutes long. If [end] has a + /// duration of two minutes, this will return `0.5` since the DurationRange + /// ends 50% of the way through the video's total length. double endFraction(Duration duration) { return end.inMilliseconds / duration.inMilliseconds; } From 4479d7e5a4af35734a3861335af4983e8bd5e359 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Mon, 25 Nov 2019 15:45:18 +0100 Subject: [PATCH 4/8] Export DurationRange and DataSourceType --- packages/video_player/video_player/lib/video_player.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index 3ec5ab55a911..9145f5d0e1d3 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -11,6 +11,8 @@ import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; +export 'package:video_player_platform_interface/video_player_platform_interface.dart' + show DurationRange, DataSourceType; // This will clear all open videos on the platform when a full restart is // performed. From 440c7517df51bc78f88a1201d2956fabe47c3109 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Mon, 25 Nov 2019 20:14:46 +0100 Subject: [PATCH 5/8] Export VideoFormat --- packages/video_player/video_player/lib/video_player.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index 9145f5d0e1d3..d82ec69397ff 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -12,7 +12,7 @@ import 'package:meta/meta.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; export 'package:video_player_platform_interface/video_player_platform_interface.dart' - show DurationRange, DataSourceType; + show DurationRange, DataSourceType, VideoFormat; // This will clear all open videos on the platform when a full restart is // performed. From 8916af0d1c21184b7fcebea1f9296cb75d49b3c3 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Mon, 25 Nov 2019 20:50:00 +0100 Subject: [PATCH 6/8] ignore: unused_element --- packages/video_player/video_player/lib/video_player.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index d82ec69397ff..21690b8126c5 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -16,7 +16,7 @@ export 'package:video_player_platform_interface/video_player_platform_interface. // This will clear all open videos on the platform when a full restart is // performed. -final VideoPlayerPlatform _ = VideoPlayerPlatform.instance..init(); +final VideoPlayerPlatform _ = VideoPlayerPlatform.instance..init(); // ignore: unused_element /// The duration, current position, buffering state, error state and settings /// of a [VideoPlayerController]. From a2e13e6dc48f2fc70e97b720263263b4f236410d Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Mon, 25 Nov 2019 20:58:11 +0100 Subject: [PATCH 7/8] Format --- packages/video_player/video_player/lib/video_player.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index 21690b8126c5..3a4768fb256c 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -16,7 +16,8 @@ export 'package:video_player_platform_interface/video_player_platform_interface. // This will clear all open videos on the platform when a full restart is // performed. -final VideoPlayerPlatform _ = VideoPlayerPlatform.instance..init(); // ignore: unused_element +// ignore: unused_element +final VideoPlayerPlatform _ = VideoPlayerPlatform.instance..init(); /// The duration, current position, buffering state, error state and settings /// of a [VideoPlayerController]. From 8676d91dc4d21d9c1b7c4946407c421ef4858947 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Tue, 26 Nov 2019 00:07:49 +0100 Subject: [PATCH 8/8] Update video_player_platform_interface dependency --- packages/video_player/video_player/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 396cb64f0fac..e191377e5c99 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -13,7 +13,7 @@ flutter: dependencies: meta: "^1.0.5" - video_player_platform_interface: ^1.0.0 + video_player_platform_interface: ^1.0.1 flutter: sdk: flutter