Open Andrekarma opened 2 months ago
I think the controller instance you created is not pointed by any variable anymore, so dart garbage collection try to clean it.
Could you try to assign the controller instance to a static / global variable (though it is not a good idea), ensure you just create ONE controller instance, and check the message still occurs?
I am creating 2 instances of a class with the video controller. i load 2 different videos at the time, but only one is showed. The second one is ready for the first one to be finished, then i switch them. Sometimes (randomly) the "[video_player_win] gc free a player that didn't dispose() yet !!!! appears" and the instance that is not playing is gone.
`class PHFPlayerVideoPlayer extends PHFPlayer{ PHFPlayerVideoPlayer(index){ this.index = index; }
VideoPlayerController? videoPlayerController;
@override closeVideoPlayer() async{ if(videoPlayerController != null) { await videoPlayerController!.pause(); await videoPlayerController!.dispose(); videoPlayerController = null; } }
@override initializeVideoSlide(path) async{ videoPlayerController = VideoPlayerController.file(File(path)); videoPlayerController!.initialize(); videoPlayerController!.setVolume(PHFConfig.instance.moviesVolume 100 (PHFConfig.instance.disableMovieAudio == 0 ? 1 : 0)); } `
I hope it is related to the fact that after some iterations of this switch beetween different videos, the app crashes with no specific error log
I write the following simple test code, always preload the next video every time when clicking "Next" button. I try to click the "Next" button every second about 50 times, and it works well with no gc occurs.
Did this solve your problem?
Note: Please remember to edit the gFileList
array in the following code if you try to run it.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:video_player_win/video_player_win.dart';
void main() {
runApp(const MyApp());
}
const gFileList = [
"E:\\test_4k.mp4",
"E:\\test_align.mp4",
"E:\\test_av1.mp4",
"E:\\test_clock.mp4",
"E:\\test_youtube.mp4",
];
class PHFPlayerVideoPlayer {
WinVideoPlayerController? controller;
Future<void> initializeVideoSlide(String path) async {
controller?.dispose();
controller = WinVideoPlayerController.file(File(path));
await controller!.initialize();
}
void play() {
controller!.play();
}
void closeVideoPlayer() {
controller?.dispose();
controller = null;
}
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var nowPlayer = PHFPlayerVideoPlayer();
var nextPlayer = PHFPlayerVideoPlayer();
int nowIndex = 0;
@override
void initState() {
super.initState();
nowIndex = 0;
nowPlayer.initializeVideoSlide(gFileList[nowIndex]).then((value) {
nowPlayer.play();
setState(() {}); // update UI
});
prepareNext();
}
void prepareNext() {
int nextIndex = (nowIndex + 1) % gFileList.length; // loop the list
nextPlayer.initializeVideoSlide(gFileList[nextIndex]);
}
void onNextButtonClicked() {
nowPlayer.closeVideoPlayer();
// swap 2 player pointer
var tmp = nextPlayer;
nextPlayer = nowPlayer;
nowPlayer = tmp;
nowIndex = (nowIndex + 1) % gFileList.length; // loop the list
nowPlayer.play();
prepareNext();
setState(() {}); // update UI
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Stack(children: [
WinVideoPlayer(nowPlayer.controller!),
ElevatedButton(
onPressed: onNextButtonClicked, child: const Text("Next")),
]),
));
}
}
It is still happening, and i don't understand why The logic is the same of your example, but the Garbage collector is doing something that should not be doing. I still think is something related to this library, because its not happening with other libraries
First, did you try to run my sample code above, WITHOUT any modification, and ensure that the GC still occurs ?
Second, you said it is not happen with other libraries, Could you give me a SIMPLE sample code ( less than 200 lines ), and tell me which library and which platform that no GC occurs. I need more information to clarify issue.
@jakky1 Here you have it
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart';
void main() { runApp(const MyApp()); }
const gFileList = [ "C:\Users\andreacarmagnola\Desktop\VIDEOTEST\4kvert.mp4", "C:\Users\andreacarmagnola\Desktop\VIDEOTEST\bene.mp4", "C:\Users\andreacarmagnola\Desktop\VIDEOTEST\male.mp4", ];
class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key);
@override
State
class _MyAppState extends State
@override initState(){ super.initState(); nowIndex = 0; Future.delayed(Duration(seconds: 1), () async { await player1.initializeVideoSlide(gFileList[nowIndex]); int nextIndex = (nowIndex + 1) % gFileList.length; // loop the list await player2.initializeVideoSlide(gFileList[nextIndex]); currentPlayer = player1;
setState(() {
showPlayer = true;
});
});
}
@override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Stack(children: [ showPlayer?currentPlayer.getVideoWidget(false):Container()
]),
),
);
} }
abstract class PHFPlayer { static const int VIDEO_PLAYER_LIBRARY = 2;
late int libraryType; late int index; late Image image;
Future
Widget getVideoWidget(useBlur);
static PHFPlayer createVideoPlayer(int libraryType, index) { return PHFPlayerVideoPlayer(index);
}
}
class PHFPlayerVideoPlayer extends PHFPlayer{ PHFPlayerVideoPlayer(index){ this.index = index; libraryType = PHFPlayer.VIDEO_PLAYER_LIBRARY; }
VideoPlayerController? videoPlayerController;
@override initializeVideoSlide(videoFile) async{ videoPlayerController = VideoPlayerController.file(File(videoFile)); await videoPlayerController!.initialize(); }
@override Widget getVideoWidget(useBlur){ videoPlayerController!.play(); return VideoPlayer(videoPlayerController!); }
}
Thanks for reporting this issue, and the sample code.
It seems there is really something wrong in this package. In my sample code last week, I use WinVideoPlayerController, and it really work well. In your sample code, you use official VideoPlayerController, and gc occurs.
It is confirmed that if any VideoPlayerController created but not displayed, then the WinVideoPlayerController which is created by this VideoPlayerController will be GC collection. I have never test this case with official VideoPlayerController before... orz
Now it is fixed, and I only push to github now. Please try it and let me know if the solution works for you.
dependencies:
video_player_win:
git:
url: https://github.com/jakky1/video_player_win.git
ref: master
The GC issue seems now resolved
But not there is another problem. Randomly after some time playing, i see this error and the app crashes
[ERROR:flutter/shell/platform/windows/external_texture_d3d.cc(107)] Binding D3D surface failed.
Because it rarely occurs, again I need a simple sample code (< 300 lines) and a more easy way to duplicate this issue.
I have no way to fix this before I can duplicate this issue on my PC.
import 'dart:async'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; import 'package:video_player_win/video_player_win.dart';
void main() { runApp(const MyApp()); }
const gFileList = [ "C:\Users\andreacarmagnola\Desktop\VIDEOTEST\4kvert.mp4", "C:\Users\andreacarmagnola\Desktop\VIDEOTEST\bene.mp4" ];
class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key);
@override
State
class _MyAppState extends State
@override initState(){ super.initState(); nowIndex = 0; Future.delayed(Duration(seconds: 1), () async { await player1.initializeVideoSlide(gFileList[0]); player1.index =1 ; int nextIndex = (nowIndex + 1) % gFileList.length; // loop the list await player2.initializeVideoSlide(gFileList[1]); player2.index = 2; currentPlayer = player1;
Timer.periodic(Duration(seconds: 5), (Timer) async {
await switchPlayer();
});
setState(() {
showPlayer = true;
});
});
}
switchPlayer() async{ if (currentPlayer.index == 1) { currentPlayer = player2; await player1.videoPlayerController!.dispose(); await player1.initializeVideoSlide(gFileList[0]); } else { currentPlayer = player1; await player2.videoPlayerController!.dispose(); await player2.initializeVideoSlide(gFileList[1]); }
setState(() {});
}
@override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Stack(children: [ showPlayer?currentPlayer.getVideoWidget(false):Container()
]),
),
);
} }
class PHFPlayerVideoPlayer {
int index = 0; WinVideoPlayerController? videoPlayerController;
initializeVideoSlide(videoFile) async{ videoPlayerController = WinVideoPlayerController.file(File(videoFile)); await videoPlayerController!.initialize(); }
Widget getVideoWidget(useBlur){ videoPlayerController!.play(); return WinVideoPlayer(videoPlayerController!); }
}
@jakky1 do you have any update on this?
I have run your code in debug mode (5 hours) and release mode (8 hours)
without any error occurs...
I have no idea how to produce & fix the error Binding D3D surface failed
you mentioned...
if i initialize a video player and dont use it (i want to prepare it for later), this message occur:
[video_player_win] gc free a player that didn't dispose() yet !!!!!
And the player is no more initialized