-
-
Notifications
You must be signed in to change notification settings - Fork 65
Open
Description
Describe the bug
I started using the latest version (from git) on Windows 11, with latest NVidia drivers. My code used to have smooth playback on windows 10 (please note I am not sure win11 upgrade is to blame but I thought I might mention it). but now I have a lot of logs in my console that says:
00000242E60421D0>500 00:00:00.5/01:45:02 cache 0v 3.6s/5732KB 982KB/s |+3|<4ms update 40.8ms 25.0fps draw 0/2 +0ms
00000242E60421D0>626 00:00:00.6/01:45:02 cache 0v 3.6s/6152KB 994KB/s |+0|<4ms update 41.3ms 23.9fps draw 0/2 +0ms
00000242E60421D0>755 00:00:00.7/01:45:02 cache 0v 3.6s/6224KB 1203KB/s |-5|>4ms update 41.6ms 24.1fps draw 0/2 +0ms
00000242E60421D0>876 00:00:00.8/01:45:02 cache 0v 3.7s/6626KB 988KB/s |+0|<4ms update 41.4ms 24.0fps draw 0/2 +0ms
00000242E60421D0>1004 00:00:01.0/01:45:02 cache 0v 3.7s/7135KB 869KB/s |-3|<4ms update 42.0ms 24.0fps draw 0/0 +0ms
00000242E60421D0>1126 00:00:01.1/01:45:02 cache 0v 3.6s/7190KB 1035KB/s |+0|<4ms update 41.8ms 23.9fps draw 0/0 +0ms
00000242E60421D0>1255 00:00:01.2/01:45:02 cache 0v 3.7s/7677KB 1067KB/s |-4|>4ms update 41.9ms 24.0fps draw 0/0 +0ms
00000242E60421D0>1376 00:00:01.3/01:45:02 cache 0v 3.5s/8131KB 9869KB/s |+0|<4ms update 41.7ms 23.8fps draw 0/0 +0ms
00000242E60421D0>1505 00:00:01.5/01:45:02 cache 0v 3.7s/8204KB 1165KB/s |-4|>4ms update 42.0ms 23.9fps draw 0/0 +0ms
00000242E60421D0>1627 00:00:01.6/01:45:02 cache 0v 3.6s/8655KB 1094KB/s |+1|<4ms update 41.3ms 23.8fps draw 0/0 +0ms
It is not very clear what they mean but since the playback is choppy, I am assuming it is related
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fvp/fvp.dart' as fvp;
import 'package:fvp/src/video_player_mdk.dart';
import 'package:fvp/src/global.dart';
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
import 'base_player.dart';
/// FVP (libmpv/mdk) implementation of BasePlayerController
class FvpPlayerImpl extends BasePlayerController {
final MdkVideoPlayer _player = MdkVideoPlayer();
final List<VoidCallback> _listeners = [];
Timer? _pollTimer;
StreamSubscription<VideoEvent>? _eventSubscription;
Size? _textureSize;
Duration _position = Duration.zero;
Duration _duration = Duration.zero;
bool _isPlaying = false;
FvpPlayerImpl(String url) {
print('[FVP] Creating player for URL: $url');
// Configure video decoders based on platform
const vd = {
'windows': ['CUDA', "D3D11", 'FFmpeg'],
'macos': ['VT', 'FFmpeg'],
'ios': ['VT', 'FFmpeg'],
'linux': ['VAAPI', 'CUDA', 'VDPAU', 'FFmpeg'],
'android': ['AMediaCodec', 'FFmpeg'],
};
final platform = Platform.operatingSystem.toLowerCase();
_player.videoDecoders = vd[platform]!;
print('[FVP] Video decoders set for $platform: ${_player.videoDecoders}');
// Set media URL - this must be done before updateTexture()
_player.media = url;
print('[FVP] Media URL set: ${_player.media}');
// Configure buffer range for smooth playback
_player.setBufferRange(min: 3000, max: 30000);
// print('[FVP] Buffer range configured: 3s - 30s');
// Listen to video events
_eventSubscription = _player.streamCtl.stream.listen((event) {
switch (event.eventType) {
case VideoEventType.initialized:
_duration = event.duration ?? Duration.zero;
_notifyListeners();
break;
case VideoEventType.completed:
_position = _duration;
_isPlaying = false;
_notifyListeners();
break;
case VideoEventType.isPlayingStateUpdate:
_isPlaying = event.isPlaying ?? false;
_notifyListeners();
break;
default:
break;
}
});
_pollTimer = Timer.periodic(Duration(milliseconds: 100), (_) {
_updatePosition();
});
}
void _updatePosition() {
final newPosition = Duration(milliseconds: _player.position);
if (newPosition != _position) {
_position = newPosition;
_notifyListeners();
}
}
void _notifyListeners() {
for (final listener in _listeners) {
listener();
}
}
@override
Future<void> initialize() async {
print('[FVP_INIT] Initializing FvpPlayerImpl');
// Register FVP plugin
fvp.registerWith();
// Initialize subtitle tracks
_player.activeSubtitleTracks = [];
// Temporarily set to playing to trigger media loading
print('[FVP] Setting state to playing to trigger loading...');
_player.state = PlaybackState.playing;
// Update texture - this triggers texture creation
_player.updateTexture();
}
@override
Future<void> play() async {
_player.state = PlaybackState.playing;
}
@override
Future<void> pause() async {
_player.state = PlaybackState.paused;
}
@override
Future<void> seekTo(Duration position) async {
print('[FVP] Seeking to ${position.inSeconds}s');
_player.seek(position: position.inSeconds);
// Force position update and notify listeners
_updatePosition();
}
@override
Future<void> dispose() async {
_pollTimer?.cancel();
await _eventSubscription?.cancel();
_player.dispose();
}
@override
bool get isPlaying => _isPlaying;
@override
Duration get position => _position;
@override
Duration get duration => _duration;
@override
double get aspectRatio {
if (_textureSize != null && _textureSize!.height > 0) {
return _textureSize!.width / _textureSize!.height;
}
return 16 / 9;
}
@override
void addListener(VoidCallback listener) {
_listeners.add(listener);
}
@override
void removeListener(VoidCallback listener) {
_listeners.remove(listener);
}
@override
Future<void> setSubtitleTrack(String? url) async {
if (url == null) {
_player.activeSubtitleTracks = [];
} else {
_player.setMedia(url, MediaType.subtitle);
}
}
@override
Future<void> setSubtitleTrackByIndex(int trackIndex) async {
if (trackIndex == -1) {
_player.activeSubtitleTracks = [];
} else {
_player.activeSubtitleTracks = [trackIndex];
}
}
@override
List<SubtitleTrackInfo> get availableSubtitles {
final subtitleTracks = _player.mediaInfo.subtitle ?? [];
return subtitleTracks.asMap().entries.map((entry) {
final track = entry.value;
final title = track.metadata['title'] as String?;
final language = track.metadata['language'] as String?;
return SubtitleTrackInfo(
title: title,
language: language,
index: entry.key,
);
}).toList();
}
@override
List<AudioTrackInfo> get availableAudioTracks {
final audioTracks = _player.mediaInfo.audio ?? [];
return audioTracks.asMap().entries.map((entry) {
final track = entry.value;
final title = track.metadata['title'] as String?;
final language = track.metadata['language'] as String?;
final channels = track.metadata['channels'] as int?;
return AudioTrackInfo(
title: title,
language: language,
channels: channels,
index: entry.key,
);
}).toList();
}
@override
Future<void> setAudioTrack(int trackIndex) async {
_player.activeAudioTracks = [trackIndex];
}
@override
Widget createVideoWidget() {
return RepaintBoundary(
child: VideoTexture(
player: _player,
),
);
}
}
/// Separate widget to handle FVP texture rendering
class VideoTexture extends StatefulWidget {
final MdkVideoPlayer player;
const VideoTexture({required this.player, super.key});
@override
State<VideoTexture> createState() => _VideoTextureState();
}
class _VideoTextureState extends State<VideoTexture> {
Size? _textureSize;
@override
void initState() {
super.initState();
_getTextureSize();
}
Future<void> _getTextureSize() async {
final videoPlayerPlatform =
VideoPlayerPlatform.instance as MdkVideoPlayerPlatform;
if (widget.player != null) {
final size = await widget.player.textureSize;
if (size != null && mounted) {
setState(() {
_textureSize = size;
});
}
}
}
@override
Widget build(BuildContext context) {
if (_textureSize == null) {
return const Center(child: CircularProgressIndicator());
}
Future.delayed(
const Duration(milliseconds: 15),
() => setState(() {}),
);
return AspectRatio(
aspectRatio: _textureSize!.width / _textureSize!.height,
child: Texture(
// filterQuality: FilterQuality.none,
textureId: widget.player.textureId.value ?? 0,
),
);
}
}
Metadata
Metadata
Assignees
Labels
No labels