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; return;
} }
if (err) { if (err) {
strong_self->onSegmentDownloadFailed(err);
WarnL << "Download ts segment " << url << " failed:" << err; WarnL << "Download ts segment " << url << " failed:" << err;
if (err.getErrCode() == Err_timeout) { if (err.getErrCode() == Err_timeout) {
strong_self->_timeout_multiple = MAX(strong_self->_timeout_multiple + 1, MAX_TIMEOUT_MULTIPLE); 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(); _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() { void HlsPlayerImp::addTrackCompleted() {
PlayerImp<HlsPlayer, PlayerBase>::onPlayResult(SockException(Err_success, "play hls success")); PlayerImp<HlsPlayer, PlayerBase>::onPlayResult(SockException(Err_success, "play hls success"));
} }

View File

@@ -90,6 +90,9 @@ protected:
* [AUTO-TRANSLATED:159a6559] * [AUTO-TRANSLATED:159a6559]
*/ */
virtual void onPacket(const char *data, size_t len) = 0; 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: private:
bool onParsed(bool is_m3u8_inner, int64_t sequence, const map<int, ts_segment> &ts_map) override; bool onParsed(bool is_m3u8_inner, int64_t sequence, const map<int, ts_segment> &ts_map) override;
@@ -149,6 +152,7 @@ public:
private: private:
//// HlsPlayer override//// //// HlsPlayer override////
void onPacket(const char *data, size_t len) override; void onPacket(const char *data, size_t len) override;
void onSegmentDownloadFailed(const toolkit::SockException &ex) override;
private: private:
//// PlayerBase override//// //// PlayerBase override////

View File

@@ -72,6 +72,10 @@ ssize_t DecoderImp::input(const uint8_t *data, size_t bytes){
return _decoder->input(data, bytes); return _decoder->input(data, bytes);
} }
void DecoderImp::clearInputCache() {
_decoder->clearInputCache();
}
DecoderImp::DecoderImp(const Decoder::Ptr &decoder, MediaSinkInterface *sink){ DecoderImp::DecoderImp(const Decoder::Ptr &decoder, MediaSinkInterface *sink){
_decoder = decoder; _decoder = decoder;
_sink = sink; _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)>; 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; 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 setOnDecode(onDecode cb);
void setOnStream(onStream cb); void setOnStream(onStream cb);
@@ -45,6 +48,7 @@ public:
static Ptr createDecoder(Type type, MediaSinkInterface *sink); static Ptr createDecoder(Type type, MediaSinkInterface *sink);
ssize_t input(const uint8_t *data, size_t bytes); ssize_t input(const uint8_t *data, size_t bytes);
void clearInputCache();
void flush(); void flush();
protected: protected:

View File

@@ -146,6 +146,12 @@ ssize_t TSDecoder::input(const uint8_t *data, size_t bytes) {
return 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) #endif//defined(ENABLE_HLS)
}//namespace mediakit }//namespace mediakit

View File

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