feat: 倍速、画质、音质调节

This commit is contained in:
guozhigq
2023-07-31 23:20:49 +08:00
parent e892452bcd
commit b947397333
11 changed files with 818 additions and 177 deletions

View File

@ -7,6 +7,7 @@ import 'package:hive/hive.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:pilipala/plugin/pl_player/models/data_source.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:screen_brightness/screen_brightness.dart';
import 'package:universal_platform/universal_platform.dart';
@ -14,6 +15,7 @@ import 'package:volume_controller/volume_controller.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'models/data_status.dart';
import 'models/play_speed.dart';
import 'models/play_status.dart';
Box videoStorage = GStrorage.video;
@ -177,7 +179,7 @@ class PlPlayerController {
DataSource dataSource, {
bool autoplay = true,
// 默认不循环
PlaylistMode looping = PlaylistMode.single,
PlaylistMode looping = PlaylistMode.none,
// 初始化播放位置
Duration seekTo = Duration.zero,
// 初始化播放速度
@ -195,6 +197,7 @@ class PlPlayerController {
_duration.value = duration ?? Duration.zero;
// 初始化视频倍速
_playbackSpeed.value = speed;
// 初始化数据加载状态
dataStatus.status.value = DataStatus.loading;
if (_videoPlayerController != null &&
@ -202,10 +205,12 @@ class PlPlayerController {
await pause(notify: false);
}
// 配置Player 音轨、字幕等等
_videoPlayerController = await _createVideoController(
dataSource, _looping, enableHA, width, height);
// 获取视频时长 00:00
_duration.value = _videoPlayerController!.state.duration;
// 数据加载完成
dataStatus.status.value = DataStatus.loaded;
await _initializePlayer(seekTo: seekTo);
@ -382,6 +387,8 @@ class PlPlayerController {
position = Duration.zero;
}
_position.value = position;
print('seek 🌹duration : ${duration.value.inSeconds}');
if (duration.value.inSeconds != 0) {
// await _videoPlayerController!.stream.buffer.first;
await _videoPlayerController?.seek(position);
@ -389,11 +396,13 @@ class PlPlayerController {
// play();
// }
} else {
print('🌹🌹');
_timerForSeek?.cancel();
_timerForSeek =
Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
//_timerForSeek = null;
if (duration.value.inSeconds != 0) {
print('🌹🌹🌹');
await _videoPlayerController?.seek(position);
// if (playerStatus.stopped) {
// play();
@ -413,11 +422,11 @@ class PlPlayerController {
/// 设置倍速
Future<void> togglePlaybackSpeed() async {
List<double> allowedSpeeds = [0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75, 2.0];
if (allowedSpeeds.indexOf(_playbackSpeed.value) <
allowedSpeeds.length - 1) {
setPlaybackSpeed(
allowedSpeeds[allowedSpeeds.indexOf(_playbackSpeed.value) + 1]);
List<double> allowedSpeeds =
PlaySpeed.values.map<double>((e) => e.value).toList();
int index = allowedSpeeds.indexOf(_playbackSpeed.value);
if (index < allowedSpeeds.length - 1) {
setPlaybackSpeed(allowedSpeeds[index + 1]);
} else {
setPlaybackSpeed(allowedSpeeds[0]);
}
@ -451,6 +460,7 @@ class PlPlayerController {
/// 更改播放状态
Future<void> togglePlay() async {
feedBack();
if (playerStatus.playing) {
pause();
} else {
@ -474,6 +484,7 @@ class PlPlayerController {
}
void onChangedSliderStart() {
feedBack();
_isSliderMoving = true;
}
@ -600,6 +611,7 @@ class PlPlayerController {
/// 关闭控制栏
void onCloseControl(bool val) {
feedBack();
_controlsClose.value = val;
showControls.value = !val;
}

View File

@ -5,3 +5,5 @@ export './view.dart';
export './models/data_source.dart';
export './models/play_status.dart';
export './models/data_status.dart';
export './widgets/common_btn.dart';
export './models/play_speed.dart';

View File

@ -0,0 +1,37 @@
enum PlaySpeed {
pointTwoFive,
pointFive,
pointSevenFive,
one,
onePointTwoFive,
onePointFive,
onePointSevenFive,
two
}
extension PlaySpeedExtension on PlaySpeed {
static final List<String> _descList = [
'0.25倍',
'0.5倍',
'0.75倍',
'正常速度',
'1.25倍',
'1.5倍',
'1.75倍',
'2.0倍',
];
get description => _descList[index];
static final List<double> _valueList = [
0.25,
0.5,
0.75,
1.0,
1.25,
1.5,
1.75,
2.0
];
get value => _valueList[index];
get defaultValue => _valueList[3];
}

View File

@ -10,12 +10,18 @@ import 'package:pilipala/utils/feed_back.dart';
import 'widgets/bottom_control.dart';
import 'widgets/common_btn.dart';
import 'widgets/header_control.dart';
class PLVideoPlayer extends StatefulWidget {
final PlPlayerController controller;
final PreferredSizeWidget? headerControl;
final Widget? danmuWidget;
const PLVideoPlayer({required this.controller, super.key});
const PLVideoPlayer({
required this.controller,
this.headerControl,
this.danmuWidget,
super.key,
});
@override
State<PLVideoPlayer> createState() => _PLVideoPlayerState();
@ -97,6 +103,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
onVerticalDragUpdate: (DragUpdateDetails details) {},
onVerticalDragEnd: (DragEndDetails details) {}),
),
// 头部、底部控制条
if (_.controlsEnabled)
Obx(
() => Column(
@ -107,7 +114,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
controller: animationController,
visible: !_.controlsClose.value && _.showControls.value,
position: 'top',
child: HeaderControl(controller: widget.controller),
child: widget.headerControl!,
),
),
const Spacer(),
@ -166,7 +173,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// print(details);
// },
onSeek: (duration) {
print(duration);
feedBack();
_.onChangedSlider(duration.inSeconds.toDouble());
_.seekTo(duration);
},
@ -195,27 +202,28 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
),
),
// 锁
Obx(
() => Align(
alignment: Alignment.centerLeft,
child: FractionalTranslation(
translation: const Offset(0.5, 0.0),
child: Visibility(
visible: _.showControls.value,
child: ComBtn(
icon: Icon(
_.controlsClose.value
? FontAwesomeIcons.lock
: FontAwesomeIcons.lockOpen,
size: 15,
color: Colors.white,
if (_.controlsEnabled)
Obx(
() => Align(
alignment: Alignment.centerLeft,
child: FractionalTranslation(
translation: const Offset(0.5, 0.0),
child: Visibility(
visible: _.showControls.value,
child: ComBtn(
icon: Icon(
_.controlsClose.value
? FontAwesomeIcons.lock
: FontAwesomeIcons.lockOpen,
size: 15,
color: Colors.white,
),
fuc: () => _.onCloseControl(!_.controlsClose.value),
),
fuc: () => _.onCloseControl(!_.controlsClose.value),
),
),
),
),
),
//
Obx(() {
if (_.dataStatus.loading || _.isBuffering.value) {

View File

@ -5,7 +5,6 @@ import 'package:get/get.dart';
import 'package:pilipala/plugin/pl_player/index.dart';
import '../utils.dart';
import 'common_btn.dart';
class BottomControl extends StatelessWidget implements PreferredSizeWidget {
final PlPlayerController? controller;
@ -67,21 +66,21 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget {
),
Row(
children: [
Obx(
() => ComBtn(
icon: Icon(
_.playerStatus.paused
? FontAwesomeIcons.play
: _.playerStatus.playing
? FontAwesomeIcons.pause
: FontAwesomeIcons.rotateRight,
size: 15,
color: Colors.white,
),
fuc: () => _.togglePlay(),
),
),
const SizedBox(width: 6),
// Obx(
// () => ComBtn(
// icon: Icon(
// _.playerStatus.paused
// ? FontAwesomeIcons.play
// : _.playerStatus.playing
// ? FontAwesomeIcons.pause
// : FontAwesomeIcons.rotateRight,
// size: 15,
// color: Colors.white,
// ),
// fuc: () => _.togglePlay(),
// ),
// ),
// const SizedBox(width: 6),
// 播放时间
Obx(() {
return Text(
@ -104,33 +103,33 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget {
),
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,
),
),
),
),
ComBtn(
icon: const Icon(
Icons.fit_screen_sharp,
size: 18,
color: Colors.white,
),
fuc: () => _.toggleVideoFit(),
),
const SizedBox(width: 4),
// Obx(
// () => SizedBox(
// width: 45,
// height: 34,
// child: TextButton(
// style: ButtonStyle(
// padding: MaterialStateProperty.all(EdgeInsets.zero),
// ),
// onPressed: () {
// _.togglePlaybackSpeed();
// },
// child: Text(
// '${_.playbackSpeed.toString()}X',
// style: textStyle,
// ),
// ),
// ),
// ),
// ComBtn(
// icon: const Icon(
// Icons.fit_screen_sharp,
// size: 18,
// color: Colors.white,
// ),
// fuc: () => _.toggleVideoFit(),
// ),
// const SizedBox(width: 4),
// 全屏
ComBtn(
icon: const Icon(

View File

@ -1,67 +0,0 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:pilipala/plugin/pl_player/index.dart';
import 'common_btn.dart';
class HeaderControl extends StatelessWidget implements PreferredSizeWidget {
final PlPlayerController? controller;
const HeaderControl({this.controller, Key? key}) : super(key: key);
@override
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
@override
Widget build(BuildContext context) {
final _ = controller!;
return AppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
elevation: 0,
scrolledUnderElevation: 0,
primary: false,
centerTitle: false,
automaticallyImplyLeading: false,
titleSpacing: 14,
title: Row(
children: [
ComBtn(
icon: const Icon(
FontAwesomeIcons.arrowLeft,
size: 15,
color: Colors.white,
),
fuc: () => Get.back(),
),
const SizedBox(width: 4),
ComBtn(
icon: const Icon(
FontAwesomeIcons.house,
size: 15,
color: Colors.white,
),
fuc: () => Get.back(),
),
const Spacer(),
ComBtn(
icon: const Icon(
FontAwesomeIcons.cropSimple,
size: 15,
color: Colors.white,
),
fuc: () => _.screenshot(),
),
const SizedBox(width: 4),
ComBtn(
icon: const Icon(
FontAwesomeIcons.sliders,
size: 15,
color: Colors.white,
),
fuc: () => _.screenshot(),
),
],
),
);
}
}