From 7b04385bc8afd39ca02aaa194411ebea008e0442 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 9 Jan 2022 15:01:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6http-ts=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E5=99=A8=E7=89=B9=E6=80=A7:=20#1336?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Http/HttpTSPlayer.cpp | 2 +- src/Http/TsPlayer.cpp | 111 +++++++++++----------- src/Http/TsPlayer.h | 58 ++++++------ src/Http/TsPlayerImp.h | 125 ++++++++++++------------ src/Http/TsplayerImp.cpp | 193 ++++++++++++++++++++------------------ src/Player/PlayerBase.cpp | 11 +-- 6 files changed, 254 insertions(+), 246 deletions(-) diff --git a/src/Http/HttpTSPlayer.cpp b/src/Http/HttpTSPlayer.cpp index ff42bd23..58c66c30 100644 --- a/src/Http/HttpTSPlayer.cpp +++ b/src/Http/HttpTSPlayer.cpp @@ -51,7 +51,7 @@ void HttpTSPlayer::onResponseBody(const char *buf, size_t size, size_t recved_si if (_split_ts) { try { _segment.input(buf, size); - }catch (std::exception &ex) { + } catch (std::exception &ex) { WarnL << ex.what(); //ts解析失败,清空缓存数据 _segment.reset(); diff --git a/src/Http/TsPlayer.cpp b/src/Http/TsPlayer.cpp index 0ba2e895..863d7400 100644 --- a/src/Http/TsPlayer.cpp +++ b/src/Http/TsPlayer.cpp @@ -1,68 +1,73 @@ -// -// Created by alex on 2021/4/6. -// +/* + * Copyright (c) 2020 The ZLMediaKit project authors. All Rights Reserved. + * Created by alex on 2021/4/6. + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include "TsPlayer.h" namespace mediakit { - TsPlayer::TsPlayer(const EventPoller::Ptr &poller):HttpTSPlayer(poller, true) {} +TsPlayer::TsPlayer(const EventPoller::Ptr &poller) : HttpTSPlayer(poller, true) {} - TsPlayer::~TsPlayer() {} +void TsPlayer::play(const string &strUrl) { + _ts_url.append(strUrl); + playTs(); +} - void TsPlayer::play(const string &strUrl) { - _ts_url.append(strUrl); - playTs(); +void TsPlayer::teardown_l(const SockException &ex) { + HttpClient::clear(); + shutdown(ex); +} + +void TsPlayer::teardown() { + teardown_l(SockException(Err_shutdown, "teardown")); +} + +void TsPlayer::playTs() { + if (waitResponse()) { + //播放器目前还存活,正在下载中 + return; } + WarnL << "fetch:" << _ts_url; + _request_complete = false; + weak_ptr weak_self = dynamic_pointer_cast(shared_from_this()); + setMethod("GET"); + sendRequest(_ts_url, 3600 * 2, 60); +} - void TsPlayer::teardown_l(const SockException &ex) { - HttpClient::clear(); - shutdown(ex); - } +void TsPlayer::onResponseCompleted() { + //接收完毕 + teardown_l(SockException(Err_success, StrPrinter << _ts_url << ": play completed")); +} - void TsPlayer::teardown() { - teardown_l(SockException(Err_shutdown, "teardown")); +void TsPlayer::onDisconnect(const SockException &ex) { + WarnL << _ts_url << " :" << ex.getErrCode() << " " << ex.what(); + if (_first) { + //第一次失败,则播放失败 + _first = false; + onPlayResult(ex); + return; } + if (ex.getErrCode() == Err_shutdown) { + onShutdown(ex); + } else { + onResponseCompleted(); + onShutdown(ex); + } +} - void TsPlayer::playTs() { - if (waitResponse()) { - //播放器目前还存活,正在下载中 - return; - } - WarnL << "fetch:" << _ts_url; - _request_complete = false; - weak_ptr weak_self = dynamic_pointer_cast(shared_from_this()); - setMethod("GET"); - sendRequest(_ts_url, 3600 * 2, 60); +ssize_t TsPlayer::onResponseHeader(const string &status, const HttpClient::HttpHeader &header) { + ssize_t ret = HttpTSPlayer::onResponseHeader(status, header); + if (_first) { + _first = false; + onPlayResult(SockException(Err_success, "play success")); } + return ret; +} - void TsPlayer::onResponseCompleted() { - //接收完毕 - teardown_l(SockException(Err_success, StrPrinter << _ts_url << ": play completed")); - } - - void TsPlayer::onDisconnect(const SockException &ex) { - WarnL << _ts_url << " :" << ex.getErrCode() << " " << ex.what(); - if (_first) { - //第一次失败,则播放失败 - _first = false; - onPlayResult(ex); - return; - } - if (ex.getErrCode() == Err_shutdown) { - onShutdown(ex); - }else{ - onResponseCompleted(); - onShutdown(ex); - } - } - - ssize_t TsPlayer::onResponseHeader(const string &status, const HttpClient::HttpHeader &header) { - ssize_t ret = HttpTSPlayer::onResponseHeader(status, header); - if (_first) { - _first = false; - onPlayResult(SockException(Err_success, "play success")); - } - return ret; - } }//namespace mediakit \ No newline at end of file diff --git a/src/Http/TsPlayer.h b/src/Http/TsPlayer.h index 72e2f007..c761b739 100644 --- a/src/Http/TsPlayer.h +++ b/src/Http/TsPlayer.h @@ -1,10 +1,6 @@ -// -// Created by alex on 2021/4/6. -// - /* * Copyright (c) 2020 The ZLMediaKit project authors. All Rights Reserved. - * + * Created by alex on 2021/4/6. * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). * * Use of this source code is governed by MIT license that can be found in the @@ -24,37 +20,37 @@ #include "Rtp/TSDecoder.h" #include "HttpTSPlayer.h" - - using namespace toolkit; namespace mediakit { - class TsPlayer : public HttpTSPlayer , public PlayerBase { - public: - TsPlayer(const EventPoller::Ptr &poller); - ~TsPlayer() override; - /** - * 开始播放 - * @param strUrl - */ - void play(const string &strUrl) override; - /** - * 停止播放 - */ - void teardown() override; - private: - void playTs(); - void teardown_l(const SockException &ex); +class TsPlayer : public HttpTSPlayer, public PlayerBase { +public: + TsPlayer(const EventPoller::Ptr &poller); + ~TsPlayer() override = default; - protected: - virtual void onResponseCompleted() override; + /** + * 开始播放 + */ + void play(const string &url) override; - virtual void onDisconnect(const SockException &ex) override; + /** + * 停止播放 + */ + void teardown() override; + +private: + void playTs(); + void teardown_l(const SockException &ex); + +protected: + virtual void onResponseCompleted() override; + virtual void onDisconnect(const SockException &ex) override; + virtual ssize_t onResponseHeader(const string &status, const HttpHeader &header) override; + +private: + bool _first = true; + string _ts_url; +}; - virtual ssize_t onResponseHeader(const string &status, const HttpHeader &header) override; - private: - bool _first = true; - string _ts_url; - }; }//namespace mediakit #endif //HTTP_TSPLAYER_H diff --git a/src/Http/TsPlayerImp.h b/src/Http/TsPlayerImp.h index 80c06167..402f32ee 100644 --- a/src/Http/TsPlayerImp.h +++ b/src/Http/TsPlayerImp.h @@ -1,6 +1,12 @@ -// -// Created by alex on 2021/7/5. -// +/* + * Copyright (c) 2020 The ZLMediaKit project authors. All Rights Reserved. + * Created by alex on 2021/4/6. + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef HTTP_TSPLAYERIMP_H #define HTTP_TSPLAYERIMP_H @@ -15,82 +21,75 @@ #include "TsPlayer.h" using namespace toolkit; + namespace mediakit { - class TsDemuxer : public MediaSinkInterface, public TrackSource, public std::enable_shared_from_this { - public: - TsDemuxer() = default; +class TsDemuxer : public MediaSinkInterface, public TrackSource, public std::enable_shared_from_this { +public: + TsDemuxer() = default; + ~TsDemuxer() override { _timer = nullptr; } - ~TsDemuxer() override { _timer = nullptr; } + void start(const EventPoller::Ptr &poller, TrackListener *listener); - void start(const EventPoller::Ptr &poller, TrackListener *listener); + bool inputFrame(const Frame::Ptr &frame) override; - bool inputFrame(const Frame::Ptr &frame) override; + bool addTrack(const Track::Ptr &track) override { + return _delegate.addTrack(track); + } - bool addTrack(const Track::Ptr &track) override { - return _delegate.addTrack(track); - } + void addTrackCompleted() override { + _delegate.addTrackCompleted(); + } - void addTrackCompleted() override { - _delegate.addTrackCompleted(); - } + void resetTracks() override { + ((MediaSink &) _delegate).resetTracks(); + } - void resetTracks() override { - ((MediaSink &) _delegate).resetTracks(); - } + vector getTracks(bool ready = true) const override { + return _delegate.getTracks(ready); + } - vector getTracks(bool ready = true) const override { - return _delegate.getTracks(ready); - } +private: + void onTick(); + int64_t getBufferMS(); + int64_t getPlayPosition(); + void setPlayPosition(int64_t pos); - private: - void onTick(); +private: + int64_t _ticker_offset = 0; + Ticker _ticker; + Stamp _stamp[2]; + Timer::Ptr _timer; + MediaSinkDelegate _delegate; + multimap _frame_cache; +}; - int64_t getBufferMS(); +class TsPlayerImp : public PlayerImp, private TrackListener { +public: + using Ptr = std::shared_ptr; - int64_t getPlayPosition(); + TsPlayerImp(const EventPoller::Ptr &poller = nullptr); + ~TsPlayerImp() override = default; - void setPlayPosition(int64_t pos); +private: + //// HlsPlayer override//// + void onPacket(const char *data, size_t len) override; - private: - int64_t _ticker_offset = 0; - Ticker _ticker; - Stamp _stamp[2]; - Timer::Ptr _timer; - MediaSinkDelegate _delegate; - multimap _frame_cache; - }; +private: + //// PlayerBase override//// + void onPlayResult(const SockException &ex) override; + vector getTracks(bool ready = true) const override; + void onShutdown(const SockException &ex) override; +private: + //// TrackListener override//// + bool addTrack(const Track::Ptr &track) override { return true; }; + void addTrackCompleted() override; - class TsPlayerImp : public PlayerImp, private TrackListener { - public: - typedef std::shared_ptr Ptr; +private: + DecoderImp::Ptr _decoder; + MediaSinkInterface::Ptr _demuxer; +}; - TsPlayerImp(const EventPoller::Ptr &poller = nullptr); - - ~TsPlayerImp() override = default; - - private: - //// HlsPlayer override//// - void onPacket(const char *data, size_t len) override; - - private: - //// PlayerBase override//// - void onPlayResult(const SockException &ex) override; - - vector getTracks(bool ready = true) const override; - - void onShutdown(const SockException &ex) override; - - private: - //// TrackListener override//// - bool addTrack(const Track::Ptr &track) override { return true; }; - - void addTrackCompleted() override; - - private: - DecoderImp::Ptr _decoder; - MediaSinkInterface::Ptr _demuxer; - }; }//namespace mediakit #endif //HTTP_TSPLAYERIMP_H diff --git a/src/Http/TsplayerImp.cpp b/src/Http/TsplayerImp.cpp index 8f0d684a..bcfd2f51 100644 --- a/src/Http/TsplayerImp.cpp +++ b/src/Http/TsplayerImp.cpp @@ -1,123 +1,132 @@ +/* + * Copyright (c) 2020 The ZLMediaKit project authors. All Rights Reserved. + * Created by alex on 2021/4/6. + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + #include "TsPlayerImp.h" namespace mediakit { - void TsDemuxer::start(const EventPoller::Ptr &poller, TrackListener *listener) { - _frame_cache.clear(); - _stamp[TrackAudio].setRelativeStamp(0); - _stamp[TrackVideo].setRelativeStamp(0); - _stamp[TrackAudio].syncTo(_stamp[TrackVideo]); - setPlayPosition(0); - _delegate.setTrackListener(listener); +void TsDemuxer::start(const EventPoller::Ptr &poller, TrackListener *listener) { + _frame_cache.clear(); + _stamp[TrackAudio].setRelativeStamp(0); + _stamp[TrackVideo].setRelativeStamp(0); + _stamp[TrackAudio].syncTo(_stamp[TrackVideo]); + setPlayPosition(0); - //每50毫秒执行一次 - weak_ptr weak_self = shared_from_this(); - _timer = std::make_shared(0.05f, [weak_self]() { - auto strong_self = weak_self.lock(); - if (!strong_self) { - return false; - } - strong_self->onTick(); - return true; - }, poller); - } + _delegate.setTrackListener(listener); - bool TsDemuxer::inputFrame(const Frame::Ptr &frame) { - //为了避免track准备时间过长, 因此在没准备好之前, 直接消费掉所有的帧 - if (!_delegate.isAllTrackReady()) { - _delegate.inputFrame(frame); - return true; + //每50毫秒执行一次 + weak_ptr weak_self = shared_from_this(); + _timer = std::make_shared(0.05f, [weak_self]() { + auto strong_self = weak_self.lock(); + if (!strong_self) { + return false; } - //计算相对时间戳 - int64_t dts, pts; - //根据时间戳缓存frame - _stamp[frame->getTrackType()].revise(frame->dts(), frame->pts(), dts, pts); - _frame_cache.emplace(dts, Frame::getCacheAbleFrame(frame)); - //根据时间戳缓存frame -// _frame_cache.emplace(dts, Frame::getCacheAbleFrame(frame)); + strong_self->onTick(); + return true; + }, poller); +} - if (getBufferMS() > 30 * 1000) { - //缓存超过30秒,强制消费至15秒(减少延时或内存占用) - while (getBufferMS() > 15 * 1000) { - _delegate.inputFrame(_frame_cache.begin()->second); - _frame_cache.erase(_frame_cache.begin()); - } - //接着播放缓存中最早的帧 - setPlayPosition(_frame_cache.begin()->first); - } +bool TsDemuxer::inputFrame(const Frame::Ptr &frame) { + //为了避免track准备时间过长, 因此在没准备好之前, 直接消费掉所有的帧 + if (!_delegate.isAllTrackReady()) { + _delegate.inputFrame(frame); return true; } + //计算相对时间戳 + int64_t dts, pts; + //根据时间戳缓存frame + _stamp[frame->getTrackType()].revise(frame->dts(), frame->pts(), dts, pts); + _frame_cache.emplace(dts, Frame::getCacheAbleFrame(frame)); - int64_t TsDemuxer::getPlayPosition() { - return _ticker.elapsedTime() + _ticker_offset; - } - - int64_t TsDemuxer::getBufferMS() { - if (_frame_cache.empty()) { - return 0; + if (getBufferMS() > 30 * 1000) { + //缓存超过30秒,强制消费至15秒(减少延时或内存占用) + while (getBufferMS() > 15 * 1000) { + _delegate.inputFrame(_frame_cache.begin()->second); + _frame_cache.erase(_frame_cache.begin()); } - return _frame_cache.rbegin()->first - _frame_cache.begin()->first; + //接着播放缓存中最早的帧 + setPlayPosition(_frame_cache.begin()->first); } + return true; +} - void TsDemuxer::setPlayPosition(int64_t pos) { - _ticker.resetTime(); - _ticker_offset = pos; +int64_t TsDemuxer::getPlayPosition() { + return _ticker.elapsedTime() + _ticker_offset; +} + +int64_t TsDemuxer::getBufferMS() { + if (_frame_cache.empty()) { + return 0; } + return _frame_cache.rbegin()->first - _frame_cache.begin()->first; +} - void TsDemuxer::onTick() { - auto it = _frame_cache.begin(); - while (it != _frame_cache.end()) { - if (it->first > getPlayPosition()) { - //这些帧还未到时间播放 - break; - } - if (getBufferMS() < 3 * 1000) { - //缓存小于3秒,那么降低定时器消费速度(让剩余的数据在3秒后消费完毕) - //目的是为了防止定时器长时间干等后,数据瞬间消费完毕 - setPlayPosition(_frame_cache.begin()->first); - } - //消费掉已经到期的帧 - _delegate.inputFrame(it->second); - it = _frame_cache.erase(it); +void TsDemuxer::setPlayPosition(int64_t pos) { + _ticker.resetTime(); + _ticker_offset = pos; +} + +void TsDemuxer::onTick() { + auto it = _frame_cache.begin(); + while (it != _frame_cache.end()) { + if (it->first > getPlayPosition()) { + //这些帧还未到时间播放 + break; } + if (getBufferMS() < 3 * 1000) { + //缓存小于3秒,那么降低定时器消费速度(让剩余的数据在3秒后消费完毕) + //目的是为了防止定时器长时间干等后,数据瞬间消费完毕 + setPlayPosition(_frame_cache.begin()->first); + } + //消费掉已经到期的帧 + _delegate.inputFrame(it->second); + it = _frame_cache.erase(it); } +} ////////////////////////////////////////////////////////////////////////// - TsPlayerImp::TsPlayerImp(const EventPoller::Ptr &poller) : PlayerImp(poller) {} +TsPlayerImp::TsPlayerImp(const EventPoller::Ptr &poller) : PlayerImp(poller) {} - void TsPlayerImp::onPacket(const char *data, size_t len) { - if (!_decoder) { - _decoder = DecoderImp::createDecoder(DecoderImp::decoder_ts, _demuxer.get()); - } - - if (_decoder && _demuxer) { - _decoder->input((uint8_t *) data, len); - } +void TsPlayerImp::onPacket(const char *data, size_t len) { + if (!_decoder) { + _decoder = DecoderImp::createDecoder(DecoderImp::decoder_ts, _demuxer.get()); } - void TsPlayerImp::addTrackCompleted() { - PlayerImp::onPlayResult(SockException(Err_success, "play hls success")); + if (_decoder && _demuxer) { + _decoder->input((uint8_t *) data, len); } +} - void TsPlayerImp::onPlayResult(const SockException &ex) { - WarnL << ex.getErrCode() << " " << ex.what(); - if (ex) { - PlayerImp::onPlayResult(ex); - } else { - auto demuxer = std::make_shared(); - demuxer->start(getPoller(), this); - _demuxer = std::move(demuxer); - } - } +void TsPlayerImp::addTrackCompleted() { + PlayerImp::onPlayResult(SockException(Err_success, "play hls success")); +} - void TsPlayerImp::onShutdown(const SockException &ex) { - PlayerImp::onShutdown(ex); - _demuxer = nullptr; +void TsPlayerImp::onPlayResult(const SockException &ex) { + WarnL << ex.getErrCode() << " " << ex.what(); + if (ex) { + PlayerImp::onPlayResult(ex); + } else { + auto demuxer = std::make_shared(); + demuxer->start(getPoller(), this); + _demuxer = std::move(demuxer); } +} - vector TsPlayerImp::getTracks(bool ready) const { - return static_pointer_cast(_demuxer)->getTracks(ready); - } +void TsPlayerImp::onShutdown(const SockException &ex) { + PlayerImp::onShutdown(ex); + _demuxer = nullptr; +} + +vector TsPlayerImp::getTracks(bool ready) const { + return static_pointer_cast(_demuxer)->getTracks(ready); +} }//namespace mediakit \ No newline at end of file diff --git a/src/Player/PlayerBase.cpp b/src/Player/PlayerBase.cpp index ff579217..aa8a0f6d 100644 --- a/src/Player/PlayerBase.cpp +++ b/src/Player/PlayerBase.cpp @@ -48,14 +48,13 @@ PlayerBase::Ptr PlayerBase::createPlayer(const EventPoller::Ptr &poller, const s if (strcasecmp("rtmp", prefix.data()) == 0) { return PlayerBase::Ptr(new RtmpPlayerImp(poller), releasePlayer); } - if ((strcasecmp("http",prefix.data()) == 0 || strcasecmp("https",prefix.data()) == 0)) { + if ((strcasecmp("http", prefix.data()) == 0 || strcasecmp("https", prefix.data()) == 0)) { if (end_with(url, ".m3u8") || end_with(url_in, ".m3u8")) { - return PlayerBase::Ptr(new HlsPlayerImp(poller),releasePlayer); + return PlayerBase::Ptr(new HlsPlayerImp(poller), releasePlayer); + } else if (end_with(url, ".ts") || end_with(url_in, ".ts")) { + return PlayerBase::Ptr(new TsPlayerImp(poller), releasePlayer); } - else if (end_with(url, ".ts") || end_with(url_in, ".ts")) { - return PlayerBase::Ptr(new TsPlayerImp(poller),releasePlayer); - } - return PlayerBase::Ptr(new TsPlayerImp(poller),releasePlayer); + return PlayerBase::Ptr(new TsPlayerImp(poller), releasePlayer); } return PlayerBase::Ptr(new RtspPlayerImp(poller), releasePlayer);