Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit ee24766

Browse files
authored
[video_player] Android: Rotate videos recorded in landscapeRight (#3820)
1 parent 8ded25d commit ee24766

File tree

4 files changed

+58
-6
lines changed

4 files changed

+58
-6
lines changed

packages/video_player/video_player/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 2.4.3
22

3+
* Fixes Android to correctly display videos recorded in landscapeRight (https://github.com/flutter/flutter/issues/60327).
34
* Fixes order-dependent unit tests.
45

56
## 2.4.2

packages/video_player/video_player/lib/video_player.dart

+29-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66
import 'dart:io';
7+
import 'dart:math' as math;
78

89
import 'package:flutter/foundation.dart';
910
import 'package:flutter/material.dart';
@@ -48,6 +49,7 @@ class VideoPlayerValue {
4849
this.isBuffering = false,
4950
this.volume = 1.0,
5051
this.playbackSpeed = 1.0,
52+
this.rotationCorrection = 0,
5153
this.errorDescription,
5254
});
5355

@@ -111,6 +113,9 @@ class VideoPlayerValue {
111113
/// The [size] of the currently loaded video.
112114
final Size size;
113115

116+
/// Degrees to rotate the video (clockwise) so it is displayed correctly.
117+
final int rotationCorrection;
118+
114119
/// Indicates whether or not the video has been loaded and is ready to play.
115120
final bool isInitialized;
116121

@@ -136,7 +141,7 @@ class VideoPlayerValue {
136141
}
137142

138143
/// Returns a new instance that has the same values as this current instance,
139-
/// except for any overrides passed in as arguments to [copyWidth].
144+
/// except for any overrides passed in as arguments to [copyWith].
140145
VideoPlayerValue copyWith({
141146
Duration? duration,
142147
Size? size,
@@ -150,6 +155,7 @@ class VideoPlayerValue {
150155
bool? isBuffering,
151156
double? volume,
152157
double? playbackSpeed,
158+
int? rotationCorrection,
153159
String? errorDescription = _defaultErrorDescription,
154160
}) {
155161
return VideoPlayerValue(
@@ -165,6 +171,7 @@ class VideoPlayerValue {
165171
isBuffering: isBuffering ?? this.isBuffering,
166172
volume: volume ?? this.volume,
167173
playbackSpeed: playbackSpeed ?? this.playbackSpeed,
174+
rotationCorrection: rotationCorrection ?? this.rotationCorrection,
168175
errorDescription: errorDescription != _defaultErrorDescription
169176
? errorDescription
170177
: this.errorDescription,
@@ -368,6 +375,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
368375
value = value.copyWith(
369376
duration: event.duration,
370377
size: event.size,
378+
rotationCorrection: event.rotationCorrection,
371379
isInitialized: event.duration != null,
372380
errorDescription: null,
373381
);
@@ -761,10 +769,29 @@ class _VideoPlayerState extends State<VideoPlayer> {
761769
Widget build(BuildContext context) {
762770
return _textureId == VideoPlayerController.kUninitializedTextureId
763771
? Container()
764-
: _videoPlayerPlatform.buildView(_textureId);
772+
: _VideoPlayerWithRotation(
773+
rotation: widget.controller.value.rotationCorrection,
774+
child: _videoPlayerPlatform.buildView(_textureId),
775+
);
765776
}
766777
}
767778

779+
class _VideoPlayerWithRotation extends StatelessWidget {
780+
const _VideoPlayerWithRotation(
781+
{Key? key, required this.rotation, required this.child})
782+
: super(key: key);
783+
final int rotation;
784+
final Widget child;
785+
786+
@override
787+
Widget build(BuildContext context) => rotation == 0
788+
? child
789+
: Transform.rotate(
790+
angle: rotation * math.pi / 180,
791+
child: child,
792+
);
793+
}
794+
768795
/// Used to configure the [VideoProgressIndicator] widget's colors for how it
769796
/// describes the video's status.
770797
///

packages/video_player/video_player/pubspec.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for displaying inline video with other Flutter
33
widgets on Android, iOS, and web.
44
repository: https://github.com/flutter/plugins/tree/main/packages/video_player/video_player
55
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
6-
version: 2.4.2
6+
version: 2.4.3
77

88
environment:
99
sdk: ">=2.14.0 <3.0.0"
@@ -23,9 +23,9 @@ dependencies:
2323
flutter:
2424
sdk: flutter
2525
html: ^0.15.0
26-
video_player_android: ^2.2.17
26+
video_player_android: ^2.3.5
2727
video_player_avfoundation: ^2.2.17
28-
video_player_platform_interface: ^5.1.0
28+
video_player_platform_interface: ^5.1.1
2929
video_player_web: ^2.0.0
3030

3131
dev_dependencies:

packages/video_player/video_player/test/video_player_test.dart

+24
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66
import 'dart:io';
7+
import 'dart:math' as math;
78

89
import 'package:flutter/material.dart';
910
import 'package:flutter/services.dart';
@@ -15,6 +16,8 @@ class FakeController extends ValueNotifier<VideoPlayerValue>
1516
implements VideoPlayerController {
1617
FakeController() : super(VideoPlayerValue(duration: Duration.zero));
1718

19+
FakeController.value(VideoPlayerValue value) : super(value);
20+
1821
@override
1922
Future<void> dispose() async {
2023
super.dispose();
@@ -149,6 +152,27 @@ void main() {
149152
findsOneWidget);
150153
});
151154

155+
testWidgets('non-zero rotationCorrection value is used',
156+
(WidgetTester tester) async {
157+
final FakeController controller = FakeController.value(
158+
VideoPlayerValue(duration: Duration.zero, rotationCorrection: 180));
159+
controller.textureId = 1;
160+
await tester.pumpWidget(VideoPlayer(controller));
161+
final Transform actualRotationCorrection =
162+
find.byType(Transform).evaluate().single.widget as Transform;
163+
expect(
164+
actualRotationCorrection.transform, equals(Matrix4.rotationZ(math.pi)));
165+
});
166+
167+
testWidgets('no transform when rotationCorrection is zero',
168+
(WidgetTester tester) async {
169+
final FakeController controller = FakeController.value(
170+
VideoPlayerValue(duration: Duration.zero, rotationCorrection: 0));
171+
controller.textureId = 1;
172+
await tester.pumpWidget(VideoPlayer(controller));
173+
expect(find.byType(Transform), findsNothing);
174+
});
175+
152176
group('ClosedCaption widget', () {
153177
testWidgets('uses a default text style', (WidgetTester tester) async {
154178
const String text = 'foo';

0 commit comments

Comments
 (0)