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