Skip to content

Commit 3d57cff

Browse files
cbenhagenHarry Terkelsen
authored andcommitted
[video_player] Use platform interface (flutter#2276)
* [video_player] Use platform interface * Move tests (leftover from part1) * Merge master * Export DurationRange and DataSourceType * Export VideoFormat * ignore: unused_element * Format * Update video_player_platform_interface dependency
1 parent 7af9a1a commit 3d57cff

File tree

7 files changed

+113
-174
lines changed

7 files changed

+113
-174
lines changed

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.4
2+
3+
* Port plugin code to use the federated Platform Interface, instead of a MethodChannel directly.
4+
15
## 0.10.3+3
26

37
* Add DartDocs and unit tests.

packages/video_player/video_player/lib/video_player.dart

Lines changed: 56 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -5,77 +5,19 @@
55
import 'dart:async';
66
import 'dart:io';
77

8+
import 'package:flutter/foundation.dart';
89
import 'package:flutter/services.dart';
910
import 'package:flutter/material.dart';
1011
import 'package:meta/meta.dart';
1112

12-
final MethodChannel _channel = const MethodChannel('flutter.io/videoPlayer')
13-
// This will clear all open videos on the platform when a full restart is
14-
// performed.
15-
..invokeMethod<void>('init');
13+
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
14+
export 'package:video_player_platform_interface/video_player_platform_interface.dart'
15+
show DurationRange, DataSourceType, VideoFormat;
1616

17-
/// Describes a discrete segment of time within a video using a [start] and
18-
/// [end] [Duration].
19-
class DurationRange {
20-
/// Trusts that the given [start] and [end] are actually in order. They should
21-
/// both be non-null.
22-
DurationRange(this.start, this.end);
23-
24-
/// The beginning of the segment described relative to the beginning of the
25-
/// entire video. Should be shorter than or equal to [end].
26-
///
27-
/// For example, if the entire video is 4 minutes long and the range is from
28-
/// 1:00-2:00, this should be a `Duration` of one minute.
29-
final Duration start;
30-
31-
/// The end of the segment described as a duration relative to the beginning of
32-
/// the entire video. This is expected to be non-null and longer than or equal
33-
/// to [start].
34-
///
35-
/// For example, if the entire video is 4 minutes long and the range is from
36-
/// 1:00-2:00, this should be a `Duration` of two minutes.
37-
final Duration end;
38-
39-
/// Assumes that [duration] is the total length of the video that this
40-
/// DurationRange is a segment form. It returns the percentage that [start] is
41-
/// through the entire video.
42-
///
43-
/// For example, assume that the entire video is 4 minutes long. If [start] has
44-
/// a duration of one minute, this will return `0.25` since the DurationRange
45-
/// starts 25% of the way through the video's total length.
46-
double startFraction(Duration duration) {
47-
return start.inMilliseconds / duration.inMilliseconds;
48-
}
49-
50-
/// Assumes that [duration] is the total length of the video that this
51-
/// DurationRange is a segment form. It returns the percentage that [start] is
52-
/// through the entire video.
53-
///
54-
/// For example, assume that the entire video is 4 minutes long. If [end] has a
55-
/// duration of two minutes, this will return `0.5` since the DurationRange
56-
/// ends 50% of the way through the video's total length.
57-
double endFraction(Duration duration) {
58-
return end.inMilliseconds / duration.inMilliseconds;
59-
}
60-
61-
@override
62-
String toString() => '$runtimeType(start: $start, end: $end)';
63-
}
64-
65-
/// The file format of the given video.
66-
enum VideoFormat {
67-
/// Dynamic Adaptive Streaming over HTTP, also known as MPEG-DASH.
68-
dash,
69-
70-
/// HTTP Live Streaming.
71-
hls,
72-
73-
/// Smooth Streaming.
74-
ss,
75-
76-
/// Any format other than the other ones defined in this enum.
77-
other
78-
}
17+
// This will clear all open videos on the platform when a full restart is
18+
// performed.
19+
// ignore: unused_element
20+
final VideoPlayerPlatform _ = VideoPlayerPlatform.instance..init();
7921

8022
/// The duration, current position, buffering state, error state and settings
8123
/// of a [VideoPlayerController].
@@ -187,20 +129,6 @@ class VideoPlayerValue {
187129
}
188130
}
189131

190-
/// The way in which the video was originally loaded. This has nothing to do
191-
/// with the video's file type. It's just the place from which the video is
192-
/// fetched from.
193-
enum DataSourceType {
194-
/// The video was included in the app's asset files.
195-
asset,
196-
197-
/// The video was downloaded from the internet.
198-
network,
199-
200-
/// The video was loaded off of the local filesystem.
201-
file
202-
}
203-
204132
/// Controls a platform video player, and provides updates when the state is
205133
/// changing.
206134
///
@@ -277,75 +205,66 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
277205
_lifeCycleObserver = _VideoAppLifeCycleObserver(this);
278206
_lifeCycleObserver.initialize();
279207
_creatingCompleter = Completer<void>();
280-
Map<dynamic, dynamic> dataSourceDescription;
208+
209+
DataSource dataSourceDescription;
281210
switch (dataSourceType) {
282211
case DataSourceType.asset:
283-
dataSourceDescription = <String, dynamic>{
284-
'asset': dataSource,
285-
'package': package
286-
};
212+
dataSourceDescription = DataSource(
213+
sourceType: DataSourceType.asset,
214+
asset: dataSource,
215+
package: package,
216+
);
287217
break;
288218
case DataSourceType.network:
289-
dataSourceDescription = <String, dynamic>{
290-
'uri': dataSource,
291-
'formatHint': _videoFormatStringMap[formatHint]
292-
};
219+
dataSourceDescription = DataSource(
220+
sourceType: DataSourceType.network,
221+
uri: dataSource,
222+
formatHint: formatHint,
223+
);
293224
break;
294225
case DataSourceType.file:
295-
dataSourceDescription = <String, dynamic>{'uri': dataSource};
226+
dataSourceDescription = DataSource(
227+
sourceType: DataSourceType.file,
228+
uri: dataSource,
229+
);
296230
break;
297231
}
298-
final Map<String, dynamic> response =
299-
await _channel.invokeMapMethod<String, dynamic>(
300-
'create',
301-
dataSourceDescription,
302-
);
303-
_textureId = response['textureId'];
232+
_textureId =
233+
await VideoPlayerPlatform.instance.create(dataSourceDescription);
304234
_creatingCompleter.complete(null);
305235
final Completer<void> initializingCompleter = Completer<void>();
306236

307-
DurationRange toDurationRange(dynamic value) {
308-
final List<dynamic> pair = value;
309-
return DurationRange(
310-
Duration(milliseconds: pair[0]),
311-
Duration(milliseconds: pair[1]),
312-
);
313-
}
314-
315-
void eventListener(dynamic event) {
237+
void eventListener(VideoEvent event) {
316238
if (_isDisposed) {
317239
return;
318240
}
319241

320-
final Map<dynamic, dynamic> map = event;
321-
switch (map['event']) {
322-
case 'initialized':
242+
switch (event.eventType) {
243+
case VideoEventType.initialized:
323244
value = value.copyWith(
324-
duration: Duration(milliseconds: map['duration']),
325-
size: Size(map['width']?.toDouble() ?? 0.0,
326-
map['height']?.toDouble() ?? 0.0),
245+
duration: event.duration,
246+
size: event.size,
327247
);
328248
initializingCompleter.complete(null);
329249
_applyLooping();
330250
_applyVolume();
331251
_applyPlayPause();
332252
break;
333-
case 'completed':
253+
case VideoEventType.completed:
334254
value = value.copyWith(isPlaying: false, position: value.duration);
335255
_timer?.cancel();
336256
break;
337-
case 'bufferingUpdate':
338-
final List<dynamic> values = map['values'];
339-
value = value.copyWith(
340-
buffered: values.map<DurationRange>(toDurationRange).toList(),
341-
);
257+
case VideoEventType.bufferingUpdate:
258+
value = value.copyWith(buffered: event.buffered);
342259
break;
343-
case 'bufferingStart':
260+
case VideoEventType.bufferingStart:
344261
value = value.copyWith(isBuffering: true);
345262
break;
346-
case 'bufferingEnd':
263+
case VideoEventType.bufferingEnd:
347264
value = value.copyWith(isBuffering: false);
348265
break;
266+
case VideoEventType.unknown:
267+
break;
349268
}
350269
}
351270

@@ -355,16 +274,12 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
355274
_timer?.cancel();
356275
}
357276

358-
_eventSubscription = _eventChannelFor(_textureId)
359-
.receiveBroadcastStream()
277+
_eventSubscription = VideoPlayerPlatform.instance
278+
.videoEventsFor(_textureId)
360279
.listen(eventListener, onError: errorListener);
361280
return initializingCompleter.future;
362281
}
363282

364-
EventChannel _eventChannelFor(int textureId) {
365-
return EventChannel('flutter.io/videoPlayer/videoEvents$textureId');
366-
}
367-
368283
@override
369284
Future<void> dispose() async {
370285
if (_creatingCompleter != null) {
@@ -373,10 +288,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
373288
_isDisposed = true;
374289
_timer?.cancel();
375290
await _eventSubscription?.cancel();
376-
await _channel.invokeMethod<void>(
377-
'dispose',
378-
<String, dynamic>{'textureId': _textureId},
379-
);
291+
await VideoPlayerPlatform.instance.dispose(_textureId);
380292
}
381293
_lifeCycleObserver.dispose();
382294
}
@@ -411,21 +323,15 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
411323
if (!value.initialized || _isDisposed) {
412324
return;
413325
}
414-
_channel.invokeMethod<void>(
415-
'setLooping',
416-
<String, dynamic>{'textureId': _textureId, 'looping': value.isLooping},
417-
);
326+
VideoPlayerPlatform.instance.setLooping(_textureId, value.isLooping);
418327
}
419328

420329
Future<void> _applyPlayPause() async {
421330
if (!value.initialized || _isDisposed) {
422331
return;
423332
}
424333
if (value.isPlaying) {
425-
await _channel.invokeMethod<void>(
426-
'play',
427-
<String, dynamic>{'textureId': _textureId},
428-
);
334+
VideoPlayerPlatform.instance.play(_textureId);
429335
_timer = Timer.periodic(
430336
const Duration(milliseconds: 500),
431337
(Timer timer) async {
@@ -441,55 +347,41 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
441347
);
442348
} else {
443349
_timer?.cancel();
444-
await _channel.invokeMethod<void>(
445-
'pause',
446-
<String, dynamic>{'textureId': _textureId},
447-
);
350+
VideoPlayerPlatform.instance.pause(_textureId);
448351
}
449352
}
450353

451354
Future<void> _applyVolume() async {
452355
if (!value.initialized || _isDisposed) {
453356
return;
454357
}
455-
await _channel.invokeMethod<void>(
456-
'setVolume',
457-
<String, dynamic>{'textureId': _textureId, 'volume': value.volume},
458-
);
358+
VideoPlayerPlatform.instance.setVolume(_textureId, value.volume);
459359
}
460360

461361
/// The position in the current video.
462362
Future<Duration> get position async {
463363
if (_isDisposed) {
464364
return null;
465365
}
466-
return Duration(
467-
milliseconds: await _channel.invokeMethod<int>(
468-
'position',
469-
<String, dynamic>{'textureId': _textureId},
470-
),
471-
);
366+
return await VideoPlayerPlatform.instance.getPosition(_textureId);
472367
}
473368

474369
/// Sets the video's current timestamp to be at [moment]. The next
475370
/// time the video is played it will resume from the given [moment].
476371
///
477372
/// If [moment] is outside of the video's full range it will be automatically
478373
/// and silently clamped.
479-
Future<void> seekTo(Duration moment) async {
374+
Future<void> seekTo(Duration position) async {
480375
if (_isDisposed) {
481376
return;
482377
}
483-
if (moment > value.duration) {
484-
moment = value.duration;
485-
} else if (moment < const Duration()) {
486-
moment = const Duration();
378+
if (position > value.duration) {
379+
position = value.duration;
380+
} else if (position < const Duration()) {
381+
position = const Duration();
487382
}
488-
await _channel.invokeMethod<void>('seekTo', <String, dynamic>{
489-
'textureId': _textureId,
490-
'location': moment.inMilliseconds,
491-
});
492-
value = value.copyWith(position: moment);
383+
VideoPlayerPlatform.instance.seekTo(_textureId, position);
384+
value = value.copyWith(position: position);
493385
}
494386

495387
/// Sets the audio volume of [this].
@@ -500,14 +392,6 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
500392
value = value.copyWith(volume: volume.clamp(0.0, 1.0));
501393
await _applyVolume();
502394
}
503-
504-
static const Map<VideoFormat, String> _videoFormatStringMap =
505-
<VideoFormat, String>{
506-
VideoFormat.ss: 'ss',
507-
VideoFormat.hls: 'hls',
508-
VideoFormat.dash: 'dash',
509-
VideoFormat.other: 'other',
510-
};
511395
}
512396

513397
class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver {
@@ -594,7 +478,9 @@ class _VideoPlayerState extends State<VideoPlayer> {
594478

595479
@override
596480
Widget build(BuildContext context) {
597-
return _textureId == null ? Container() : Texture(textureId: _textureId);
481+
return _textureId == null
482+
? Container()
483+
: VideoPlayerPlatform.instance.buildView(_textureId);
598484
}
599485
}
600486

packages/video_player/video_player/pubspec.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ name: video_player
22
description: Flutter plugin for displaying inline video with other Flutter
33
widgets on Android and iOS.
44
author: Flutter Team <flutter-dev@googlegroups.com>
5-
version: 0.10.3+3
6-
homepage: https://github.com/flutter/plugins/tree/master/packages/video_player
5+
version: 0.10.4
6+
homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player
77

88
flutter:
99
plugin:
@@ -13,6 +13,8 @@ flutter:
1313

1414
dependencies:
1515
meta: "^1.0.5"
16+
video_player_platform_interface: ^1.0.1
17+
1618
flutter:
1719
sdk: flutter
1820

packages/video_player/video_player/test/video_player_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:flutter/services.dart';
99
import 'package:flutter/widgets.dart';
1010
import 'package:video_player/video_player.dart';
1111
import 'package:flutter_test/flutter_test.dart';
12+
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
1213

1314
class FakeController extends ValueNotifier<VideoPlayerValue>
1415
implements VideoPlayerController {

0 commit comments

Comments
 (0)