diff --git a/src/Http/HlsPlayer.cpp b/src/Http/HlsPlayer.cpp index 4c5f8eaf..7b11ef2d 100644 --- a/src/Http/HlsPlayer.cpp +++ b/src/Http/HlsPlayer.cpp @@ -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::onPlayResult(SockException(Err_success, "play hls success")); } diff --git a/src/Http/HlsPlayer.h b/src/Http/HlsPlayer.h index 3f3d965a..ad0d408e 100644 --- a/src/Http/HlsPlayer.h +++ b/src/Http/HlsPlayer.h @@ -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 &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//// diff --git a/src/Rtp/Decoder.cpp b/src/Rtp/Decoder.cpp index 42abe783..a94fde9b 100644 --- a/src/Rtp/Decoder.cpp +++ b/src/Rtp/Decoder.cpp @@ -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; diff --git a/src/Rtp/Decoder.h b/src/Rtp/Decoder.h index 8a8b90a1..3734481d 100644 --- a/src/Rtp/Decoder.h +++ b/src/Rtp/Decoder.h @@ -25,6 +25,9 @@ public: using onStream = std::function; 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: diff --git a/src/Rtp/TSDecoder.cpp b/src/Rtp/TSDecoder.cpp index c9362860..03b8014d 100644 --- a/src/Rtp/TSDecoder.cpp +++ b/src/Rtp/TSDecoder.cpp @@ -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 diff --git a/src/Rtp/TSDecoder.h b/src/Rtp/TSDecoder.h index 2cd2d4d6..d5fa6479 100644 --- a/src/Rtp/TSDecoder.h +++ b/src/Rtp/TSDecoder.h @@ -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;