Merge branch 'main' into feature-media_kit

This commit is contained in:
guozhigq
2024-05-12 00:54:24 +08:00
137 changed files with 4899 additions and 3301 deletions

View File

@ -335,8 +335,10 @@ class PlPlayerController {
}) {
// 如果实例尚未创建,则创建一个新实例
_instance ??= PlPlayerController._();
_instance!._playerCount.value += 1;
_videoType.value = videoType;
if (videoType != 'none') {
_instance!._playerCount.value += 1;
_videoType.value = videoType;
}
return _instance!;
}
@ -351,7 +353,7 @@ class PlPlayerController {
// 初始化播放速度
double speed = 1.0,
// 硬件加速
bool enableHA = true,
bool enableHA = false,
double? width,
double? height,
Duration? duration,
@ -393,13 +395,7 @@ class PlPlayerController {
}
// 配置Player 音轨、字幕等等
_videoPlayerController = await _createVideoController(
dataSource,
_looping,
enableHA,
width,
height,
seekTo,
);
dataSource, _looping, enableHA, width, height, seekTo);
// 获取视频时长 00:00
_duration.value = duration ?? _videoPlayerController!.state.duration;
updateDurationSecond();
@ -430,7 +426,7 @@ class PlPlayerController {
bool enableHA,
double? width,
double? height,
Duration? seekTo,
Duration seekTo,
) async {
// 每次配置时先移除监听
removeListeners();
@ -480,17 +476,17 @@ class PlPlayerController {
}
// 字幕
if (dataSource.subFiles != '' && dataSource.subFiles != null) {
await pp.setProperty(
'sub-files',
UniversalPlatform.isWindows
? dataSource.subFiles!.replaceAll(';', '\\;')
: dataSource.subFiles!.replaceAll(':', '\\:'),
);
await pp.setProperty("subs-with-matching-audio", "no");
await pp.setProperty("sub-forced-only", "yes");
await pp.setProperty("blend-subtitles", "video");
}
// if (dataSource.subFiles != '' && dataSource.subFiles != null) {
// await pp.setProperty(
// 'sub-files',
// UniversalPlatform.isWindows
// ? dataSource.subFiles!.replaceAll(';', '\\;')
// : dataSource.subFiles!.replaceAll(':', '\\:'),
// );
// await pp.setProperty("subs-with-matching-audio", "no");
// await pp.setProperty("sub-forced-only", "yes");
// await pp.setProperty("blend-subtitles", "video");
// }
_videoController = _videoController ??
VideoController(
@ -512,12 +508,9 @@ class PlPlayerController {
play: false,
);
}
player.open(
Media(
dataSource.videoSource!,
httpHeaders: dataSource.httpHeaders,
start: seekTo ?? Duration.zero,
),
await player.open(
Media(dataSource.videoSource!,
httpHeaders: dataSource.httpHeaders, start: seekTo),
play: false,
);
// 音轨
@ -532,7 +525,22 @@ class PlPlayerController {
Future _initializePlayer({
Duration? duration,
}) async {
// 设置倍速
getVideoFit();
// if (_looping) {
// await setLooping(_looping);
// }
/// 跳转播放
// if (seekTo != Duration.zero) {
// await this.seekTo(seekTo);
// }
/// 自动播放
if (_autoPlay) {
await play(duration: duration);
}
/// 设置倍速
if (videoType.value == 'live') {
await setPlaybackSpeed(1.0);
} else {
@ -542,15 +550,6 @@ class PlPlayerController {
await setPlaybackSpeed(1.0);
}
}
getVideoFit();
// if (_looping) {
// await setLooping(_looping);
// }
// 自动播放
if (_autoPlay) {
await play(duration: duration);
}
}
List<StreamSubscription> subscriptions = [];
@ -608,7 +607,9 @@ class PlPlayerController {
makeHeartBeat(event.inSeconds);
}),
videoPlayerController!.stream.duration.listen((event) {
duration.value = event;
if (event > Duration.zero) {
duration.value = event;
}
}),
videoPlayerController!.stream.buffer.listen((event) {
_buffered.value = event;
@ -651,36 +652,38 @@ class PlPlayerController {
/// 跳转至指定位置
Future<void> seekTo(Duration position, {type = 'seek'}) async {
// if (position >= duration.value) {
// position = duration.value - const Duration(milliseconds: 100);
// }
if (position < Duration.zero) {
position = Duration.zero;
}
_position.value = position;
updatePositionSecond();
_heartDuration = position.inSeconds;
if (duration.value.inSeconds != 0) {
if (type != 'slider') {
/// 拖动进度条调节时,不等待第一帧,防止抖动
await _videoPlayerController?.stream.buffer.first;
try {
if (position < Duration.zero) {
position = Duration.zero;
}
await _videoPlayerController?.seek(position);
} else {
print('seek duration else');
_timerForSeek?.cancel();
_timerForSeek =
Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
if (duration.value.inSeconds != 0) {
await _videoPlayerController!.stream.buffer.first;
await _videoPlayerController?.seek(position);
t.cancel();
_timerForSeek = null;
_position.value = position;
updatePositionSecond();
_heartDuration = position.inSeconds;
if (duration.value.inSeconds != 0) {
if (type != 'slider') {
await _videoPlayerController?.stream.buffer.first;
}
});
await _videoPlayerController?.seek(position);
} else {
_timerForSeek?.cancel();
_timerForSeek ??= _startSeekTimer(position);
}
} catch (err) {
print('Error while seeking: $err');
}
}
Timer? _startSeekTimer(Duration position) {
return Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
if (duration.value.inSeconds != 0) {
await _videoPlayerController!.stream.buffer.first;
await _videoPlayerController?.seek(position);
t.cancel();
_timerForSeek = null;
}
});
}
/// 设置倍速
Future<void> setPlaybackSpeed(double speed) async {
/// TODO _duration.value丢失
@ -717,11 +720,10 @@ class PlPlayerController {
await seekTo(Duration.zero);
}
await _videoPlayerController?.play();
playerStatus.status.value = PlayerStatus.playing;
await getCurrentVolume();
await getCurrentBrightness();
playerStatus.status.value = PlayerStatus.playing;
// screenManager.setOverlays(false);
/// 临时fix _duration.value丢失
@ -975,41 +977,8 @@ class PlPlayerController {
} else {
await landScape();
}
// bool isValid =
// direction.value == 'vertical' || mode == FullScreenMode.vertical
// ? true
// : false;
// var result = await showDialog(
// context: Get.context!,
// useSafeArea: false,
// builder: (context) => Dialog.fullscreen(
// backgroundColor: Colors.black,
// child: SafeArea(
// // 忽略手机安全区域
// top: isValid,
// left: false,
// right: false,
// bottom: isValid,
// child: PLVideoPlayer(
// controller: this,
// headerControl: headerControl,
// bottomControl: bottomControl,
// danmuWidget: danmuWidget,
// ),
// ),
// ),
// );
// if (result == null) {
// // 退出全屏
// StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE);
// exitFullScreen();
// await verticalScreen();
// toggleFullScreen(false);
// }
} else if (isFullScreen.value) {
} else if (isFullScreen.value && !status) {
StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE);
// Get.back();
exitFullScreen();
await verticalScreen();
toggleFullScreen(false);
@ -1121,9 +1090,6 @@ class PlPlayerController {
}
Future<void> dispose({String type = 'single'}) async {
print('dispose');
print('dispose: ${playerCount.value}');
// 每次减1最后销毁
if (type == 'single' && playerCount.value > 1) {
_playerCount.value -= 1;
@ -1133,7 +1099,6 @@ class PlPlayerController {
}
_playerCount.value = 0;
try {
print('dispose dispose ---------');
_timer?.cancel();
_timerForVolume?.cancel();
_timerForGettingVolume?.cancel();

View File

@ -4,6 +4,7 @@ enum BottomControlType {
next,
time,
space,
episode,
fit,
speed,
fullscreen,

View File

@ -37,6 +37,7 @@ class PLVideoPlayer extends StatefulWidget {
this.bottomList,
this.customWidget,
this.customWidgets,
this.showEposideCb,
super.key,
});
@ -49,6 +50,7 @@ class PLVideoPlayer extends StatefulWidget {
final Widget? customWidget;
final List<Widget>? customWidgets;
final Function? showEposideCb;
@override
State<PLVideoPlayer> createState() => _PLVideoPlayerState();
@ -214,8 +216,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 上一集
BottomControlType.pre: ComBtn(
icon: const Icon(
Icons.skip_previous_outlined,
size: 15,
Icons.skip_previous_rounded,
size: 21,
color: Colors.white,
),
fuc: () {},
@ -229,8 +231,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 下一集
BottomControlType.next: ComBtn(
icon: const Icon(
Icons.last_page_outlined,
size: 15,
Icons.skip_next_rounded,
size: 21,
color: Colors.white,
),
fuc: () {},
@ -239,6 +241,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 时间进度
BottomControlType.time: Row(
children: [
const SizedBox(width: 8),
Obx(() {
return Text(
_.durationSeconds.value >= 3600
@ -266,6 +269,24 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 空白占位
BottomControlType.space: const Spacer(),
/// 选集
BottomControlType.episode: SizedBox(
height: 30,
width: 30,
child: TextButton(
onPressed: () {
widget.showEposideCb?.call();
},
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero),
),
child: const Text(
'选集',
style: TextStyle(color: Colors.white, fontSize: 13),
),
),
),
/// 画面比例
BottomControlType.fit: SizedBox(
height: 30,
@ -313,7 +334,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
color: Colors.white,
),
),
fuc: () => _.triggerFullScreen(),
fuc: () => _.triggerFullScreen(status: !_.isFullScreen.value),
),
};
final List<Widget> list = [];

View File

@ -68,91 +68,8 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget {
);
},
),
Row(
children: [...buildBottomControl!],
),
// Row(
// children: [
// PlayOrPauseButton(
// controller: _,
// ),
// const SizedBox(width: 4),
// // 播放时间
// Obx(() {
// return Text(
// _.durationSeconds.value >= 3600
// ? printDurationWithHours(
// Duration(seconds: _.positionSeconds.value))
// : printDuration(
// Duration(seconds: _.positionSeconds.value)),
// style: textStyle,
// );
// }),
// const SizedBox(width: 2),
// const Text('/', style: textStyle),
// const SizedBox(width: 2),
// Obx(
// () => Text(
// _.durationSeconds.value >= 3600
// ? printDurationWithHours(
// Duration(seconds: _.durationSeconds.value))
// : printDuration(
// Duration(seconds: _.durationSeconds.value)),
// style: textStyle,
// ),
// ),
// const Spacer(),
// // 倍速
// // Obx(
// // () => SizedBox(
// // width: 45,
// // height: 34,
// // child: TextButton(
// // style: ButtonStyle(
// // padding: MaterialStateProperty.all(EdgeInsets.zero),
// // ),
// // onPressed: () {
// // _.togglePlaybackSpeed();
// // },
// // child: Text(
// // '${_.playbackSpeed.toString()}X',
// // style: textStyle,
// // ),
// // ),
// // ),
// // ),
// SizedBox(
// height: 30,
// child: TextButton(
// onPressed: () => _.toggleVideoFit(),
// style: ButtonStyle(
// padding: MaterialStateProperty.all(EdgeInsets.zero),
// ),
// child: Obx(
// () => Text(
// _.videoFitDEsc.value,
// style: const TextStyle(color: Colors.white, fontSize: 13),
// ),
// ),
// ),
// ),
// const SizedBox(width: 10),
// // 全屏
// Obx(
// () => ComBtn(
// icon: Icon(
// _.isFullScreen.value
// ? FontAwesomeIcons.compress
// : FontAwesomeIcons.expand,
// size: 15,
// color: Colors.white,
// ),
// fuc: () => triggerFullScreen!(),
// ),
// ),
// ],
// ),
const SizedBox(height: 12),
Row(children: [...buildBottomControl!]),
const SizedBox(height: 10),
],
),
);