diff --git a/packages/video_player/android/src/main/java/io/flutter/videoplayer/VideoPlayerPlugin.java b/packages/video_player/android/src/main/java/io/flutter/videoplayer/VideoPlayerPlugin.java index 8ded2975dcc6..338c04246bf3 100644 --- a/packages/video_player/android/src/main/java/io/flutter/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/android/src/main/java/io/flutter/videoplayer/VideoPlayerPlugin.java @@ -152,6 +152,8 @@ private void sendInitialized() { Map event = new HashMap<>(); event.put("event", "initialized"); event.put("duration", mediaPlayer.getDuration()); + event.put("width", mediaPlayer.getVideoWidth()); + event.put("height", mediaPlayer.getVideoHeight()); eventSink.success(event); } } diff --git a/packages/video_player/example/lib/main.dart b/packages/video_player/example/lib/main.dart index 44b667901b8e..7fb1109a9391 100644 --- a/packages/video_player/example/lib/main.dart +++ b/packages/video_player/example/lib/main.dart @@ -255,12 +255,7 @@ class VideoInListOfCards extends StatelessWidget { alignment: FractionalOffset.bottomRight + const FractionalOffset(-0.1, -0.1), children: [ - new Center( - child: new AspectRatio( - aspectRatio: 3 / 2, - child: new VideoPlayPause(controller), - ), - ), + new AspectRatioVideo(controller), new Image.asset('assets/flutter-mark-square-64.png'), ]), ], @@ -276,19 +271,49 @@ class VideoInListOfCards extends StatelessWidget { } } -class FullScreenVideo extends StatelessWidget { +class AspectRatioVideo extends StatefulWidget { final VideoPlayerController controller; - FullScreenVideo(this.controller); + AspectRatioVideo(this.controller); + + @override + AspectRatioVideoState createState() => new AspectRatioVideoState(); +} + +class AspectRatioVideoState extends State { + VideoPlayerController get controller => widget.controller; + bool initialized = false; + + VoidCallback listener; + + @override + void initState() { + super.initState(); + listener = () { + if (!mounted) { + return; + } + if (initialized != controller.value.initialized) { + initialized = controller.value.initialized; + setState(() {}); + } + }; + controller.addListener(listener); + } @override Widget build(BuildContext context) { - return new Center( - child: new AspectRatio( - aspectRatio: 3 / 2, - child: new VideoPlayPause(controller), - ), - ); + if (initialized) { + final Size size = controller.value.size; + return new Center( + child: new AspectRatio( + aspectRatio: size.width / size.height, + child: new VideoPlayPause(controller), + ), + ); + } else { + return new Container(); + } } } @@ -313,7 +338,7 @@ void main() { new PlayerLifeCycle( 'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_20mb.mp4', (BuildContext context, VideoPlayerController controller) => - new FullScreenVideo(controller), + new AspectRatioVideo(controller), ), new PlayerLifeCycle( 'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_20mb.mp4', diff --git a/packages/video_player/ios/Classes/VideoPlayerPlugin.m b/packages/video_player/ios/Classes/VideoPlayerPlugin.m index c4aa3bc20f60..1754c796efab 100644 --- a/packages/video_player/ios/Classes/VideoPlayerPlugin.m +++ b/packages/video_player/ios/Classes/VideoPlayerPlugin.m @@ -173,7 +173,13 @@ - (void)updatePlayingState { - (void)sendInitialized { if (_eventSink && _isInitialized) { - _eventSink(@{ @"event" : @"initialized", @"duration" : @([self duration]) }); + CGSize size = [self.player currentItem].presentationSize; + _eventSink(@{ + @"event" : @"initialized", + @"duration" : @([self duration]), + @"width" : @(size.width), + @"height" : @(size.height), + }); } } diff --git a/packages/video_player/lib/video_player.dart b/packages/video_player/lib/video_player.dart index 822edf6942a3..fc7331ee4c69 100644 --- a/packages/video_player/lib/video_player.dart +++ b/packages/video_player/lib/video_player.dart @@ -39,9 +39,11 @@ class VideoPlayerValue { final bool isLooping; final double volume; final String errorDescription; + final Size size; VideoPlayerValue({ @required this.duration, + this.size, this.position: const Duration(), this.buffered: const [], this.isPlaying: false, @@ -57,9 +59,11 @@ class VideoPlayerValue { bool get initialized => duration != null; bool get isErroneous => errorDescription != null; + double get aspectRatio => size.width / size.height; VideoPlayerValue copyWith({ Duration duration, + Size size, Duration position, List buffered, bool isPlaying, @@ -69,6 +73,7 @@ class VideoPlayerValue { }) { return new VideoPlayerValue( duration: duration ?? this.duration, + size: size ?? this.size, position: position ?? this.position, buffered: buffered ?? this.buffered, isPlaying: isPlaying ?? this.isPlaying, @@ -82,6 +87,7 @@ class VideoPlayerValue { String toString() { return '$runtimeType(' 'duration: $duration, ' + 'size: $size, ' 'position: $position, ' 'buffered: [${buffered.join(', ')}], ' 'isplaying: $isPlaying, ' @@ -134,6 +140,7 @@ class VideoPlayerController extends ValueNotifier { if (event["event"] == "initialized") { value = value.copyWith( duration: new Duration(milliseconds: event["duration"]), + size: new Size(event["width"].toDouble(), event["height"].toDouble()), ); _applyLooping(); _applyVolume(); @@ -168,6 +175,7 @@ class VideoPlayerController extends ValueNotifier { if (_creatingCompleter != null) { await _creatingCompleter.future; if (!isDisposed) { + isDisposed = true; timer?.cancel(); await _eventSubscription?.cancel(); await _channel.invokeMethod( @@ -218,7 +226,13 @@ class VideoPlayerController extends ValueNotifier { timer = new Timer.periodic( const Duration(milliseconds: 500), (Timer timer) async { + if (isDisposed) { + return; + } final Duration newPosition = await position; + if (isDisposed) { + return; + } value = value.copyWith(position: newPosition); }, );