mod: 视频单例模式
This commit is contained in:
@ -14,7 +14,7 @@ class LiveRoomController extends GetxController {
|
||||
// 静音状态
|
||||
RxBool volumeOff = false.obs;
|
||||
PlPlayerController plPlayerController =
|
||||
PlPlayerController(controlsEnabled: false);
|
||||
PlPlayerController.getInstance(controlsEnabled: false);
|
||||
|
||||
// MeeduPlayerController meeduPlayerController = MeeduPlayerController(
|
||||
// colorTheme: Theme.of(Get.context!).colorScheme.primary,
|
||||
|
@ -54,7 +54,7 @@ class VideoDetailController extends GetxController
|
||||
RxString bgCover = ''.obs;
|
||||
Box user = GStrorage.user;
|
||||
Box localCache = GStrorage.localCache;
|
||||
PlPlayerController plPlayerController = PlPlayerController();
|
||||
PlPlayerController plPlayerController = PlPlayerController.getInstance();
|
||||
// 是否开始自动播放 存在多p的情况下,第二p需要为true
|
||||
RxBool autoPlay = true.obs;
|
||||
// 视频资源是否有效
|
||||
@ -62,6 +62,11 @@ class VideoDetailController extends GetxController
|
||||
// 封面图的展示
|
||||
RxBool isShowCover = true.obs;
|
||||
|
||||
late VideoItem firstVideo;
|
||||
late String videoUrl;
|
||||
late String audioUrl;
|
||||
late Duration defaultST;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
@ -107,7 +112,7 @@ class VideoDetailController extends GetxController
|
||||
/// 更新画质、音质
|
||||
/// TODO 继续进度播放
|
||||
updatePlayer() {
|
||||
Duration position = plPlayerController.position.value;
|
||||
defaultST = plPlayerController.position.value;
|
||||
plPlayerController.removeListeners();
|
||||
plPlayerController.isBuffering.value = false;
|
||||
plPlayerController.buffered.value = Duration.zero;
|
||||
@ -115,24 +120,23 @@ class VideoDetailController extends GetxController
|
||||
/// 暂不匹配解码规则
|
||||
|
||||
/// 根据currentVideoQa 重新设置videoUrl
|
||||
VideoItem firstVideo =
|
||||
firstVideo =
|
||||
data.dash!.video!.firstWhere((i) => i.id == currentVideoQa.code);
|
||||
// String videoUrl = firstVideo.baseUrl!;
|
||||
videoUrl = firstVideo.baseUrl!;
|
||||
|
||||
/// 根据currentAudioQa 重新设置audioUrl
|
||||
AudioItem firstAudio =
|
||||
data.dash!.audio!.firstWhere((i) => i.id == currentAudioQa.code);
|
||||
String audioUrl = firstAudio.baseUrl ?? '';
|
||||
audioUrl = firstAudio.baseUrl ?? '';
|
||||
|
||||
playerInit(firstVideo, audioUrl, defaultST: position);
|
||||
playerInit();
|
||||
}
|
||||
|
||||
Future playerInit(firstVideo, audioSource,
|
||||
{Duration defaultST = Duration.zero, int duration = 0}) async {
|
||||
Future playerInit({video, audio, seekToTime, duration}) async {
|
||||
await plPlayerController.setDataSource(
|
||||
DataSource(
|
||||
videoSource: firstVideo.baseUrl,
|
||||
audioSource: audioSource,
|
||||
videoSource: video ?? videoUrl,
|
||||
audioSource: audio ?? audioUrl,
|
||||
type: DataSourceType.network,
|
||||
httpHeaders: {
|
||||
'user-agent':
|
||||
@ -143,11 +147,14 @@ class VideoDetailController extends GetxController
|
||||
// 硬解
|
||||
enableHA: true,
|
||||
autoplay: autoPlay.value,
|
||||
seekTo: defaultST,
|
||||
duration: Duration(milliseconds: duration),
|
||||
seekTo: seekToTime ?? defaultST,
|
||||
duration: duration ?? Duration(milliseconds: data.timeLength ?? 0),
|
||||
// 宽>高 水平 否则 垂直
|
||||
direction:
|
||||
firstVideo.width - firstVideo.height > 0 ? 'horizontal' : 'vertical',
|
||||
direction: (firstVideo.width! - firstVideo.height!) > 0
|
||||
? 'horizontal'
|
||||
: 'vertical',
|
||||
// 默认1倍速
|
||||
speed: 1.0,
|
||||
);
|
||||
}
|
||||
|
||||
@ -163,25 +170,21 @@ class VideoDetailController extends GetxController
|
||||
data = result['data'];
|
||||
|
||||
/// 优先顺序 省流模式 -> 设置中指定质量 -> 当前可选的最高质量
|
||||
VideoItem firstVideo = data.dash!.video!.first;
|
||||
// String videoUrl = firstVideo.baseUrl!;
|
||||
firstVideo = data.dash!.video!.first;
|
||||
videoUrl = firstVideo.baseUrl!;
|
||||
//
|
||||
currentVideoQa = VideoQualityCode.fromCode(firstVideo.id!)!;
|
||||
|
||||
/// 优先顺序 设置中指定质量 -> 当前可选的最高质量
|
||||
AudioItem firstAudio =
|
||||
data.dash!.audio!.isNotEmpty ? data.dash!.audio!.first : AudioItem();
|
||||
String audioUrl = firstAudio.baseUrl ?? '';
|
||||
audioUrl = firstAudio.baseUrl ?? '';
|
||||
//
|
||||
if (firstAudio.id != null) {
|
||||
currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!;
|
||||
}
|
||||
await playerInit(
|
||||
firstVideo,
|
||||
audioUrl,
|
||||
defaultST: Duration(milliseconds: data.lastPlayTime!),
|
||||
duration: data.timeLength ?? 0,
|
||||
);
|
||||
defaultST = Duration(milliseconds: data.lastPlayTime!);
|
||||
await playerInit();
|
||||
} else {
|
||||
SmartDialog.showToast(result['msg'].toString());
|
||||
}
|
||||
|
@ -49,8 +49,25 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
void initState() {
|
||||
super.initState();
|
||||
plPlayerController = videoDetailController.plPlayerController;
|
||||
playerListener();
|
||||
|
||||
appbarStream = StreamController<double>();
|
||||
|
||||
_extendNestCtr.addListener(
|
||||
() {
|
||||
double offset = _extendNestCtr.position.pixels;
|
||||
appbarStream.add(offset);
|
||||
},
|
||||
);
|
||||
|
||||
statusBarHeight = localCache.get('statusBarHeight');
|
||||
_futureBuilderFuture = videoDetailController.queryVideoUrl();
|
||||
}
|
||||
|
||||
// 播放器状态监听
|
||||
void playerListener() {
|
||||
plPlayerController!.onPlayerStatusChanged.listen(
|
||||
(PlayerStatus status) {
|
||||
(PlayerStatus status) async {
|
||||
videoDetailController.markHeartBeat();
|
||||
playerStatus = status;
|
||||
if (status == PlayerStatus.playing) {
|
||||
@ -68,18 +85,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
appbarStream = StreamController<double>();
|
||||
|
||||
_extendNestCtr.addListener(
|
||||
() {
|
||||
double offset = _extendNestCtr.position.pixels;
|
||||
appbarStream.add(offset);
|
||||
},
|
||||
);
|
||||
|
||||
statusBarHeight = localCache.get('statusBarHeight');
|
||||
_futureBuilderFuture = videoDetailController.queryVideoUrl();
|
||||
}
|
||||
|
||||
// 继续播放或重新播放
|
||||
@ -104,6 +109,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
if (videoDetailController.timer!.isActive) {
|
||||
videoDetailController.timer!.cancel();
|
||||
}
|
||||
videoDetailController.defaultST = plPlayerController!.position.value;
|
||||
plPlayerController!.pause();
|
||||
super.didPushNext();
|
||||
}
|
||||
@ -111,6 +117,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
@override
|
||||
// 返回当前页面时
|
||||
void didPopNext() async {
|
||||
videoDetailController.playerInit();
|
||||
if (_extendNestCtr.position.pixels == 0) {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
plPlayerController!.play();
|
||||
|
@ -2,7 +2,6 @@ import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
@ -13,7 +12,7 @@ import 'package:pilipala/utils/storage.dart';
|
||||
import 'package:screen_brightness/screen_brightness.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
import 'package:volume_controller/volume_controller.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
// import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
|
||||
import 'models/data_status.dart';
|
||||
import 'models/play_speed.dart';
|
||||
@ -25,6 +24,9 @@ class PlPlayerController {
|
||||
Player? _videoPlayerController;
|
||||
VideoController? _videoController;
|
||||
|
||||
// 添加一个私有静态变量来保存实例
|
||||
static PlPlayerController? _instance;
|
||||
|
||||
// 流事件 监听播放状态变化
|
||||
StreamSubscription? _playerEventSubs;
|
||||
|
||||
@ -44,6 +46,8 @@ class PlPlayerController {
|
||||
final Rx<Duration> _duration = Rx(Duration.zero);
|
||||
final Rx<Duration> _buffered = Rx(Duration.zero);
|
||||
|
||||
final Rx<int> _playerCount = Rx(0);
|
||||
|
||||
final Rx<double> _playbackSpeed = 1.0.obs;
|
||||
final Rx<double> _currentVolume = 1.0.obs;
|
||||
final Rx<double> _currentBrightness = 0.0.obs;
|
||||
@ -172,10 +176,24 @@ class PlPlayerController {
|
||||
/// 全屏方向
|
||||
Rx<String> get direction => _direction;
|
||||
|
||||
PlPlayerController({
|
||||
// 直播间 传false 关闭控制栏
|
||||
this.controlsEnabled = true,
|
||||
this.fits = const [
|
||||
Rx<int> get playerCount => _playerCount;
|
||||
|
||||
// 添加一个私有构造函数
|
||||
PlPlayerController._() {
|
||||
controlsEnabled = controlsEnabled;
|
||||
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
|
||||
// if (status == PlayerStatus.playing) {
|
||||
// WakelockPlus.enable();
|
||||
// } else {
|
||||
// WakelockPlus.disable();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
// 获取实例 传参
|
||||
static PlPlayerController getInstance({
|
||||
bool controlsEnabled = true,
|
||||
List<BoxFit> fits = const [
|
||||
BoxFit.contain,
|
||||
BoxFit.cover,
|
||||
BoxFit.fill,
|
||||
@ -184,14 +202,10 @@ class PlPlayerController {
|
||||
BoxFit.scaleDown
|
||||
],
|
||||
}) {
|
||||
controlsEnabled = controlsEnabled;
|
||||
_playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
|
||||
if (status == PlayerStatus.playing) {
|
||||
WakelockPlus.enable();
|
||||
} else {
|
||||
WakelockPlus.enable();
|
||||
}
|
||||
});
|
||||
// 如果实例尚未创建,则创建一个新实例
|
||||
_instance ??= PlPlayerController._();
|
||||
_instance!._playerCount.value += 1;
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
// 初始化资源
|
||||
@ -258,6 +272,9 @@ class PlPlayerController {
|
||||
double? width,
|
||||
double? height,
|
||||
) async {
|
||||
// 每次配置时先移除监听
|
||||
removeListeners();
|
||||
|
||||
Player player = _videoPlayerController ??
|
||||
Player(
|
||||
configuration: const PlayerConfiguration(
|
||||
@ -663,6 +680,12 @@ class PlPlayerController {
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
// 每次减1,最后销毁
|
||||
_playerCount.value -= 1;
|
||||
if (playerCount.value > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_timer?.cancel();
|
||||
_timerForVolume?.cancel();
|
||||
_timerForGettingVolume?.cancel();
|
||||
@ -685,5 +708,6 @@ class PlPlayerController {
|
||||
removeListeners();
|
||||
await _videoPlayerController?.dispose();
|
||||
_videoPlayerController = null;
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user