betterplayer
betterplayer copied to clipboard
[BUG] [Android TV] HLS ABR video doesn't fill screen until resolution changes
History check I've checked the issue history and haven't found any reports which quite match.
Describe the bug In release mode, on the new Google Chromecast with Google TV, when playing an HLS ABR video that starts out as 720p but later switches to 1080p, the video is rendered in a small portion of the upper left corner of the screen. Once the video switches to 1080p, it is rendered filling the screen as expected.
To Reproduce Steps to reproduce the behavior:
- Add BetterPlayer widget and allow it to fill the screen
- Build in release mode and install to Android/Google TV device
- Play an ABR video over HLS
- See that the video doesn't respect the
fit
setting and plays in the upper-left corner until the video's resolution changes
Example code
import 'package:better_player/better_player.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late BetterPlayerController _betterPlayerController;
@override
void initState() {
super.initState();
BetterPlayerDataSource betterPlayerDataSource = BetterPlayerDataSource(
BetterPlayerDataSourceType.network,
"https://stream.mux.com/LC7NoNM00LQTQRmzsSLhYhrwDSLwD8uaX8N2e4qXn8pQ.m3u8",
);
_betterPlayerController = BetterPlayerController(
const BetterPlayerConfiguration(
autoPlay: true,
fit: BoxFit.contain,
),
betterPlayerDataSource: betterPlayerDataSource);
}
@override
Widget build(BuildContext context) {
return BetterPlayer(
controller: _betterPlayerController,
);
}
}
Expected behavior
The video should always fill the screen as per the fit: BoxFit.contain
setting.
Screenshots
Before switching to 1080p quality (in practice, the first few seconds of playback):
After switching to 1080p quality:
Flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.5.3, on Fedora 34 (Workstation Edition) 5.14.11-200.fc34.x86_64, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] Android Studio (version 4.2)
[✓] VS Code (version 1.61.1)
[✓] Connected device (3 available)
• No issues found!
Better Player version
- Version:
0.0.77
Smartphone (please complete the following information): I understand that TV devices aren't the intended use case for better_player (or even Flutter), but other than this bug, it meets our needs quite nicely. I was hoping the author of the plugin or anyone else could provide some insight on how to fix or work around this.
- Device: Chromecast with Google TV
- OS: Android TV 10
The problem also happens on Fire TV sticks, but the area the video doesn't cover is solid green, strangely:
- Device: Fire TV Stick 4K
- OS: Fire OS 6.2.8.1
Additional context
- It's important to note that this problem only seems to happen when the app is run in release mode. In debug mode, I wasn't able to reproduce the issue reliably (or at all).
- It only happens on the first run of the app. Stopping the video and playing another without restarting or reinstalling the app doesn't show the same incorrect behavior.
- 720p videos played directly from MP4 files don't show this behavior either. It only applies to ABR videos streamed through HLS.
- It doesn't seem to matter whether better_player is "fullscreen" or not.
@trms-alex Thanks for preparing such detailed description.
Unfortunately, right now I don't see any solution for that. I'm seeing same error for official video_player plugin: https://github.com/flutter/flutter/issues/85583 which hasn't been solved.
Other links: https://github.com/jhomlala/betterplayer/issues/658
I'll leave this ticket open, maybe in the future I'll find solution for that.
Just wanted to throw out that I just saw this same behavior on a a simulator:
Simulator details incase its useful:
Name: Pixel_3a_API_30_x86
CPU/ABI: Google APIs Intel Atom (x86)
Path: /Users/raytiley/.android/avd/Pixel_3a_API_30_x86.avd
Target: google_apis [Google APIs] (API level 30)
Skin: pixel_3a
SD Card: 800M
Snapshot: no
hw.dPad: no
hw.lcd.height: 2220
runtime.network.speed: full
hw.accelerometer: yes
hw.device.name: pixel_3a
vm.heapSize: 256
hw.device.manufacturer: Google
hw.lcd.width: 1080
hw.gps: yes
image.androidVersion.api: 30
hw.audioInput: yes
image.sysdir.1: system-images/android-30/google_apis/x86/
tag.id: google_apis
hw.camera.back: emulated
hw.mainKeys: no
AvdId: Pixel_3a_API_30_x86
hw.camera.front: emulated
hw.lcd.density: 440
avd.ini.displayname: Pixel_3a_API_30_x86
hw.arc: false
hw.gpu.mode: auto
snapshot.present: no
hw.device.hash2: MD5:0e6953ebf01bdc6b33a2f54746629c50
hw.ramSize: 1536
hw.trackBall: no
PlayStore.enabled: false
hw.battery: yes
hw.cpu.ncore: 6
hw.sdCard: yes
tag.display: Google APIs
runtime.network.latency: none
hw.keyboard: yes
hw.sensors.proximity: yes
disk.dataPartition.size: 6442450944
hw.sensors.orientation: yes
avd.ini.encoding: UTF-8
hw.gpu.enabled: yes
I have the exact same problem on a Mi Android TV (Android 9) setup.
I also tested it with an emulator using @raytiley 's proposed version and settings and I confirm that the problem can be repeated on this emulator.
However I could not find why it behaves different on different devices.
I forked the repository (https://github.com/postacik/betterplayer) and upgraded Exoplayer to v2.16.1 but it did not solve the problem.
Has any of you found a solution for this problem?
I extended the sample above with video_player plugin and it has the same behaviour as better_player:
import 'dart:developer';
import 'package:better_player/better_player.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _mediaFile = "https://stream.mux.com/LC7NoNM00LQTQRmzsSLhYhrwDSLwD8uaX8N2e4qXn8pQ.m3u8";
late BetterPlayerController _betterPlayerController;
late VideoPlayerController _videoPlayerController;
@override
void initState() {
super.initState();
BetterPlayerDataSource betterPlayerDataSource = BetterPlayerDataSource(BetterPlayerDataSourceType.network, _mediaFile);
_betterPlayerController = BetterPlayerController(
BetterPlayerConfiguration(
autoPlay: true,
// controlsConfiguration: const BetterPlayerControlsConfiguration(
// enableFullscreen: false,
// playerTheme: BetterPlayerTheme.cupertino,
// enableSkips: false,
// ),
// fullScreenByDefault: false,
// expandToFill: false,
fit: BoxFit.contain,
eventListener: (ev) {
if (ev.betterPlayerEventType != BetterPlayerEventType.progress && ev.betterPlayerEventType != BetterPlayerEventType.bufferingUpdate) {
log("${ev.betterPlayerEventType}");
}
if (ev.betterPlayerEventType == BetterPlayerEventType.initialized) {
var size = _betterPlayerController.videoPlayerController!.value.size;
log("${size!.width}x${size.height}");
}
},
),
betterPlayerDataSource: betterPlayerDataSource,
);
_videoPlayerController = VideoPlayerController.network(_mediaFile);
_videoPlayerController.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {
_videoPlayerController.play();
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BetterPlayer(
controller: _betterPlayerController,
),
_videoPlayerController.value.isInitialized
? GestureDetector(
onTap: () {
if (_videoPlayerController.value.isPlaying) {
_videoPlayerController.pause();
} else {
_videoPlayerController.play();
}
},
child: AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
),
)
: Container(),
],
),
),
),
);
}
}
And here is the video demonstrating the problem. The video at the top is better_player, the one at the bottom is video_player.
https://user-images.githubusercontent.com/3977227/153762613-0971a362-3903-4415-ab85-f775537747e4.mp4
Similar issues have been reported for video_player like the one below:
https://github.com/flutter/flutter/issues/46460#issue-534504607
Does anyone find any workaround? Please reply.
There is a fix for this problem on master channel: https://github.com/flutter/engine/pull/24888
I tested this commit (Flutter channel master 3.1.0-0.0.pre.2125) with my TV player application.
Although compilation gave some errors complaining about missing overrides and parameters in ".pub-cache/hosted/pub.dartlang.org/fwfh_text_style-2.7.3+1/lib/fwfh_text_style.dart", I managed to fix it with small additions.
I do confirm that the problem is solved on my Mi Smart Projector running Android TV 9.0.
This seems to be the same problem...
I'm using a stream with multiple resolutions, it starts the video at a low resolution and then goes to full resolution. Here I have a problem that the video does not fit the screen size, it exceeds.
Then I switched to the lowest resolution and the screen looked like this:
flutter/engine#24888
There is a fix for this problem on master channel: flutter/engine#24888
I tested this commit (Flutter channel master 3.1.0-0.0.pre.2125) with my TV player application.
Although compilation gave some errors complaining about missing overrides and parameters in ".pub-cache/hosted/pub.dartlang.org/fwfh_text_style-2.7.3+1/lib/fwfh_text_style.dart", I managed to fix it with small additions.
I do confirm that the problem is solved on my Mi Smart Projector running Android TV 9.0.
How can I install this version 3.1.0-0.0.pre.2125?
There are no tags with this version
I installed the master and still with the same problem