fix: android subtitle font

This commit is contained in:
edde746
2025-12-04 16:39:07 +01:00
parent 074a6e7e7d
commit 1d50763d9b
3 changed files with 78 additions and 2 deletions
+25
View File
@@ -4,6 +4,8 @@ import 'dart:io' show Platform;
import 'package:flutter/services.dart';
import '../utils/android_font_loader.dart';
import '../models/audio_device.dart';
import '../models/audio_track.dart';
import '../models/player_log.dart';
@@ -295,6 +297,11 @@ class PlayerNative implements Player {
throw Exception('Failed to initialize player');
}
// Configure subtitle fonts for Android libass support
if (Platform.isAndroid) {
await _configureAndroidSubtitleFonts();
}
// Subscribe to MPV properties
await _observeProperty('time-pos', 'double');
await _observeProperty('duration', 'double');
@@ -321,6 +328,24 @@ class PlayerNative implements Player {
});
}
/// Configures subtitle fonts for Android libass support.
/// On Android, libass cannot access system fonts, so we need to provide
/// a font file from assets.
Future<void> _configureAndroidSubtitleFonts() async {
try {
final fontDir = await AndroidFontLoader.loadSubtitleFont();
if (fontDir != null) {
// Configure MPV to use the extracted font for libass
await setProperty('config', 'yes');
await setProperty('sub-fonts-dir', fontDir);
await setProperty('sub-font', AndroidFontLoader.fontName);
}
} catch (e) {
// Font configuration is not critical - continue without it
_errorController.add('Failed to configure subtitle fonts: $e');
}
}
void _checkDisposed() {
if (_disposed) {
throw StateError('Player has been disposed');
+53
View File
@@ -0,0 +1,53 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
/// Utility class for loading font assets on Android for libass subtitle rendering.
///
/// On Android, libass cannot access system fonts through fontconfig, so we need
/// to extract font files from Flutter assets to the app's cache directory.
class AndroidFontLoader {
static const String _fontAssetPath = 'assets/go-noto-current-regular.ttf';
static const String _fontName = 'Go Noto Current-Regular';
/// Loads the subtitle font from assets to the Android cache directory.
/// Returns the directory path containing the font file.
static Future<String?> loadSubtitleFont() async {
try {
// Get the app's cache directory
final cacheDir = await getTemporaryDirectory();
final fontDir = Directory(path.join(cacheDir.path, 'subtitle_fonts'));
// Create fonts directory if it doesn't exist
if (!await fontDir.exists()) {
await fontDir.create(recursive: true);
}
final fontFile = File(
path.join(fontDir.path, 'go-noto-current-regular.ttf'),
);
// Load font from assets and write to cache if it doesn't exist
if (!await fontFile.exists()) {
final fontData = await rootBundle.load(_fontAssetPath);
await fontFile.writeAsBytes(fontData.buffer.asUint8List());
}
return fontDir.path;
} catch (e) {
// Return null if font loading fails - libass will fall back gracefully
if (kDebugMode) {
debugPrint('Failed to load subtitle font: $e');
}
return null;
}
}
/// Returns the font name to be used with libass.
static String get fontName => _fontName;
/// Returns the font asset path.
static String get fontAssetPath => _fontAssetPath;
}
-2
View File
@@ -254,8 +254,6 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen>
player = Player();
await player!.setProperty('sub-ass', 'yes'); // Enable libass
await player!.setProperty('sub-fonts-dir', 'assets');
await player!.setProperty('sub-font', 'Go Noto Current-Regular');
await player!.setProperty(
'demuxer-max-bytes',
bufferSizeBytes.toString(),