From 98aaca286bd7e5b7eedf88cd95bf613606968d60 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 11 Mar 2024 00:02:11 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E7=9B=B4=E6=92=AD=E7=94=BB?= =?UTF-8?q?=E8=B4=A8=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/live/quality.dart | 43 +++++++++++++++++++ lib/pages/live_room/controller.dart | 34 ++++++++++++++- .../live_room/widgets/bottom_control.dart | 25 +++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 lib/models/live/quality.dart diff --git a/lib/models/live/quality.dart b/lib/models/live/quality.dart new file mode 100644 index 000000000..479384162 --- /dev/null +++ b/lib/models/live/quality.dart @@ -0,0 +1,43 @@ +enum LiveQuality { + dolby, + super4K, + origin, + veryHigh, + bluRay, + superHD, + smooth, + flunt, +} + +extension LiveQualityCode on LiveQuality { + static final List _codeList = [ + 30000, + 20000, + 10000, + 400, + 250, + 150, + 80, + ]; + int get code => _codeList[index]; + + static LiveQuality? fromCode(int code) { + final index = _codeList.indexOf(code); + if (index != -1) { + return LiveQuality.values[index]; + } + return null; + } +} + +extension VideoQualityDesc on LiveQuality { + static final List _descList = [ + '杜比', + '4K', + '原画', + '蓝光', + '超清', + '流畅', + ]; + get description => _descList[index]; +} diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index 2bb1cd0a7..a1878c74f 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -1,6 +1,7 @@ import 'package:get/get.dart'; import 'package:pilipala/http/constants.dart'; import 'package:pilipala/http/live.dart'; +import 'package:pilipala/models/live/quality.dart'; import 'package:pilipala/models/live/room_info.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; import '../../models/live/room_info_h5.dart'; @@ -19,10 +20,14 @@ class LiveRoomController extends GetxController { PlPlayerController.getInstance(videoType: 'live'); Rx roomInfoH5 = RoomInfoH5Model().obs; late bool enableCDN; + late int currentQn; + late List> acceptQnList; + RxString currentQnDesc = ''.obs; @override void onInit() { super.onInit(); + currentQn = 10000; roomId = int.parse(Get.parameters['roomid']!); if (Get.arguments != null) { liveItem = Get.arguments['liveItem']; @@ -57,11 +62,26 @@ class LiveRoomController extends GetxController { } Future queryLiveInfo() async { - var res = await LiveHttp.liveRoomInfo(roomId: roomId, qn: 10000); + /// TODO 默认获取预设质量的直播资源 + var res = await LiveHttp.liveRoomInfo(roomId: roomId, qn: currentQn); if (res['status']) { List codec = res['data'].playurlInfo.playurl.stream.first.format.first.codec; CodecItem item = codec.first; + // 以服务端返回的码率为准 + currentQn = item.currentQn!; + List acceptQn = item.acceptQn!; + acceptQnList = acceptQn.map((e) { + return { + 'code': e, + 'desc': LiveQuality.values + .firstWhere((element) => element.code == e) + .description, + }; + }).toList(); + currentQnDesc.value = LiveQuality.values + .firstWhere((element) => element.code == currentQn) + .description; String videoUrl = enableCDN ? VideoUtils.getCdnUrl(item) : (item.urlInfo?.first.host)! + @@ -90,4 +110,16 @@ class LiveRoomController extends GetxController { } return res; } + + // 修改画质 + void changeQn(int qn) async { + if (currentQn == qn) { + return; + } + currentQn = qn; + currentQnDesc.value = LiveQuality.values + .firstWhere((element) => element.code == currentQn) + .description; + await queryLiveInfo(); + } } diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index a00f3d92f..0dcedc2c6 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/models/video/play/url.dart'; import 'package:pilipala/pages/live_room/index.dart'; @@ -113,6 +114,30 @@ class _BottomControlState extends State { ), const SizedBox(width: 4), ], + SizedBox( + width: 30, + child: PopupMenuButton( + padding: EdgeInsets.zero, + onSelected: (value) { + widget.liveRoomCtr!.changeQn(value); + }, + child: Obx( + () => Text( + widget.liveRoomCtr!.currentQnDesc.value, + style: const TextStyle(color: Colors.white, fontSize: 13), + ), + ), + itemBuilder: (BuildContext context) { + return widget.liveRoomCtr!.acceptQnList.map((e) { + return PopupMenuItem( + value: e['code'], + child: Text(e['desc']), + ); + }).toList(); + }, + ), + ), + const SizedBox(width: 10), ComBtn( icon: const Icon( Icons.fullscreen, From da2bbeedffdfd08143a4353a1cf6abd0719d41c0 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 13 Mar 2024 23:12:34 +0800 Subject: [PATCH 2/3] =?UTF-8?q?mod:=20=E9=BB=98=E8=AE=A4=E7=9B=B4=E6=92=AD?= =?UTF-8?q?=E7=94=BB=E8=B4=A8=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/live/quality.dart | 2 +- lib/pages/live_room/controller.dart | 4 +- .../live_room/widgets/bottom_control.dart | 50 +++++++++---------- lib/pages/setting/play_setting.dart | 36 +++++++++++-- lib/utils/storage.dart | 1 + 5 files changed, 62 insertions(+), 31 deletions(-) diff --git a/lib/models/live/quality.dart b/lib/models/live/quality.dart index 479384162..677d615b4 100644 --- a/lib/models/live/quality.dart +++ b/lib/models/live/quality.dart @@ -2,7 +2,6 @@ enum LiveQuality { dolby, super4K, origin, - veryHigh, bluRay, superHD, smooth, @@ -37,6 +36,7 @@ extension VideoQualityDesc on LiveQuality { '原画', '蓝光', '超清', + '高清', '流畅', ]; get description => _descList[index]; diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index a1878c74f..f785da635 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -27,7 +27,8 @@ class LiveRoomController extends GetxController { @override void onInit() { super.onInit(); - currentQn = 10000; + currentQn = setting.get(SettingBoxKey.defaultLiveQa, + defaultValue: LiveQuality.values.last.code); roomId = int.parse(Get.parameters['roomid']!); if (Get.arguments != null) { liveItem = Get.arguments['liveItem']; @@ -62,7 +63,6 @@ class LiveRoomController extends GetxController { } Future queryLiveInfo() async { - /// TODO 默认获取预设质量的直播资源 var res = await LiveHttp.liveRoomInfo(roomId: roomId, qn: currentQn); if (res['status']) { List codec = diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index 0dcedc2c6..c98a80ae0 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -85,6 +85,30 @@ class _BottomControlState extends State { // ), // ), // const SizedBox(width: 4), + SizedBox( + width: 30, + child: PopupMenuButton( + padding: EdgeInsets.zero, + onSelected: (value) { + widget.liveRoomCtr!.changeQn(value); + }, + child: Obx( + () => Text( + widget.liveRoomCtr!.currentQnDesc.value, + style: const TextStyle(color: Colors.white, fontSize: 13), + ), + ), + itemBuilder: (BuildContext context) { + return widget.liveRoomCtr!.acceptQnList.map((e) { + return PopupMenuItem( + value: e['code'], + child: Text(e['desc']), + ); + }).toList(); + }, + ), + ), + const SizedBox(width: 10), if (Platform.isAndroid) ...[ SizedBox( width: 34, @@ -112,32 +136,8 @@ class _BottomControlState extends State { ), ), ), - const SizedBox(width: 4), + const SizedBox(width: 10), ], - SizedBox( - width: 30, - child: PopupMenuButton( - padding: EdgeInsets.zero, - onSelected: (value) { - widget.liveRoomCtr!.changeQn(value); - }, - child: Obx( - () => Text( - widget.liveRoomCtr!.currentQnDesc.value, - style: const TextStyle(color: Colors.white, fontSize: 13), - ), - ), - itemBuilder: (BuildContext context) { - return widget.liveRoomCtr!.acceptQnList.map((e) { - return PopupMenuItem( - value: e['code'], - child: Text(e['desc']), - ); - }).toList(); - }, - ), - ), - const SizedBox(width: 10), ComBtn( icon: const Icon( Icons.fullscreen, diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index bfd5db5fc..03e912121 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -9,6 +9,7 @@ import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/services/service_locator.dart'; import 'package:pilipala/utils/storage.dart'; +import '../../models/live/quality.dart'; import 'widgets/switch_item.dart'; class PlaySetting extends StatefulWidget { @@ -21,6 +22,7 @@ class PlaySetting extends StatefulWidget { class _PlaySettingState extends State { Box setting = GStrorage.setting; late dynamic defaultVideoQa; + late dynamic defaultLiveQa; late dynamic defaultAudioQa; late dynamic defaultDecode; late int defaultFullScreenMode; @@ -31,6 +33,8 @@ class _PlaySettingState extends State { super.initState(); defaultVideoQa = setting.get(SettingBoxKey.defaultVideoQa, defaultValue: VideoQuality.values.last.code); + defaultLiveQa = setting.get(SettingBoxKey.defaultLiveQa, + defaultValue: LiveQuality.values.last.code); defaultAudioQa = setting.get(SettingBoxKey.defaultAudioQa, defaultValue: AudioQuality.values.last.code); defaultDecode = setting.get(SettingBoxKey.defaultDecode, @@ -148,9 +152,9 @@ class _PlaySettingState extends State { ), ListTile( dense: false, - title: Text('默认画质', style: titleStyle), + title: Text('默认视频画质', style: titleStyle), subtitle: Text( - '当前画质${VideoQualityCode.fromCode(defaultVideoQa)!.description!}', + '当前默认画质${VideoQualityCode.fromCode(defaultVideoQa)!.description!}', style: subTitleStyle, ), onTap: () async { @@ -158,7 +162,7 @@ class _PlaySettingState extends State { context: context, builder: (context) { return SelectDialog( - title: '默认画质', + title: '默认视频画质', value: defaultVideoQa, values: VideoQuality.values.reversed.map((e) { return {'title': e.description, 'value': e.code}; @@ -172,6 +176,32 @@ class _PlaySettingState extends State { } }, ), + ListTile( + dense: false, + title: Text('默认直播画质', style: titleStyle), + subtitle: Text( + '当前默认画质${LiveQualityCode.fromCode(defaultLiveQa)!.description!}', + style: subTitleStyle, + ), + onTap: () async { + int? result = await showDialog( + context: context, + builder: (context) { + return SelectDialog( + title: '默认直播画质', + value: defaultLiveQa, + values: LiveQuality.values.reversed.map((e) { + return {'title': e.description, 'value': e.code}; + }).toList()); + }, + ); + if (result != null) { + defaultLiveQa = result; + setting.put(SettingBoxKey.defaultLiveQa, result); + setState(() {}); + } + }, + ), ListTile( dense: false, title: Text('默认音质', style: titleStyle), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 16cef4639..47fd75968 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -77,6 +77,7 @@ class SettingBoxKey { autoUpgradeEnable = 'autoUpgradeEnable', feedBackEnable = 'feedBackEnable', defaultVideoQa = 'defaultVideoQa', + defaultLiveQa = 'defaultLiveQa', defaultAudioQa = 'defaultAudioQa', autoPlayEnable = 'autoPlayEnable', fullScreenMode = 'fullScreenMode', From 33d28f51d1819f9f28451bf315a0ad8ee16188ad Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Mar 2024 00:36:00 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E6=9C=AA=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=88=87=E6=8D=A2=E7=9B=B4=E6=92=AD=E7=94=BB?= =?UTF-8?q?=E8=B4=A8=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/live_room/controller.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index f785da635..5c2a9800d 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -1,3 +1,4 @@ +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/http/constants.dart'; import 'package:pilipala/http/live.dart'; @@ -21,6 +22,7 @@ class LiveRoomController extends GetxController { Rx roomInfoH5 = RoomInfoH5Model().obs; late bool enableCDN; late int currentQn; + int? tempCurrentQn; late List> acceptQnList; RxString currentQnDesc = ''.obs; @@ -70,6 +72,9 @@ class LiveRoomController extends GetxController { CodecItem item = codec.first; // 以服务端返回的码率为准 currentQn = item.currentQn!; + if (tempCurrentQn != null && tempCurrentQn == currentQn) { + SmartDialog.showToast('画质切换失败,请检查登录状态'); + } List acceptQn = item.acceptQn!; acceptQnList = acceptQn.map((e) { return { @@ -113,6 +118,7 @@ class LiveRoomController extends GetxController { // 修改画质 void changeQn(int qn) async { + tempCurrentQn = currentQn; if (currentQn == qn) { return; }