fix(player): 修复清晰度切换闪屏与还原黑屏
This commit is contained in:
1 parent
43e60e29ec
commit
85dedf20fa
8 files changed
+249
-296
No files matched your search
@@ -29,6 +29,7 @@ class PlayerVideoSurface extends StatefulWidget {
|
||||
this.debugIndex,
|
||||
this.showFallbackBackground = true,
|
||||
this.onVideoVisible,
|
||||
this.resumeSignal = 0,
|
||||
});
|
||||
|
||||
final VideoPlayerController? controller;
|
||||
@@ -60,6 +61,10 @@ class PlayerVideoSurface extends StatefulWidget {
|
||||
final bool theater;
|
||||
final VoidCallback? onVideoVisible;
|
||||
|
||||
/// iOS 画中画还原等场景的恢复信号:数值变化时回退到占位并重新等首帧,
|
||||
/// 避免纹理被系统回收后显示黑屏(封面占位 → 新帧淡入)。
|
||||
final int resumeSignal;
|
||||
|
||||
@override
|
||||
State<PlayerVideoSurface> createState() => _PlayerVideoSurfaceState();
|
||||
}
|
||||
@@ -76,6 +81,11 @@ class _PlayerVideoSurfaceState extends State<PlayerVideoSurface>
|
||||
bool _transitioning = false;
|
||||
bool _videoVisible = false;
|
||||
bool _videoVisibleNotified = false;
|
||||
/// 清晰度切换时新源 seek 后的进度;position 越过它才认定纹理已有画面。
|
||||
Duration? _confirmBasePosition;
|
||||
/// 画中画还原等场景的首帧确认下限时刻:position 可能一拍就过基准,
|
||||
/// 但纹理出帧滞后于进度观测,淡入前强制等待一小段真实解码时间。
|
||||
DateTime? _confirmNotBefore;
|
||||
String? _lastLayerState;
|
||||
|
||||
@override
|
||||
@@ -99,6 +109,13 @@ class _PlayerVideoSurfaceState extends State<PlayerVideoSurface>
|
||||
@override
|
||||
void didUpdateWidget(covariant PlayerVideoSurface oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.resumeSignal != widget.resumeSignal) {
|
||||
_logSlot('pip-resume-reset', widget.controller?.value);
|
||||
_resetForControllerChange();
|
||||
_confirmNotBefore = DateTime.now().add(const Duration(milliseconds: 450));
|
||||
setState(() {});
|
||||
if (oldWidget.controller == widget.controller) return;
|
||||
}
|
||||
if (oldWidget.controller != widget.controller) {
|
||||
_logSlot('controller-change-before', oldWidget.controller?.value);
|
||||
_detachController(oldWidget.controller);
|
||||
@@ -261,6 +278,16 @@ class _PlayerVideoSurfaceState extends State<PlayerVideoSurface>
|
||||
return false;
|
||||
}
|
||||
if (widget.warmFrameAvailable || !widget.waitForPlaybackFrame) return true;
|
||||
// 清晰度切换:新源 seek 完成后 position 立即大于 0,但不代表纹理已有
|
||||
// 画面;等 position 越过切换时刻的值(解码循环已在出帧)再确认,避免闪黑。
|
||||
final base = _confirmBasePosition;
|
||||
if (base != null) {
|
||||
final notBefore = _confirmNotBefore;
|
||||
if (notBefore != null && DateTime.now().isBefore(notBefore)) {
|
||||
return false;
|
||||
}
|
||||
return value.position > base || value.isCompleted;
|
||||
}
|
||||
if (value.position > Duration.zero || value.isCompleted) return true;
|
||||
return _playbackStarted && !value.isPlaying && !value.isBuffering;
|
||||
}
|
||||
@@ -321,6 +348,8 @@ class _PlayerVideoSurfaceState extends State<PlayerVideoSurface>
|
||||
_videoVisible = false;
|
||||
_videoVisibleNotified = false;
|
||||
_lastLayerState = null;
|
||||
// 记录新源切换时刻的进度,供首帧确认判断 position 是否已前进。
|
||||
_confirmBasePosition = widget.controller?.value.position;
|
||||
}
|
||||
|
||||
void _notifyVideoVisible() {
|
||||
|
||||
Reference in new issue
Block a user