fix: iOS OOM during PiP playback cycles
Cancel leaked stream subscriptions in video player dispose and flush sample buffer layer on PiP teardown/cleanup to release video frames.
This commit is contained in:
@@ -245,10 +245,17 @@ class MpvPipController: NSObject {
|
||||
}
|
||||
pipController = nil
|
||||
delegateHelper = nil
|
||||
sampleBufferLayer.flushAndRemoveImage()
|
||||
sampleBufferLayer.controlTimebase = nil
|
||||
sampleBufferLayer.removeFromSuperlayer()
|
||||
containerView?.removeFromSuperview()
|
||||
containerView = nil
|
||||
}
|
||||
|
||||
/// Flush enqueued sample buffers from the layer to free video frame memory
|
||||
func flushLayer() {
|
||||
sampleBufferLayer.flushAndRemoveImage()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - PiP Delegate Helper (iOS 15+)
|
||||
|
||||
@@ -171,6 +171,7 @@ class MpvPlayerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, MpvPlayerD
|
||||
playerCore?.isPipActive = false
|
||||
isManualPipRequest = false
|
||||
stopPipTimebaseSync()
|
||||
pipController?.flushLayer()
|
||||
_ = playerCore?.switchToGpuNextVO()
|
||||
if pause { playerCore?.setProperty("pause", value: "yes") }
|
||||
if notify { pipChannel?.invokeMethod("onPipChanged", arguments: false) }
|
||||
|
||||
@@ -141,6 +141,9 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
StreamSubscription<void>? _playbackRestartSubscription;
|
||||
StreamSubscription<void>? _backendSwitchedSubscription;
|
||||
StreamSubscription<void>? _sleepTimerSubscription;
|
||||
StreamSubscription<bool>? _mediaControlsPlayingSubscription;
|
||||
StreamSubscription<Duration>? _mediaControlsPositionSubscription;
|
||||
StreamSubscription<double>? _mediaControlsRateSubscription;
|
||||
bool _isReplacingWithVideo = false; // Flag to skip orientation restoration during video-to-video navigation
|
||||
bool _isDisposingForNavigation = false;
|
||||
bool _waitingForExternalSubsTrackSelection = false;
|
||||
@@ -799,12 +802,12 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
);
|
||||
|
||||
// Listen to playing state and update media controls
|
||||
player!.streams.playing.listen((isPlaying) {
|
||||
_mediaControlsPlayingSubscription = player!.streams.playing.listen((isPlaying) {
|
||||
_updateMediaControlsPlaybackState();
|
||||
});
|
||||
|
||||
// Listen to position updates for media controls and Discord
|
||||
player!.streams.position.listen((position) {
|
||||
_mediaControlsPositionSubscription = player!.streams.position.listen((position) {
|
||||
_mediaControlsManager?.updatePlaybackState(
|
||||
isPlaying: player!.state.playing,
|
||||
position: position,
|
||||
@@ -814,7 +817,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
});
|
||||
|
||||
// Listen to playback rate changes for Discord Rich Presence
|
||||
player!.streams.rate.listen((rate) {
|
||||
_mediaControlsRateSubscription = player!.streams.rate.listen((rate) {
|
||||
DiscordRPCService.instance.updatePlaybackSpeed(rate);
|
||||
});
|
||||
|
||||
@@ -1740,6 +1743,9 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
_playbackRestartSubscription?.cancel();
|
||||
_backendSwitchedSubscription?.cancel();
|
||||
_sleepTimerSubscription?.cancel();
|
||||
_mediaControlsPlayingSubscription?.cancel();
|
||||
_mediaControlsPositionSubscription?.cancel();
|
||||
_mediaControlsRateSubscription?.cancel();
|
||||
|
||||
// Cancel auto-play timer
|
||||
_autoPlayTimer?.cancel();
|
||||
|
||||
Reference in New Issue
Block a user