diff --git a/src/Player/PlayerBase.cpp b/src/Player/PlayerBase.cpp index 1f389aad..ef891bad 100644 --- a/src/Player/PlayerBase.cpp +++ b/src/Player/PlayerBase.cpp @@ -39,8 +39,13 @@ const char PlayerBase::kRtspUser[] = "rtsp_user" ; const char PlayerBase::kRtspPwd[] = "rtsp_pwd"; const char PlayerBase::kRtspPwdIsMD5[] = "rtsp_pwd_md5"; +const char PlayerBase::kPlayTimeoutMS[] = "play_timeout_ms"; +const char PlayerBase::kMediaTimeoutMS[] = "media_timeout_ms"; +const char PlayerBase::kBeatIntervalMS[] = "beat_interval_ms"; +const char PlayerBase::kMaxAnalysisMS[] = "max_analysis_ms"; -PlayerBase::Ptr PlayerBase::createPlayer(const char* strUrl) { + + PlayerBase::Ptr PlayerBase::createPlayer(const char* strUrl) { static auto releasePlayer = [](PlayerBase *ptr){ onceToken token(nullptr,[&](){ delete ptr; @@ -57,6 +62,13 @@ PlayerBase::Ptr PlayerBase::createPlayer(const char* strUrl) { return PlayerBase::Ptr(new RtspPlayerImp(),releasePlayer); } +PlayerBase::PlayerBase() { + this->mINI::operator[](kPlayTimeoutMS) = 10000; + this->mINI::operator[](kMediaTimeoutMS) = 5000; + this->mINI::operator[](kBeatIntervalMS) = 5000; + this->mINI::operator[](kMaxAnalysisMS) = 2000; +} + ///////////////////////////Demuxer////////////////////////////// bool Demuxer::isInited(int analysisMs) { if(_ticker.createdTime() < analysisMs){ diff --git a/src/Player/PlayerBase.h b/src/Player/PlayerBase.h index 7fce8563..7a396be5 100644 --- a/src/Player/PlayerBase.h +++ b/src/Player/PlayerBase.h @@ -56,7 +56,7 @@ public: * @param analysisMs 数据流最大分析时间 单位毫秒 * @return */ - virtual bool isInited(int analysisMs = 2000) { return true; } + virtual bool isInited(int analysisMs) { return true; } /** * 获取全部的Track @@ -103,10 +103,19 @@ public: static const char kRtspUser[]; //rtsp认证用用户密码,可以是明文也可以是md5,md5密码生成方式 md5(username:realm:password) static const char kRtspPwd[]; - //rtsp认证用用户密码是否为md5 + //rtsp认证用用户密码是否为md5类型 static const char kRtspPwdIsMD5[]; + //播放超时时间,默认10,000 毫秒 + static const char kPlayTimeoutMS[]; + //rtp/rtmp包接收超时时间,默认5000秒 + static const char kMediaTimeoutMS[]; + //rtsp/rtmp心跳时间,默认5000毫秒 + static const char kBeatIntervalMS[]; + //Track编码格式探测最大时间,单位毫秒,默认2000 + static const char kMaxAnalysisMS[]; - PlayerBase(){} + + PlayerBase(); virtual ~PlayerBase(){} /** @@ -187,7 +196,7 @@ public: _playResultCB = cb; } - bool isInited(int analysisMs = 2000) override{ + bool isInited(int analysisMs) override{ if (_parser) { return _parser->isInited(analysisMs); } @@ -243,21 +252,20 @@ protected: _playResultCB = nullptr; return; } - //播放成功 - - if(isInited()){ + //播放成功后,我们还必须等待各个Track初始化完毕才能回调告知已经初始化完毕 + if(isInited(INT_MAX)){ //初始化完毕则立即回调 _playResultCB(ex); _playResultCB = nullptr; return; } - //播放成功却未初始化完毕 + //播放成功却未初始化完毕,这个时候不回调汇报播放成功 } - void checkInited(){ + void checkInited(int analysisMs){ if(!_playResultCB){ return; } - if(isInited()){ + if(isInited(analysisMs)){ _playResultCB(SockException(Err_success,"play success")); _playResultCB = nullptr; } @@ -285,7 +293,7 @@ public: * @param analysisMs 数据流最大分析时间 单位毫秒 * @return */ - bool isInited(int analysisMs = 2000) override; + bool isInited(int analysisMs) override; /** * 获取所有可用Track,请在isInited()返回true时调用 diff --git a/src/Rtmp/RtmpPlayer.cpp b/src/Rtmp/RtmpPlayer.cpp index b699506c..500e67e2 100644 --- a/src/Rtmp/RtmpPlayer.cpp +++ b/src/Rtmp/RtmpPlayer.cpp @@ -80,7 +80,7 @@ void RtmpPlayer::play(const char* strUrl) { _strTcUrl = string("rtmp://") + strHost + "/" + _strApp; if (!_strApp.size() || !_strStream.size()) { - _onPlayResult(SockException(Err_other,"rtmp url非法")); + onPlayResult_l(SockException(Err_other,"rtmp url非法")); return; } DebugL << strHost << " " << _strApp << " " << _strStream; @@ -96,27 +96,30 @@ void RtmpPlayer::play(const char* strUrl) { if(!(*this)[PlayerBase::kNetAdapter].empty()){ setNetAdapter((*this)[PlayerBase::kNetAdapter]); } - startConnect(strHost, iPort); -} -void RtmpPlayer::onErr(const SockException &ex){ - _onShutdown(ex); -} -void RtmpPlayer::onConnect(const SockException &err){ - if(err.getErrCode()!=Err_success) { - _onPlayResult(err); - return; - } weak_ptr weakSelf= dynamic_pointer_cast(shared_from_this()); - _pPlayTimer.reset( new Timer(10, [weakSelf]() { + float playTimeOutSec = (*this)[kPlayTimeoutMS].as() / 1000.0; + _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { auto strongSelf=weakSelf.lock(); if(!strongSelf) { return false; } - strongSelf->_onPlayResult(SockException(Err_timeout,"play rtmp timeout")); + strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtmp timeout")); strongSelf->teardown(); return false; },getPoller())); + + startConnect(strHost, iPort , playTimeOutSec); +} +void RtmpPlayer::onErr(const SockException &ex){ + onShutdown_l(ex); +} +void RtmpPlayer::onConnect(const SockException &err){ + if(err.getErrCode()!=Err_success) { + onPlayResult_l(err); + return; + } + weak_ptr weakSelf= dynamic_pointer_cast(shared_from_this()); startClientSession([weakSelf](){ auto strongSelf=weakSelf.lock(); if(!strongSelf) { @@ -130,8 +133,8 @@ void RtmpPlayer::onRecv(const Buffer::Ptr &pBuf){ onParseRtmp(pBuf->data(), pBuf->size()); } catch (exception &e) { SockException ex(Err_other, e.what()); - _onPlayResult(ex); - _onShutdown(ex); + onPlayResult_l(ex); + onShutdown_l(ex); teardown(); } } @@ -210,7 +213,7 @@ inline void RtmpPlayer::send_pause(bool bPause) { }else{ _bPaused = bPause; if(!bPause){ - _onPlayResult(SockException(Err_success, "rtmp resum success")); + onPlayResult_l(SockException(Err_success, "rtmp resum success")); }else{ //暂停播放 _pMediaTimer.reset(); @@ -222,7 +225,7 @@ inline void RtmpPlayer::send_pause(bool bPause) { _pBeatTimer.reset(); if(bPause){ weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pBeatTimer.reset(new Timer(3,[weakSelf](){ + _pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as() / 1000.0,[weakSelf](){ auto strongSelf = weakSelf.lock(); if (!strongSelf){ return false; @@ -279,12 +282,12 @@ void RtmpPlayer::onCmd_onMetaData(AMFDecoder &dec) { if(!onCheckMeta(val)){ throw std::runtime_error("onCheckMeta faied"); } - _onPlayResult(SockException(Err_success,"play rtmp success")); + onPlayResult_l(SockException(Err_success,"play rtmp success")); } void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) { //TraceL << ui32StreamId; - _onShutdown(SockException(Err_other,"rtmp stream dry")); + onShutdown_l(SockException(Err_other,"rtmp stream dry")); } @@ -311,7 +314,7 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) { if (_aNowStampTicker[idx].elapsedTime() > 500) { _aiNowStamp[idx] = chunkData.timeStamp; } - _onMediaData(std::make_shared(std::move(chunkData))); + onMediaData_l(std::make_shared(std::move(chunkData))); } break; default: diff --git a/src/Rtmp/RtmpPlayer.h b/src/Rtmp/RtmpPlayer.h index fef8dc69..364a4482 100644 --- a/src/Rtmp/RtmpPlayer.h +++ b/src/Rtmp/RtmpPlayer.h @@ -58,32 +58,33 @@ protected: uint32_t getProgressMilliSecond() const; void seekToMilliSecond(uint32_t ms); protected: - void _onShutdown(const SockException &ex) { + void onShutdown_l(const SockException &ex) { WarnL << ex.getErrCode() << " " << ex.what(); _pPlayTimer.reset(); _pMediaTimer.reset(); _pBeatTimer.reset(); onShutdown(ex); } - void _onMediaData(const RtmpPacket::Ptr &chunkData) { + void onMediaData_l(const RtmpPacket::Ptr &chunkData) { _mediaTicker.resetTime(); onMediaData(chunkData); } - void _onPlayResult(const SockException &ex) { + void onPlayResult_l(const SockException &ex) { WarnL << ex.getErrCode() << " " << ex.what(); _pPlayTimer.reset(); _pMediaTimer.reset(); if (!ex) { _mediaTicker.resetTime(); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pMediaTimer.reset( new Timer(5, [weakSelf]() { + int timeoutMS = (*this)[kMediaTimeoutMS].as(); + _pMediaTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { auto strongSelf=weakSelf.lock(); if(!strongSelf) { return false; } - if(strongSelf->_mediaTicker.elapsedTime()>10000) { + if(strongSelf->_mediaTicker.elapsedTime()> timeoutMS) { //recv media timeout! - strongSelf->_onShutdown(SockException(Err_timeout,"recv rtmp timeout")); + strongSelf->onShutdown_l(SockException(Err_timeout,"recv rtmp timeout")); strongSelf->teardown(); return false; } diff --git a/src/Rtmp/RtmpPlayerImp.h b/src/Rtmp/RtmpPlayerImp.h index 89c4a48b..c38efd13 100644 --- a/src/Rtmp/RtmpPlayerImp.h +++ b/src/Rtmp/RtmpPlayerImp.h @@ -56,6 +56,10 @@ public: fProgress = MAX(float(0),MIN(fProgress,float(1.0))); seekToMilliSecond(fProgress * getDuration() * 1000); }; + void play(const char* strUrl) override { + _analysisMs = (*this)[PlayerBase::kMaxAnalysisMS].as(); + PlayerImp::play(strUrl); + } private: //派生类回调函数 bool onCheckMeta(AMFValue &val) override { @@ -71,18 +75,19 @@ private: _pRtmpMediaSrc->onWrite(chunkData); } if(!_parser){ + //这个流没有metedata,那么尝试在音视频包里面还原出相关信息 _parser.reset(new RtmpDemuxer()); - _onPlayResult(SockException(Err_success,"play rtmp success")); + onPlayResult_l(SockException(Err_success,"play rtmp success")); } _parser->inputRtmp(chunkData); - checkInited(); + checkInited(_analysisMs); } - private: RtmpMediaSource::Ptr _pRtmpMediaSrc; + int _analysisMs; }; - - + + } /* namespace mediakit */ #endif /* SRC_RTMP_RTMPPLAYERIMP_H_ */ diff --git a/src/Rtmp/RtmpToRtspMediaSource.h b/src/Rtmp/RtmpToRtspMediaSource.h index d0b8d4ea..361ac38e 100644 --- a/src/Rtmp/RtmpToRtspMediaSource.h +++ b/src/Rtmp/RtmpToRtspMediaSource.h @@ -59,15 +59,15 @@ public: } virtual ~RtmpToRtspMediaSource(){} - void onGetMetaData(const AMFValue &_metadata) override { - _rtmpDemuxer = std::make_shared(_metadata); - RtmpMediaSource::onGetMetaData(_metadata); + void onGetMetaData(const AMFValue &metadata) override { + _rtmpDemuxer = std::make_shared(metadata); + RtmpMediaSource::onGetMetaData(metadata); } void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos) override { if(_rtmpDemuxer){ _rtmpDemuxer->inputRtmp(pkt); - if(!_rtspMuxer && _rtmpDemuxer->isInited()){ + if(!_rtspMuxer && _rtmpDemuxer->isInited(2000)){ _rtspMuxer = std::make_shared(getVhost(), getApp(), getId(), diff --git a/src/RtmpMuxer/H264RtmpCodec.cpp b/src/RtmpMuxer/H264RtmpCodec.cpp index 1c29d4dc..18d8336d 100644 --- a/src/RtmpMuxer/H264RtmpCodec.cpp +++ b/src/RtmpMuxer/H264RtmpCodec.cpp @@ -54,7 +54,7 @@ bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) { return false; } - if (_sps.size() && pkt->strBuf.size() > 9) { + if (pkt->strBuf.size() > 9) { uint32_t iTotalLen = pkt->strBuf.size(); uint32_t iOffset = 5; uint8_t *cts_ptr = (uint8_t *) (pkt->strBuf.data() + 2); @@ -81,9 +81,15 @@ inline void H264RtmpDecoder::onGetH264_l(const char* pcData, int iLen, uint32_t switch (H264_TYPE(pcData[0])) { case H264Frame::NAL_IDR: { //I frame - onGetH264(_sps.data(), _sps.length(), dts , pts); - onGetH264(_pps.data(), _pps.length(), dts , pts); + if(_sps.length()){ + onGetH264(_sps.data(), _sps.length(), dts , pts); + } + if(_pps.length()){ + onGetH264(_pps.data(), _pps.length(), dts , pts); + } + onGetH264(pcData, iLen, dts , pts); } + break; case H264Frame::NAL_B_P: { //I or P or B frame onGetH264(pcData, iLen, dts , pts); diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 08f92b97..984fefe0 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -133,7 +133,20 @@ void RtspPlayer::play(const char* strUrl, const char *strUser, const char *strPw if(!(*this)[PlayerBase::kNetAdapter].empty()){ setNetAdapter((*this)[PlayerBase::kNetAdapter]); } - startConnect(ip.data(), port); + + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + float playTimeOutSec = (*this)[kPlayTimeoutMS].as() / 1000.0; + _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { + auto strongSelf=weakSelf.lock(); + if(!strongSelf) { + return false; + } + strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout")); + strongSelf->teardown(); + return false; + },getPoller())); + + startConnect(ip.data(), port , playTimeOutSec); } void RtspPlayer::onConnect(const SockException &err){ if(err.getErrCode()!=Err_success) { @@ -143,17 +156,6 @@ void RtspPlayer::onConnect(const SockException &err){ } sendDescribe(); - - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pPlayTimer.reset( new Timer(10, [weakSelf]() { - auto strongSelf=weakSelf.lock(); - if(!strongSelf) { - return false; - } - strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout")); - strongSelf->teardown(); - return false; - },getPoller())); } void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) { @@ -346,7 +348,7 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) } /////////////////////////心跳///////////////////////////////// weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pBeatTimer.reset(new Timer(5, [weakSelf](){ + _pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as() / 1000.0, [weakSelf](){ auto strongSelf = weakSelf.lock(); if (!strongSelf){ return false; @@ -591,12 +593,13 @@ void RtspPlayer::onPlayResult_l(const SockException &ex) { if (!ex) { _rtpTicker.resetTime(); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pRtpTimer.reset( new Timer(5, [weakSelf]() { + int timeoutMS = (*this)[kMediaTimeoutMS].as(); + _pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { auto strongSelf=weakSelf.lock(); if(!strongSelf) { return false; } - if(strongSelf->_rtpTicker.elapsedTime()>10000) { + if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) { //recv rtp timeout! strongSelf->onShutdown_l(SockException(Err_timeout,"recv rtp timeout")); strongSelf->teardown(); diff --git a/src/Rtsp/RtspPlayerImp.h b/src/Rtsp/RtspPlayerImp.h index 54c387e2..34bad2cd 100644 --- a/src/Rtsp/RtspPlayerImp.h +++ b/src/Rtsp/RtspPlayerImp.h @@ -74,10 +74,15 @@ private: _pRtspMediaSrc->onWrite(rtppt,true); } _parser->inputRtp(rtppt); - checkInited(); + + //由于我们重载isInited方法强制认为一旦获取sdp那么就初始化Track成功, + //所以我们不需要在后续检验是否初始化成功 + //checkInited(0); } - bool isInited(int analysisMs = 2000) override{ + bool isInited(int analysisMs) override{ + //rtsp是通过sdp来完成track的初始化的,所以我们强制返回true, + //认为已经初始化完毕,这样可以提高rtsp打开速度 return true; } private: diff --git a/src/Rtsp/RtspToRtmpMediaSource.h b/src/Rtsp/RtspToRtmpMediaSource.h index ed55ccb0..61ea27e8 100644 --- a/src/Rtsp/RtspToRtmpMediaSource.h +++ b/src/Rtsp/RtspToRtmpMediaSource.h @@ -61,7 +61,7 @@ public: virtual void onWrite(const RtpPacket::Ptr &rtp, bool bKeyPos) override { if (_rtspDemuxer) { bKeyPos = _rtspDemuxer->inputRtp(rtp); - if (!_rtmpMuxer && _rtspDemuxer->isInited()) { + if (!_rtmpMuxer && _rtspDemuxer->isInited(2000)) { _rtmpMuxer = std::make_shared(getVhost(), getApp(), getId(),