[video_player] Android: Rotate videos recorded in landscapeRight (#3820)
diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md
index bfefb99..8dca057 100644
--- a/packages/video_player/video_player/CHANGELOG.md
+++ b/packages/video_player/video_player/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 2.4.3
+* Fixes Android to correctly display videos recorded in landscapeRight (https://github.com/flutter/flutter/issues/60327).
* Fixes order-dependent unit tests.
## 2.4.2
diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart
index a6ec510..95bdc07 100644
--- a/packages/video_player/video_player/lib/video_player.dart
+++ b/packages/video_player/video_player/lib/video_player.dart
@@ -4,6 +4,7 @@
import 'dart:async';
import 'dart:io';
+import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -48,6 +49,7 @@
this.isBuffering = false,
this.volume = 1.0,
this.playbackSpeed = 1.0,
+ this.rotationCorrection = 0,
this.errorDescription,
});
@@ -111,6 +113,9 @@
/// The [size] of the currently loaded video.
final Size size;
+ /// Degrees to rotate the video (clockwise) so it is displayed correctly.
+ final int rotationCorrection;
+
/// Indicates whether or not the video has been loaded and is ready to play.
final bool isInitialized;
@@ -136,7 +141,7 @@
}
/// Returns a new instance that has the same values as this current instance,
- /// except for any overrides passed in as arguments to [copyWidth].
+ /// except for any overrides passed in as arguments to [copyWith].
VideoPlayerValue copyWith({
Duration? duration,
Size? size,
@@ -150,6 +155,7 @@
bool? isBuffering,
double? volume,
double? playbackSpeed,
+ int? rotationCorrection,
String? errorDescription = _defaultErrorDescription,
}) {
return VideoPlayerValue(
@@ -165,6 +171,7 @@
isBuffering: isBuffering ?? this.isBuffering,
volume: volume ?? this.volume,
playbackSpeed: playbackSpeed ?? this.playbackSpeed,
+ rotationCorrection: rotationCorrection ?? this.rotationCorrection,
errorDescription: errorDescription != _defaultErrorDescription
? errorDescription
: this.errorDescription,
@@ -368,6 +375,7 @@
value = value.copyWith(
duration: event.duration,
size: event.size,
+ rotationCorrection: event.rotationCorrection,
isInitialized: event.duration != null,
errorDescription: null,
);
@@ -761,10 +769,29 @@
Widget build(BuildContext context) {
return _textureId == VideoPlayerController.kUninitializedTextureId
? Container()
- : _videoPlayerPlatform.buildView(_textureId);
+ : _VideoPlayerWithRotation(
+ rotation: widget.controller.value.rotationCorrection,
+ child: _videoPlayerPlatform.buildView(_textureId),
+ );
}
}
+class _VideoPlayerWithRotation extends StatelessWidget {
+ const _VideoPlayerWithRotation(
+ {Key? key, required this.rotation, required this.child})
+ : super(key: key);
+ final int rotation;
+ final Widget child;
+
+ @override
+ Widget build(BuildContext context) => rotation == 0
+ ? child
+ : Transform.rotate(
+ angle: rotation * math.pi / 180,
+ child: child,
+ );
+}
+
/// Used to configure the [VideoProgressIndicator] widget's colors for how it
/// describes the video's status.
///
diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml
index 05cfcf1..8b2fc57 100644
--- a/packages/video_player/video_player/pubspec.yaml
+++ b/packages/video_player/video_player/pubspec.yaml
@@ -3,7 +3,7 @@
widgets on Android, iOS, and web.
repository: https://github.com/flutter/plugins/tree/main/packages/video_player/video_player
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
-version: 2.4.2
+version: 2.4.3
environment:
sdk: ">=2.14.0 <3.0.0"
@@ -23,9 +23,9 @@
flutter:
sdk: flutter
html: ^0.15.0
- video_player_android: ^2.2.17
+ video_player_android: ^2.3.5
video_player_avfoundation: ^2.2.17
- video_player_platform_interface: ^5.1.0
+ video_player_platform_interface: ^5.1.1
video_player_web: ^2.0.0
dev_dependencies:
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 83a4988..f4eda11 100644
--- a/packages/video_player/video_player/test/video_player_test.dart
+++ b/packages/video_player/video_player/test/video_player_test.dart
@@ -4,6 +4,7 @@
import 'dart:async';
import 'dart:io';
+import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -15,6 +16,8 @@
implements VideoPlayerController {
FakeController() : super(VideoPlayerValue(duration: Duration.zero));
+ FakeController.value(VideoPlayerValue value) : super(value);
+
@override
Future<void> dispose() async {
super.dispose();
@@ -149,6 +152,27 @@
findsOneWidget);
});
+ testWidgets('non-zero rotationCorrection value is used',
+ (WidgetTester tester) async {
+ final FakeController controller = FakeController.value(
+ VideoPlayerValue(duration: Duration.zero, rotationCorrection: 180));
+ controller.textureId = 1;
+ await tester.pumpWidget(VideoPlayer(controller));
+ final Transform actualRotationCorrection =
+ find.byType(Transform).evaluate().single.widget as Transform;
+ expect(
+ actualRotationCorrection.transform, equals(Matrix4.rotationZ(math.pi)));
+ });
+
+ testWidgets('no transform when rotationCorrection is zero',
+ (WidgetTester tester) async {
+ final FakeController controller = FakeController.value(
+ VideoPlayerValue(duration: Duration.zero, rotationCorrection: 0));
+ controller.textureId = 1;
+ await tester.pumpWidget(VideoPlayer(controller));
+ expect(find.byType(Transform), findsNothing);
+ });
+
group('ClosedCaption widget', () {
testWidgets('uses a default text style', (WidgetTester tester) async {
const String text = 'foo';