| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| import 'dart:ui'; |
| |
| import 'package:flutter/widgets.dart'; |
| import 'package:meta/meta.dart' show required, visibleForTesting; |
| |
| import 'method_channel_video_player.dart'; |
| |
| /// The interface that implementations of video_player must implement. |
| /// |
| /// Platform implementations should extend this class rather than implement it as `video_player` |
| /// does not consider newly added methods to be breaking changes. Extending this class |
| /// (using `extends`) ensures that the subclass will get the default implementation, while |
| /// platform implementations that `implements` this interface will be broken by newly added |
| /// [VideoPlayerPlatform] methods. |
| abstract class VideoPlayerPlatform { |
| /// Only mock implementations should set this to true. |
| /// |
| /// Mockito mocks are implementing this class with `implements` which is forbidden for anything |
| /// other than mocks (see class docs). This property provides a backdoor for mockito mocks to |
| /// skip the verification that the class isn't implemented with `implements`. |
| @visibleForTesting |
| bool get isMock => false; |
| |
| /// The default instance of [VideoPlayerPlatform] to use. |
| /// |
| /// Platform-specific plugins should override this with their own |
| /// platform-specific class that extends [VideoPlayerPlatform] when they |
| /// register themselves. |
| /// |
| /// Defaults to [MethodChannelVideoPlayer]. |
| static VideoPlayerPlatform _instance = MethodChannelVideoPlayer(); |
| |
| static VideoPlayerPlatform get instance => _instance; |
| |
| // TODO(amirh): Extract common platform interface logic. |
| // https://github.com/flutter/flutter/issues/43368 |
| static set instance(VideoPlayerPlatform instance) { |
| if (!instance.isMock) { |
| try { |
| instance._verifyProvidesDefaultImplementations(); |
| } on NoSuchMethodError catch (_) { |
| throw AssertionError( |
| 'Platform interfaces must not be implemented with `implements`'); |
| } |
| } |
| _instance = instance; |
| } |
| |
| /// Initializes the platform interface and disposes all existing players. |
| /// |
| /// This method is called when the plugin is first initialized |
| /// and on every full restart. |
| Future<void> init() { |
| throw UnimplementedError('init() has not been implemented.'); |
| } |
| |
| /// Clears one video. |
| Future<void> dispose(int textureId) { |
| throw UnimplementedError('dispose() has not been implemented.'); |
| } |
| |
| /// Creates an instance of a video player and returns its textureId. |
| Future<int> create(DataSource dataSource) { |
| throw UnimplementedError('create() has not been implemented.'); |
| } |
| |
| /// Returns a Stream of [VideoEventType]s. |
| Stream<VideoEvent> videoEventsFor(int textureId) { |
| throw UnimplementedError('videoEventsFor() has not been implemented.'); |
| } |
| |
| /// Sets the looping attribute of the video. |
| Future<void> setLooping(int textureId, bool looping) { |
| throw UnimplementedError('setLooping() has not been implemented.'); |
| } |
| |
| /// Starts the video playback. |
| Future<void> play(int textureId) { |
| throw UnimplementedError('play() has not been implemented.'); |
| } |
| |
| /// Stops the video playback. |
| Future<void> pause(int textureId) { |
| throw UnimplementedError('pause() has not been implemented.'); |
| } |
| |
| /// Sets the volume to a range between 0.0 and 1.0. |
| Future<void> setVolume(int textureId, double volume) { |
| throw UnimplementedError('setVolume() has not been implemented.'); |
| } |
| |
| /// Sets the video position to a [Duration] from the start. |
| Future<void> seekTo(int textureId, Duration position) { |
| throw UnimplementedError('seekTo() has not been implemented.'); |
| } |
| |
| /// Gets the video position as [Duration] from the start. |
| Future<Duration> getPosition(int textureId) { |
| throw UnimplementedError('getPosition() has not been implemented.'); |
| } |
| |
| /// Returns a widget displaying the video with a given textureID. |
| Widget buildView(int textureId) { |
| throw UnimplementedError('buildView() has not been implemented.'); |
| } |
| |
| // This method makes sure that VideoPlayer isn't implemented with `implements`. |
| // |
| // See class doc for more details on why implementing this class is forbidden. |
| // |
| // This private method is called by the instance setter, which fails if the class is |
| // implemented with `implements`. |
| void _verifyProvidesDefaultImplementations() {} |
| } |
| |
| class DataSource { |
| DataSource({ |
| @required this.sourceType, |
| this.uri, |
| this.formatHint, |
| this.asset, |
| this.package, |
| }); |
| |
| final DataSourceType sourceType; |
| final String uri; |
| final VideoFormat formatHint; |
| final String asset; |
| final String package; |
| } |
| |
| enum DataSourceType { |
| asset, |
| network, |
| file, |
| } |
| |
| enum VideoFormat { |
| dash, |
| hls, |
| ss, |
| other, |
| } |
| |
| class VideoEvent { |
| VideoEvent({ |
| @required this.eventType, |
| this.duration, |
| this.size, |
| this.buffered, |
| }); |
| |
| final VideoEventType eventType; |
| final Duration duration; |
| final Size size; |
| final List<DurationRange> buffered; |
| } |
| |
| enum VideoEventType { |
| initialized, |
| completed, |
| bufferingUpdate, |
| bufferingStart, |
| bufferingEnd, |
| unknown, |
| } |
| |
| 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)'; |
| } |