feat(android): tune frame rate and subtitle rendering
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../../services/device_performance.dart';
|
||||
import '../../../services/settings_service.dart';
|
||||
import '../../models.dart';
|
||||
import '../player_base.dart';
|
||||
|
||||
@@ -98,6 +100,14 @@ class PlayerAndroid extends PlayerBase {
|
||||
'tunnelingEnabled': _tunnelingEnabled,
|
||||
'dvConversionMode': _dvConversionMode,
|
||||
'audioPassthroughEnabled': _audioPassthroughEnabled,
|
||||
// Cheap (32-bit) TV boxes run the hardware video path a frame behind a GL
|
||||
// subtitle overlay; render the ASS one frame earlier there to realign.
|
||||
'assVideoLatencyFrames': DevicePerformance.isLowEndHardware ? 1 : 0,
|
||||
// libass overlay raster scale from the "Render Resolution" subtitle setting
|
||||
// (Full / ¾ / ½ / ⅓ / ¼); < 1 trades sharpness for throughput on slow GPUs.
|
||||
'subtitleRenderScale': SettingsService.instance
|
||||
.read(SettingsService.subtitleRenderResolution)
|
||||
.androidRenderScale,
|
||||
});
|
||||
if (result != true) {
|
||||
throw Exception('Failed to initialize ExoPlayer');
|
||||
@@ -459,12 +469,20 @@ class PlayerAndroid extends PlayerBase {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setVideoFrameRate(double fps, int durationMs, {int extraDelayMs = 0}) async {
|
||||
Future<bool> setVideoFrameRate(
|
||||
double fps,
|
||||
int durationMs, {
|
||||
int extraDelayMs = 0,
|
||||
int videoWidth = 0,
|
||||
int videoHeight = 0,
|
||||
}) async {
|
||||
if (disposed || !initialized) return false;
|
||||
final result = await invoke<bool>('setVideoFrameRate', {
|
||||
'fps': fps,
|
||||
'duration': durationMs,
|
||||
'extraDelayMs': extraDelayMs,
|
||||
'videoWidth': videoWidth,
|
||||
'videoHeight': videoHeight,
|
||||
});
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,13 @@ abstract class Player {
|
||||
/// the caller is responsible for starting playback itself.
|
||||
///
|
||||
/// On other platforms, this is a no-op that returns `false`.
|
||||
Future<bool> setVideoFrameRate(double fps, int durationMs, {int extraDelayMs = 0});
|
||||
Future<bool> setVideoFrameRate(
|
||||
double fps,
|
||||
int durationMs, {
|
||||
int extraDelayMs = 0,
|
||||
int videoWidth = 0,
|
||||
int videoHeight = 0,
|
||||
});
|
||||
|
||||
/// Clear the video frame rate hint and restore default display mode.
|
||||
///
|
||||
|
||||
@@ -613,7 +613,13 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
|
||||
Future<void> updateFrame() async {}
|
||||
|
||||
@override
|
||||
Future<bool> setVideoFrameRate(double fps, int durationMs, {int extraDelayMs = 0}) async => false;
|
||||
Future<bool> setVideoFrameRate(
|
||||
double fps,
|
||||
int durationMs, {
|
||||
int extraDelayMs = 0,
|
||||
int videoWidth = 0,
|
||||
int videoHeight = 0,
|
||||
}) async => false;
|
||||
|
||||
@override
|
||||
// ignore: no-empty-block - base no-op, overridden by platform subclasses
|
||||
|
||||
@@ -7,9 +7,7 @@ import '../../media/media_display_criteria.dart';
|
||||
import '../models.dart';
|
||||
import 'player_base.dart';
|
||||
|
||||
/// Shared native implementation of [Player] for iOS, macOS, Android (MPV fallback), and Linux.
|
||||
/// Uses MPVKit via platform channels with Metal rendering (Apple), native window (Android),
|
||||
/// or FlTextureGL (Linux).
|
||||
/// MPV-backed player for platforms where AetherEngine is not the native route.
|
||||
class PlayerNative extends PlayerBase {
|
||||
int? _textureIdValue;
|
||||
String _dvConversionMode = 'auto';
|
||||
@@ -403,12 +401,20 @@ class PlayerNative extends PlayerBase {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setVideoFrameRate(double fps, int durationMs, {int extraDelayMs = 0}) async {
|
||||
Future<bool> setVideoFrameRate(
|
||||
double fps,
|
||||
int durationMs, {
|
||||
int extraDelayMs = 0,
|
||||
int videoWidth = 0,
|
||||
int videoHeight = 0,
|
||||
}) async {
|
||||
if (!Platform.isAndroid || disposed || !initialized) return false;
|
||||
final result = await invoke<bool>('setVideoFrameRate', {
|
||||
'fps': fps,
|
||||
'duration': durationMs,
|
||||
'extraDelayMs': extraDelayMs,
|
||||
'videoWidth': videoWidth,
|
||||
'videoHeight': videoHeight,
|
||||
});
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user