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

[video_player] Android: Rotate videos recorded in landscapeRight #3820

Merged
merged 30 commits into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6426e17
Restoring `main` fork branch to fetch from upstream (will create a ne…
KyleFin Apr 22, 2021
30ad913
Restoring `main` fork branch to fetch from upstream (will create a ne…
KyleFin Apr 22, 2021
83c70f2
Restoring `main` fork branch to fetch from upstream (will create a ne…
KyleFin Apr 22, 2021
055882f
Rotate video widget 180 degrees on Android if exoPlayer.getVideoForma…
KyleFin Apr 22, 2021
5c1346c
Add draft test to confirm VideoPlayer widget is rotated for landscape…
KyleFin Jun 25, 2021
4d1bf5e
Add draft unit test to confirm VideoPlayer widget uses rotation.
KyleFin Jun 25, 2021
c58b9dd
Working widget test to confirm rotation is used.
KyleFin Aug 23, 2021
780fed4
Don't need to use real value for Pi.
KyleFin Aug 23, 2021
3a3bb7d
Add Java unit test for setting rotation.
KyleFin Aug 24, 2021
5564d21
Revert initial attempt at e2e Android rotation test.
KyleFin Aug 24, 2021
b8738b0
Use mockExoplayer.
KyleFin Aug 24, 2021
a927104
Update CHANGELOG.md and pubspec version.
KyleFin Aug 24, 2021
9c0609b
Simplify testing constructor for VideoPlayer.java.
KyleFin Sep 24, 2021
751ea50
Addressing PR suggestions:
KyleFin Dec 16, 2021
1254ff4
Fixes for format and publishable checks.
KyleFin Dec 17, 2021
ccb0902
Use degrees for rotationCorrection
KyleFin Mar 16, 2022
3fae79c
Add current non-Java code after merging platform interface PR.
KyleFin Mar 23, 2022
e41ae68
Restore unrelated dart that got clobbered in syncing to head.
KyleFin Mar 23, 2022
2facfcb
Remove extra java constructor (not needed for testing)
KyleFin Apr 1, 2022
c2a9dde
Revert Java unit tests (don't expose internals)
KyleFin Apr 1, 2022
04bf121
Fix checks
KyleFin Apr 1, 2022
8bda777
Update video_player_platform_interface for Android and video_player
KyleFin Apr 2, 2022
374111f
Update video_player dep on video_player_android
KyleFin Apr 2, 2022
3277926
Add tests and refactor
camsim99 Apr 25, 2022
ffb787d
Address comments
camsim99 Apr 27, 2022
1b66881
Fix tests, add fix
camsim99 Apr 27, 2022
7f666a7
Add annotation
camsim99 Apr 27, 2022
5fc340d
Move lines
camsim99 May 4, 2022
a32b5ff
Update pubspec and CHANGELOG
KyleFin Jun 2, 2022
aba4688
Use widget class instead of returning widget from helper https://yout…
KyleFin Jun 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/video_player/video_player/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
31 changes: 29 additions & 2 deletions packages/video_player/video_player/lib/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -48,6 +49,7 @@ class VideoPlayerValue {
this.isBuffering = false,
this.volume = 1.0,
this.playbackSpeed = 1.0,
this.rotationCorrection = 0,
this.errorDescription,
});

Expand Down Expand Up @@ -111,6 +113,9 @@ class VideoPlayerValue {
/// 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;

Expand All @@ -136,7 +141,7 @@ class VideoPlayerValue {
}

/// 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,
Expand All @@ -150,6 +155,7 @@ class VideoPlayerValue {
bool? isBuffering,
double? volume,
double? playbackSpeed,
int? rotationCorrection,
String? errorDescription = _defaultErrorDescription,
}) {
return VideoPlayerValue(
Expand All @@ -165,6 +171,7 @@ class VideoPlayerValue {
isBuffering: isBuffering ?? this.isBuffering,
volume: volume ?? this.volume,
playbackSpeed: playbackSpeed ?? this.playbackSpeed,
rotationCorrection: rotationCorrection ?? this.rotationCorrection,
errorDescription: errorDescription != _defaultErrorDescription
? errorDescription
: this.errorDescription,
Expand Down Expand Up @@ -368,6 +375,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
value = value.copyWith(
duration: event.duration,
size: event.size,
rotationCorrection: event.rotationCorrection,
isInitialized: event.duration != null,
errorDescription: null,
);
Expand Down Expand Up @@ -761,10 +769,29 @@ class _VideoPlayerState extends State<VideoPlayer> {
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.
///
Expand Down
6 changes: 3 additions & 3 deletions packages/video_player/video_player/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for displaying inline video with other Flutter
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"
Expand All @@ -23,9 +23,9 @@ dependencies:
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:
Expand Down
24 changes: 24 additions & 0 deletions packages/video_player/video_player/test/video_player_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -15,6 +16,8 @@ class FakeController extends ValueNotifier<VideoPlayerValue>
implements VideoPlayerController {
FakeController() : super(VideoPlayerValue(duration: Duration.zero));

FakeController.value(VideoPlayerValue value) : super(value);

@override
Future<void> dispose() async {
super.dispose();
Expand Down Expand Up @@ -149,6 +152,27 @@ void main() {
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';
Expand Down