From 54c49e1b54eb8b7b2373fe13b4c6cc0f0ced7094 Mon Sep 17 00:00:00 2001 From: xfangfang <2553041586@qq.com> Date: Fri, 10 Nov 2023 02:15:17 +0800 Subject: [PATCH] Refresh video link after error --- .../include/activity/live_player_activity.hpp | 9 ++- wiliwili/include/presenter/live_data.hpp | 10 ++- wiliwili/include/view/mpv_core.hpp | 1 + .../source/activity/live_player_activity.cpp | 61 +++++++++++++------ wiliwili/source/view/mpv_core.cpp | 2 + 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/wiliwili/include/activity/live_player_activity.hpp b/wiliwili/include/activity/live_player_activity.hpp index a8b59f27..22cf02f7 100644 --- a/wiliwili/include/activity/live_player_activity.hpp +++ b/wiliwili/include/activity/live_player_activity.hpp @@ -17,7 +17,7 @@ class LiveActivity : public brls::Activity, public LiveDataRequest { explicit LiveActivity(const bilibili::LiveVideoResult& live); explicit LiveActivity(int roomid, const std::string& name = "", - const std::string& views = ""); + const std::string& views = ""); void setCommonData(); @@ -37,9 +37,12 @@ class LiveActivity : public brls::Activity, public LiveDataRequest { private: BRLS_BIND(VideoView, video, "fullscreen/video"); + // 暂停的延时函数 handle + size_t toggleDelayIter = 0; + // 遇到错误重试的延时函数 handle + size_t errorDelayIter = 0; + bilibili::LiveVideoResult liveData; - // 视频超时的时间戳 - std::chrono::system_clock::time_point videoExpires{}; //更新timeLabel MPVEvent::Subscription tl_event_id; diff --git a/wiliwili/include/presenter/live_data.hpp b/wiliwili/include/presenter/live_data.hpp index 25605318..10d1d886 100644 --- a/wiliwili/include/presenter/live_data.hpp +++ b/wiliwili/include/presenter/live_data.hpp @@ -50,8 +50,10 @@ class LiveDataRequest : public Presenter { onLiveData(liveRoomPlayInfo); }, [ASYNC_TOKEN](BILI_ERR) { - ASYNC_RELEASE - this->onError(error); + brls::sync([ASYNC_TOKEN, error]() { + ASYNC_RELEASE + this->onError(error); + }); }); reportHistory(roomid); @@ -66,7 +68,9 @@ class LiveDataRequest : public Presenter { [roomid]() { brls::Logger::debug("report live history {}", roomid); }, - [this](BILI_ERR) { this->onError(error); }); + [](BILI_ERR) { + brls::Logger::error("report live history:", error); + }); } std::string getQualityDescription(int qn) { diff --git a/wiliwili/include/view/mpv_core.hpp b/wiliwili/include/view/mpv_core.hpp index 8c08f053..0561c609 100644 --- a/wiliwili/include/view/mpv_core.hpp +++ b/wiliwili/include/view/mpv_core.hpp @@ -229,6 +229,7 @@ class MPVCore : public brls::Singleton { double playback_time = 0; double percent_pos = 0; int64_t video_progress = 0; + int mpv_error_code = 0; // 低画质解码,剔除解码过程中的部分步骤,可以用来节省cpu inline static bool LOW_QUALITY = false; diff --git a/wiliwili/source/activity/live_player_activity.cpp b/wiliwili/source/activity/live_player_activity.cpp index 5ffc7c61..ed00a0d9 100644 --- a/wiliwili/source/activity/live_player_activity.cpp +++ b/wiliwili/source/activity/live_player_activity.cpp @@ -64,7 +64,6 @@ static void onDanmakuReceived(std::string&& message) { LiveActivity::LiveActivity(const bilibili::LiveVideoResult& live) : liveData(live) { brls::Logger::debug("LiveActivity: create: {}", live.roomid); - MPVCore::instance().command_async("set", "loop-playlist", "force"); this->setCommonData(); GA("open_live", {{"id", std::to_string(live.roomid)}}) GA("open_live", {{"live_id", std::to_string(live.roomid)}}) @@ -74,7 +73,6 @@ LiveActivity::LiveActivity(const bilibili::LiveVideoResult& live) LiveActivity::LiveActivity(int roomid, const std::string& name, const std::string& views) { brls::Logger::debug("LiveActivity: create: {}", roomid); - MPVCore::instance().command_async("set", "loop-playlist", "force"); this->liveData.roomid = roomid; this->liveData.title = name; this->liveData.watched_show.text_large = views; @@ -102,19 +100,34 @@ void LiveActivity::setCommonData() { tl_event_id = MPV_E->subscribe([this](MpvEventEnum e) { if (e == UPDATE_PROGRESS) { if (!liveRoomPlayInfo.live_time) return; - auto timeNow = std::chrono::system_clock::now(); std::chrono::time_point _zero; size_t now = std::chrono::duration_cast( - timeNow - _zero) + std::chrono::system_clock::now() - _zero) .count(); this->video->setStatusLabelLeft( wiliwili::sec2Time(now - liveRoomPlayInfo.live_time)); - if (timeNow > videoExpires) { - MPVCore::instance().pause(); - // 十秒后再次检查,避免链接获取失败 - videoExpires = timeNow + std::chrono::seconds(10); - requestData(liveData.roomid); + } else if (e == MPV_FILE_ERROR) { + this->video->showOSD(false); + this->video->setStatusLabelLeft("播放错误"); + + switch (MPVCore::instance().mpv_error_code) { + case MPV_ERROR_UNKNOWN_FORMAT: + this->video->setOnlineCount("暂不支持当前视频格式"); + break; + case MPV_ERROR_LOADING_FAILED: + this->video->setOnlineCount("加载失败"); + // 加载失败时,获取直播间信息,查看是否直播间已经关闭 + // 如果直播间信息获取失败,则认定为断网,每隔N秒重试一次 + this->requestData(liveData.roomid); + default: + this->video->setOnlineCount( + {mpv_error_string(MPVCore::instance().mpv_error_code)}); } + } else if (e == END_OF_FILE) { + // flv 直播遇到网络错误不会报错,而是输出 END_OF_FILE + // 直播间关闭时也可能进入这里 + this->video->setOnlineCount("加载失败"); + this->requestData(liveData.roomid); } }); } @@ -170,8 +183,9 @@ void LiveActivity::onContentAvailable() { } else { this->video->showOSD(false); MPVCore::instance().pause(); + brls::cancelDelay(toggleDelayIter); ASYNC_RETAIN - brls::delay(5000, [ASYNC_TOKEN]() { + toggleDelayIter = brls::delay(5000, [ASYNC_TOKEN]() { ASYNC_RELEASE if (MPVCore::instance().isPaused()) { MPVCore::instance().stop(); @@ -208,9 +222,13 @@ int LiveActivity::getCurrentQualityIndex() { } void LiveActivity::onLiveData(const bilibili::LiveRoomPlayInfo& result) { + // todo:定时获取在线人数 + this->video->setOnlineCount(liveData.watched_show.text_large); + if (result.live_status != 1) { // 未开播 brls::Logger::error("LiveActivity: not live"); + this->video->showOSD(false); this->video->setStatusLabelLeft("未开播"); return; } @@ -227,13 +245,6 @@ void LiveActivity::onLiveData(const bilibili::LiveRoomPlayInfo& result) { for (const auto& i : liveUrl.url_info) { auto url = i.host + liveUrl.base_url + i.extra; - // 查找过期时间 - // 链接中写的超时时间为1小时,但是实际测试能播放6小时 - // 暂时设置为固定的5小时,避免系统时间是错误的没办法直接和视频链接中的 expires 进行比较。 - // 另外的解决办法是获取一下网络时间 - videoExpires = - std::chrono::system_clock::now() + std::chrono::seconds(18000); - // 设置视频链接 brls::Logger::debug("Live stream url: {}", url); this->video->setUrl(url); @@ -243,15 +254,27 @@ void LiveActivity::onLiveData(const bilibili::LiveRoomPlayInfo& result) { void LiveActivity::onError(const std::string& error) { brls::Logger::error("ERROR request live data: {}", error); + this->video->showOSD(false); + this->video->setOnlineCount(error); + + // 每隔1秒自动重试 + brls::cancelDelay(errorDelayIter); + ASYNC_RETAIN + errorDelayIter = brls::delay(1000, [ASYNC_TOKEN]() { + ASYNC_RELEASE + this->requestData(liveData.roomid); + }); } LiveActivity::~LiveActivity() { brls::Logger::debug("LiveActivity: delete"); - this->video->stop(); LiveDanmaku::instance().disconnect(); // 取消监控mpv MPV_CE->unsubscribe(event_id); MPV_E->unsubscribe(tl_event_id); - MPVCore::instance().command_async("set", "loop-playlist", "1"); + // 在取消监控之后再停止播放器,避免在播放器停止时触发事件 (尤其是:END_OF_FILE) + this->video->stop(); LiveDanmakuCore::instance().reset(); + brls::cancelDelay(toggleDelayIter); + brls::cancelDelay(errorDelayIter); } diff --git a/wiliwili/source/view/mpv_core.cpp b/wiliwili/source/view/mpv_core.cpp index 77b6752d..d1d3e06e 100644 --- a/wiliwili/source/view/mpv_core.cpp +++ b/wiliwili/source/view/mpv_core.cpp @@ -701,6 +701,7 @@ void MPVCore::eventMainLoop() { disableDimming(false); auto node = (mpv_event_end_file *)event->data; if (node->reason == MPV_END_FILE_REASON_ERROR) { + mpv_error_code = node->error; brls::Logger::error("========> MPV ERROR: {}", mpv_error_string(node->error)); mpvCoreEvent.fire(MpvEventEnum::MPV_FILE_ERROR); @@ -887,6 +888,7 @@ void MPVCore::reset() { this->cache_speed = 0; // Bps this->playback_time = 0; this->video_progress = 0; + this->mpv_error_code = 0; // 软硬解切换后应该手动设置一次渲染尺寸 // 切换视频前设置渲染尺寸可以顺便将上一条视频的最后一帧画面清空