HLS TS 切片下载失败后清除该切片遗留的解复用输入缓存 (#4786)

在 HLS TS 切片下载失败后清除该切片遗留的解复用输入缓存,防止其与下一切片拼接导致错误的包或者损坏的包出现.
This commit is contained in:
YuLi
2026-07-23 20:23:19 -07:00
committed by GitHub
parent 1681864d79
commit 245f7c3e45
6 changed files with 28 additions and 0 deletions

View File

@@ -153,6 +153,7 @@ void HlsPlayer::fetchSegment() {
return;
}
if (err) {
strong_self->onSegmentDownloadFailed(err);
WarnL << "Download ts segment " << url << " failed:" << err;
if (err.getErrCode() == Err_timeout) {
strong_self->_timeout_multiple = MAX(strong_self->_timeout_multiple + 1, MAX_TIMEOUT_MULTIPLE);
@@ -492,6 +493,14 @@ void HlsPlayerImp::onPacket(const char *data, size_t len) {
_recvtotalbytes += HlsPlayer::getRecvTotalBytes();
}
void HlsPlayerImp::onSegmentDownloadFailed(const toolkit::SockException &ex) {
if (_decoder && ex) {
// 失败切片的输入残片不能与下一切片拼接;这里只清输入缓存,不 flush 解码帧。
// Input left by a failed segment must not join the next one; clear it without flushing decoded frames.
_decoder->clearInputCache();
}
}
void HlsPlayerImp::addTrackCompleted() {
PlayerImp<HlsPlayer, PlayerBase>::onPlayResult(SockException(Err_success, "play hls success"));
}

View File

@@ -90,6 +90,9 @@ protected:
* [AUTO-TRANSLATED:159a6559]
*/
virtual void onPacket(const char *data, size_t len) = 0;
// TS 切片下载失败通知;派生类可清理该切片遗留的输入状态。
// Notify derived classes to clear input state left by a failed TS segment.
virtual void onSegmentDownloadFailed(const toolkit::SockException &ex) {}
private:
bool onParsed(bool is_m3u8_inner, int64_t sequence, const map<int, ts_segment> &ts_map) override;
@@ -149,6 +152,7 @@ public:
private:
//// HlsPlayer override////
void onPacket(const char *data, size_t len) override;
void onSegmentDownloadFailed(const toolkit::SockException &ex) override;
private:
//// PlayerBase override////

View File

@@ -72,6 +72,10 @@ ssize_t DecoderImp::input(const uint8_t *data, size_t bytes){
return _decoder->input(data, bytes);
}
void DecoderImp::clearInputCache() {
_decoder->clearInputCache();
}
DecoderImp::DecoderImp(const Decoder::Ptr &decoder, MediaSinkInterface *sink){
_decoder = decoder;
_sink = sink;

View File

@@ -25,6 +25,9 @@ public:
using onStream = std::function<void(int stream, int codecid, const void *extra, size_t bytes, int finish)>;
virtual ssize_t input(const uint8_t *data, size_t bytes) = 0;
// 清理未完成的输入缓存,但不 flush 已解析的帧。
// Clear incomplete input cache without flushing parsed frames.
virtual void clearInputCache() {}
void setOnDecode(onDecode cb);
void setOnStream(onStream cb);
@@ -45,6 +48,7 @@ public:
static Ptr createDecoder(Type type, MediaSinkInterface *sink);
ssize_t input(const uint8_t *data, size_t bytes);
void clearInputCache();
void flush();
protected:

View File

@@ -146,6 +146,12 @@ ssize_t TSDecoder::input(const uint8_t *data, size_t bytes) {
return bytes;
}
void TSDecoder::clearInputCache() {
// 只清理未完成的 TS 输入缓存,不重置 libmpegts 或 flush 残留帧。
// Clear only incomplete TS input; do not reset libmpegts or flush pending frames.
_ts_segment.reset();
}
#endif//defined(ENABLE_HLS)
}//namespace mediakit

View File

@@ -49,6 +49,7 @@ public:
TSDecoder();
~TSDecoder();
ssize_t input(const uint8_t* data, size_t bytes) override ;
void clearInputCache() override;
private:
TSSegment _ts_segment;