From c7611e436f05226936853942265a4a04a158e2b1 Mon Sep 17 00:00:00 2001 From: orz12 Date: Sun, 24 Dec 2023 02:48:51 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix/opt:=20=E9=87=8D=E6=9E=84=E5=BC=B9?= =?UTF-8?q?=E5=B9=95=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改用map存储,将同属于100毫秒内的弹幕归入一个元素,无需再排序和二分比较取得,降低时间复杂度与播放时功耗; 分离PlDanmakuController与playerController的功能,避免代码耦合; 精简用于表示状态的变量与相关逻辑,修复播放完毕后因currentSegIndex永久增加而无法再显示弹幕的错误; 为PlDanmakuController添加dispose()。 --- lib/pages/danmaku/controller.dart | 93 ++++++++++++------------------ lib/pages/danmaku/view.dart | 96 ++++++++++--------------------- 2 files changed, 68 insertions(+), 121 deletions(-) diff --git a/lib/pages/danmaku/controller.dart b/lib/pages/danmaku/controller.dart index 38d09e048..0d3f795fd 100644 --- a/lib/pages/danmaku/controller.dart +++ b/lib/pages/danmaku/controller.dart @@ -3,74 +3,57 @@ import 'package:pilipala/models/danmaku/dm.pb.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; class PlDanmakuController { - PlDanmakuController(this.cid, this.playerController); + PlDanmakuController(this.cid); final int cid; - final PlPlayerController playerController; late Duration videoDuration; - // 按 6min 分段 - int segCount = 0; - List dmSegList = []; + Map> dmSegMap = {}; // 已请求的段落标记 - List hasrequestSeg = []; - int currentSegIndex = 1; - int currentDmIndex = 0; + List requestedSeg = []; - void calcSegment() { - dmSegList.clear(); - // 视频分段数 - segCount = (videoDuration.inSeconds / (60 * 6)).ceil(); - dmSegList = List.generate( - segCount < 1 ? 1 : segCount, (index) => DmSegMobileReply()); - // 当前分段 - try { - currentSegIndex = - (playerController.position.value.inSeconds / (60 * 6)).ceil(); - currentSegIndex = currentSegIndex < 1 ? 1 : currentSegIndex; - } catch (_) {} - } + bool get initiated => requestedSeg.isNotEmpty; - Future> queryDanmaku() async { - // dmSegList.clear(); - DmSegMobileReply result = - await DanmakaHttp.queryDanmaku(cid: cid, segmentIndex: currentSegIndex); - if (result.elems.isNotEmpty) { - result.elems.sort((a, b) => (a.progress).compareTo(b.progress)); - // dmSegList.add(result); - currentSegIndex = currentSegIndex < 1 ? 1 : currentSegIndex; - dmSegList[currentSegIndex - 1] = result; - } - if (dmSegList.isNotEmpty) { - findClosestPositionIndex(playerController.position.value.inMilliseconds); + static int SEGMENT_LENGTH = 60 * 6 * 1000; + + void initiate(int progress) { + if (requestedSeg.isEmpty) { + int segCount = (videoDuration.inSeconds / (60 * 6)).ceil(); + requestedSeg = List.generate(segCount, (index) => false); } - return dmSegList; + queryDanmaku( + calcSegment(progress) + ); } - /// 查询当前最接近的弹幕 - void findClosestPositionIndex(int position) { - int segIndex = (position / (6 * 60 * 1000)).ceil() - 1; - if (segIndex < 0) segIndex = 0; - List elems = dmSegList[segIndex].elems; - - if (segIndex < dmSegList.length) { - int left = 0; - int right = elems.length; + void dispose() { + dmSegMap.clear(); + requestedSeg.clear(); + } - while (left < right) { - int mid = (right + left) ~/ 2; - var midPosition = elems[mid].progress; + int calcSegment(int progress) { + return progress ~/ SEGMENT_LENGTH; + } - if (midPosition >= position) { - right = mid; - } else { - left = mid + 1; + void queryDanmaku(int segmentIndex) async { + assert(requestedSeg[segmentIndex] == false); + requestedSeg[segmentIndex] = true; + DmSegMobileReply result = + await DanmakaHttp.queryDanmaku(cid: cid, segmentIndex: segmentIndex + 1); + if (result.elems.isNotEmpty) { + for (var element in result.elems) { + int pos = element.progress ~/ 100;//每0.1秒存储一次 + if (dmSegMap[pos] == null) { + dmSegMap[pos] = []; } + dmSegMap[pos]!.add(element); } + } + } - currentSegIndex = segIndex; - currentDmIndex = right; - } else { - currentSegIndex = segIndex; - currentDmIndex = 0; + List? getCurrentDanmaku(int progress) { + int segmentIndex = calcSegment(progress); + if (!requestedSeg[segmentIndex]) { + queryDanmaku(segmentIndex); } + return dmSegMap[progress ~/ 100]; } } diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index 1ff7677c1..d7030ebfc 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:ns_danmaku/ns_danmaku.dart'; +import 'package:pilipala/models/danmaku/dm.pb.dart'; import 'package:pilipala/pages/danmaku/index.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/utils/danmaku.dart'; @@ -27,7 +28,7 @@ class _PlDanmakuState extends State { late PlPlayerController playerController; late PlDanmakuController _plDanmakuController; DanmakuController? _controller; - bool danmuPlayStatus = true; + // bool danmuPlayStatus = true; Box setting = GStrorage.setting; late bool enableShowDanmaku; late List blockTypes; @@ -35,6 +36,7 @@ class _PlDanmakuState extends State { late double opacityVal; late double fontSizeVal; late double danmakuDurationVal; + int latestAddedPosition = -1; @override void initState() { @@ -42,26 +44,24 @@ class _PlDanmakuState extends State { enableShowDanmaku = setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false); _plDanmakuController = - PlDanmakuController(widget.cid, widget.playerController); + PlDanmakuController(widget.cid); if (mounted) { playerController = widget.playerController; _plDanmakuController.videoDuration = playerController.duration.value; if (enableShowDanmaku || playerController.isOpenDanmu.value) { - _plDanmakuController - ..calcSegment() - ..queryDanmaku(); + _plDanmakuController.initiate( + playerController.position.value.inMilliseconds + ); } playerController ..addStatusLister(playerListener) ..addPositionListener(videoPositionListen); } playerController.isOpenDanmu.listen((p0) { - if (p0) { - if (_plDanmakuController.dmSegList.isEmpty) { - _plDanmakuController - ..calcSegment() - ..queryDanmaku(); - } + if (p0 && !_plDanmakuController.initiated) { + _plDanmakuController.initiate( + playerController.position.value.inMilliseconds + ); } }); blockTypes = playerController.blockTypes; @@ -82,68 +82,32 @@ class _PlDanmakuState extends State { } void videoPositionListen(Duration position) { - if (!danmuPlayStatus) { - _controller!.onResume(); - danmuPlayStatus = true; - } if (!playerController.isOpenDanmu.value) { return; } - PlDanmakuController ctr = _plDanmakuController; int currentPosition = position.inMilliseconds; - blockTypes = playerController.blockTypes; - // 根据position判断是否有已缓存弹幕。没有则请求对应段 - int segIndex = (currentPosition / (6 * 60 * 1000)).ceil(); - segIndex = segIndex < 1 ? 1 : segIndex; - // print('🌹🌹: ${segIndex}'); - // print('🌹🌹: ${ctr.dmSegList.length}'); - // print('🌹🌹: ${ctr.hasrequestSeg.contains(segIndex - 1)}'); - if (segIndex - 1 >= ctr.dmSegList.length || - (ctr.dmSegList[segIndex - 1].elems.isEmpty && - !ctr.hasrequestSeg.contains(segIndex - 1))) { - ctr.hasrequestSeg.add(segIndex - 1); - ctr.currentSegIndex = segIndex; - EasyThrottle.throttle('follow', const Duration(seconds: 1), () { - ctr.queryDanmaku(); - }); - } - // 超出分段数返回 - if (ctr.currentSegIndex >= ctr.dmSegList.length) { - return; - } - if (ctr.dmSegList.isEmpty || - ctr.dmSegList[ctr.currentSegIndex].elems.isEmpty) { - return; - } - // 超出当前分段的弹幕总数返回 - if (ctr.currentDmIndex >= ctr.dmSegList[ctr.currentSegIndex].elems.length) { - ctr.currentDmIndex = 0; - ctr.currentSegIndex++; + currentPosition -= currentPosition % 100;//取整百的毫秒数 + + if (currentPosition == latestAddedPosition) { return; } - var element = ctr.dmSegList[ctr.currentSegIndex].elems[ctr.currentDmIndex]; - var delta = currentPosition - element.progress; + latestAddedPosition = currentPosition; - if (delta >= 0 && delta < 200) { - // 屏蔽彩色弹幕 - if (blockTypes.contains(6) ? element.color == 16777215 : true) { - _controller!.addItems([ - DanmakuItem( - element.content, - color: DmUtils.decimalToColor(element.color), - time: element.progress, - type: DmUtils.getPosition(element.mode), - ) - ]); - } - ctr.currentDmIndex++; - } else { - if (!playerController.isOpenDanmu.value) { - _controller!.pause(); - danmuPlayStatus = false; - return; - } - ctr.findClosestPositionIndex(position.inMilliseconds); + List? currentDanmakuList = + _plDanmakuController.getCurrentDanmaku(currentPosition); + + if (currentDanmakuList != null) { + Color? defaultColor = playerController.blockTypes.contains(6) ? + DmUtils.decimalToColor(16777215) : null; + + _controller!.addItems( + currentDanmakuList.map((e) => DanmakuItem( + e.content, + color: defaultColor ?? DmUtils.decimalToColor(e.color), + time: e.progress, + type: DmUtils.getPosition(e.mode), + )).toList() + ); } } From 022b3580dc002b7a13f9085710a077bd227f129f Mon Sep 17 00:00:00 2001 From: orz12 Date: Sun, 24 Dec 2023 02:55:50 +0800 Subject: [PATCH 2/2] =?UTF-8?q?opt:=20=E6=A2=B3=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/danmaku/controller.dart | 5 ++--- lib/pages/danmaku/view.dart | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pages/danmaku/controller.dart b/lib/pages/danmaku/controller.dart index 0d3f795fd..c7d627a88 100644 --- a/lib/pages/danmaku/controller.dart +++ b/lib/pages/danmaku/controller.dart @@ -5,7 +5,6 @@ import 'package:pilipala/plugin/pl_player/index.dart'; class PlDanmakuController { PlDanmakuController(this.cid); final int cid; - late Duration videoDuration; Map> dmSegMap = {}; // 已请求的段落标记 List requestedSeg = []; @@ -14,9 +13,9 @@ class PlDanmakuController { static int SEGMENT_LENGTH = 60 * 6 * 1000; - void initiate(int progress) { + void initiate(int videoDuration, int progress) { if (requestedSeg.isEmpty) { - int segCount = (videoDuration.inSeconds / (60 * 6)).ceil(); + int segCount = (videoDuration / SEGMENT_LENGTH).ceil(); requestedSeg = List.generate(segCount, (index) => false); } queryDanmaku( diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index d7030ebfc..027b9dfa8 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -47,9 +47,9 @@ class _PlDanmakuState extends State { PlDanmakuController(widget.cid); if (mounted) { playerController = widget.playerController; - _plDanmakuController.videoDuration = playerController.duration.value; if (enableShowDanmaku || playerController.isOpenDanmu.value) { _plDanmakuController.initiate( + playerController.duration.value.inMilliseconds, playerController.position.value.inMilliseconds ); } @@ -60,6 +60,7 @@ class _PlDanmakuState extends State { playerController.isOpenDanmu.listen((p0) { if (p0 && !_plDanmakuController.initiated) { _plDanmakuController.initiate( + playerController.duration.value.inMilliseconds, playerController.position.value.inMilliseconds ); }