5
5
import 'dart:async' ;
6
6
import 'dart:io' ;
7
7
8
+ import 'package:flutter/foundation.dart' ;
8
9
import 'package:flutter/services.dart' ;
9
10
import 'package:flutter/material.dart' ;
10
11
import 'package:meta/meta.dart' ;
11
12
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;
16
16
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 ();
79
21
80
22
/// The duration, current position, buffering state, error state and settings
81
23
/// of a [VideoPlayerController] .
@@ -187,20 +129,6 @@ class VideoPlayerValue {
187
129
}
188
130
}
189
131
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
-
204
132
/// Controls a platform video player, and provides updates when the state is
205
133
/// changing.
206
134
///
@@ -277,75 +205,66 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
277
205
_lifeCycleObserver = _VideoAppLifeCycleObserver (this );
278
206
_lifeCycleObserver.initialize ();
279
207
_creatingCompleter = Completer <void >();
280
- Map <dynamic , dynamic > dataSourceDescription;
208
+
209
+ DataSource dataSourceDescription;
281
210
switch (dataSourceType) {
282
211
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
+ );
287
217
break ;
288
218
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
+ );
293
224
break ;
294
225
case DataSourceType .file:
295
- dataSourceDescription = < String , dynamic > {'uri' : dataSource};
226
+ dataSourceDescription = DataSource (
227
+ sourceType: DataSourceType .file,
228
+ uri: dataSource,
229
+ );
296
230
break ;
297
231
}
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);
304
234
_creatingCompleter.complete (null );
305
235
final Completer <void > initializingCompleter = Completer <void >();
306
236
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) {
316
238
if (_isDisposed) {
317
239
return ;
318
240
}
319
241
320
- final Map <dynamic , dynamic > map = event;
321
- switch (map['event' ]) {
322
- case 'initialized' :
242
+ switch (event.eventType) {
243
+ case VideoEventType .initialized:
323
244
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,
327
247
);
328
248
initializingCompleter.complete (null );
329
249
_applyLooping ();
330
250
_applyVolume ();
331
251
_applyPlayPause ();
332
252
break ;
333
- case ' completed' :
253
+ case VideoEventType . completed:
334
254
value = value.copyWith (isPlaying: false , position: value.duration);
335
255
_timer? .cancel ();
336
256
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);
342
259
break ;
343
- case ' bufferingStart' :
260
+ case VideoEventType . bufferingStart:
344
261
value = value.copyWith (isBuffering: true );
345
262
break ;
346
- case ' bufferingEnd' :
263
+ case VideoEventType . bufferingEnd:
347
264
value = value.copyWith (isBuffering: false );
348
265
break ;
266
+ case VideoEventType .unknown:
267
+ break ;
349
268
}
350
269
}
351
270
@@ -355,16 +274,12 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
355
274
_timer? .cancel ();
356
275
}
357
276
358
- _eventSubscription = _eventChannelFor (_textureId)
359
- .receiveBroadcastStream ( )
277
+ _eventSubscription = VideoPlayerPlatform .instance
278
+ .videoEventsFor (_textureId )
360
279
.listen (eventListener, onError: errorListener);
361
280
return initializingCompleter.future;
362
281
}
363
282
364
- EventChannel _eventChannelFor (int textureId) {
365
- return EventChannel ('flutter.io/videoPlayer/videoEvents$textureId ' );
366
- }
367
-
368
283
@override
369
284
Future <void > dispose () async {
370
285
if (_creatingCompleter != null ) {
@@ -373,10 +288,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
373
288
_isDisposed = true ;
374
289
_timer? .cancel ();
375
290
await _eventSubscription? .cancel ();
376
- await _channel.invokeMethod <void >(
377
- 'dispose' ,
378
- < String , dynamic > {'textureId' : _textureId},
379
- );
291
+ await VideoPlayerPlatform .instance.dispose (_textureId);
380
292
}
381
293
_lifeCycleObserver.dispose ();
382
294
}
@@ -411,21 +323,15 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
411
323
if (! value.initialized || _isDisposed) {
412
324
return ;
413
325
}
414
- _channel.invokeMethod <void >(
415
- 'setLooping' ,
416
- < String , dynamic > {'textureId' : _textureId, 'looping' : value.isLooping},
417
- );
326
+ VideoPlayerPlatform .instance.setLooping (_textureId, value.isLooping);
418
327
}
419
328
420
329
Future <void > _applyPlayPause () async {
421
330
if (! value.initialized || _isDisposed) {
422
331
return ;
423
332
}
424
333
if (value.isPlaying) {
425
- await _channel.invokeMethod <void >(
426
- 'play' ,
427
- < String , dynamic > {'textureId' : _textureId},
428
- );
334
+ VideoPlayerPlatform .instance.play (_textureId);
429
335
_timer = Timer .periodic (
430
336
const Duration (milliseconds: 500 ),
431
337
(Timer timer) async {
@@ -441,55 +347,41 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
441
347
);
442
348
} else {
443
349
_timer? .cancel ();
444
- await _channel.invokeMethod <void >(
445
- 'pause' ,
446
- < String , dynamic > {'textureId' : _textureId},
447
- );
350
+ VideoPlayerPlatform .instance.pause (_textureId);
448
351
}
449
352
}
450
353
451
354
Future <void > _applyVolume () async {
452
355
if (! value.initialized || _isDisposed) {
453
356
return ;
454
357
}
455
- await _channel.invokeMethod <void >(
456
- 'setVolume' ,
457
- < String , dynamic > {'textureId' : _textureId, 'volume' : value.volume},
458
- );
358
+ VideoPlayerPlatform .instance.setVolume (_textureId, value.volume);
459
359
}
460
360
461
361
/// The position in the current video.
462
362
Future <Duration > get position async {
463
363
if (_isDisposed) {
464
364
return null ;
465
365
}
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);
472
367
}
473
368
474
369
/// Sets the video's current timestamp to be at [moment] . The next
475
370
/// time the video is played it will resume from the given [moment] .
476
371
///
477
372
/// If [moment] is outside of the video's full range it will be automatically
478
373
/// and silently clamped.
479
- Future <void > seekTo (Duration moment ) async {
374
+ Future <void > seekTo (Duration position ) async {
480
375
if (_isDisposed) {
481
376
return ;
482
377
}
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 ();
487
382
}
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);
493
385
}
494
386
495
387
/// Sets the audio volume of [this] .
@@ -500,14 +392,6 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
500
392
value = value.copyWith (volume: volume.clamp (0.0 , 1.0 ));
501
393
await _applyVolume ();
502
394
}
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
- };
511
395
}
512
396
513
397
class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver {
@@ -594,7 +478,9 @@ class _VideoPlayerState extends State<VideoPlayer> {
594
478
595
479
@override
596
480
Widget build (BuildContext context) {
597
- return _textureId == null ? Container () : Texture (textureId: _textureId);
481
+ return _textureId == null
482
+ ? Container ()
483
+ : VideoPlayerPlatform .instance.buildView (_textureId);
598
484
}
599
485
}
600
486
0 commit comments