diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index fe572323..936d3c05 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit fe572323b10d72819a4d69b326dd70e73c7bf1a6 +Subproject commit 936d3c05b183cba279bb348f8eac9eca0cc810c2 diff --git a/src/Extension/H264.h b/src/Extension/H264.h index 853c7f60..400f5474 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -128,13 +128,14 @@ public: * 一个复合帧可以通过无内存拷贝的方式切割成多个H264FrameSubFrame * 提供该类的目的是切换复合帧时防止内存拷贝,提高性能 */ -class H264FrameSubFrame : public H264FrameNoCacheAble{ +template +class FrameInternal : public Parent{ public: - typedef std::shared_ptr Ptr; - H264FrameSubFrame(const Frame::Ptr &parent_frame, - char *ptr, - uint32_t size, - int prefixeSize) : H264FrameNoCacheAble(ptr,size,parent_frame->dts(),parent_frame->pts(),prefixeSize){ + typedef std::shared_ptr Ptr; + FrameInternal(const Frame::Ptr &parent_frame, + char *ptr, + uint32_t size, + int prefixeSize) : Parent(ptr,size,parent_frame->dts(),parent_frame->pts(),prefixeSize){ _parent_frame = parent_frame; } bool cacheAble() const override { @@ -144,6 +145,8 @@ private: Frame::Ptr _parent_frame; }; +typedef FrameInternal H264FrameInternal; + /** * 264视频通道 */ @@ -243,21 +246,21 @@ public: splitH264(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(), [&](const char *ptr, int len){ - if(first_frame){ - H264FrameSubFrame::Ptr sub_frame = std::make_shared(frame, - frame->data(), - len + frame->prefixSize(), - frame->prefixSize()); - inputFrame_l(sub_frame); - first_frame = false; - }else{ - H264FrameSubFrame::Ptr sub_frame = std::make_shared(frame, - (char *)ptr, - len , - 3); - inputFrame_l(sub_frame); - } - }); + if(first_frame){ + H264FrameInternal::Ptr sub_frame = std::make_shared(frame, + frame->data(), + len + frame->prefixSize(), + frame->prefixSize()); + inputFrame_l(sub_frame); + first_frame = false; + }else{ + H264FrameInternal::Ptr sub_frame = std::make_shared(frame, + (char *)ptr, + len , + 3); + inputFrame_l(sub_frame); + } + }); } else{ inputFrame_l(frame); } diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index 8f735fe3..9ff10e27 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -51,6 +51,8 @@ bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) { //缓存sps pps,后续插入到I帧之前 _sps = pkt->getH264SPS(); _pps = pkt->getH264PPS(); + onGetH264(_sps.data(), _sps.size(), pkt->timeStamp , pkt->timeStamp); + onGetH264(_pps.data(), _pps.size(), pkt->timeStamp , pkt->timeStamp); return false; } @@ -69,44 +71,13 @@ bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) { if(iFrameLen + iOffset > iTotalLen){ break; } - onGetH264_l(pkt->strBuf.data() + iOffset, iFrameLen, pkt->timeStamp , pts); + onGetH264(pkt->strBuf.data() + iOffset, iFrameLen, pkt->timeStamp , pts); iOffset += iFrameLen; } } return pkt->isVideoKeyFrame(); } - -inline void H264RtmpDecoder::onGetH264_l(const char* pcData, int iLen, uint32_t dts,uint32_t pts) { - switch (H264_TYPE(pcData[0])) { - case H264Frame::NAL_IDR: { - //I frame - 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); - } - break; - case H264Frame::NAL_SPS: { - _sps.assign(pcData, iLen); - } - break; - case H264Frame::NAL_PPS:{ - _pps.assign(pcData, iLen); - } - break; - default: - break; - } -} inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t dts,uint32_t pts) { #if 1 _h264frame->type = H264_TYPE(pcData[0]); diff --git a/src/Extension/H264Rtmp.h b/src/Extension/H264Rtmp.h index e4bd4bbe..ed015e76 100644 --- a/src/Extension/H264Rtmp.h +++ b/src/Extension/H264Rtmp.h @@ -60,7 +60,6 @@ public: } protected: bool decodeRtmp(const RtmpPacket::Ptr &Rtmp); - void onGetH264_l(const char *pcData, int iLen, uint32_t dts,uint32_t pts); void onGetH264(const char *pcData, int iLen, uint32_t dts,uint32_t pts); H264Frame::Ptr obtainFrame(); protected: diff --git a/src/Extension/H265.h b/src/Extension/H265.h index 9ba82458..cd367b66 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -30,6 +30,7 @@ #include "Frame.h" #include "Track.h" #include "Util/base64.h" +#include "H264.h" using namespace toolkit; #define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f) @@ -147,6 +148,7 @@ public: } }; +typedef FrameInternal H265FrameInternal; /** * 265视频通道 @@ -209,11 +211,38 @@ public: } + /** + * 输入数据帧,并获取sps pps + * @param frame 数据帧 + */ + void inputFrame(const Frame::Ptr &frame) override{ + bool first_frame = true; + splitH264(frame->data() + frame->prefixSize(), + frame->size() - frame->prefixSize(), + [&](const char *ptr, int len){ + if(first_frame){ + H265FrameInternal::Ptr sub_frame = std::make_shared(frame, + frame->data(), + len + frame->prefixSize(), + frame->prefixSize()); + inputFrame_l(sub_frame); + first_frame = false; + }else{ + H265FrameInternal::Ptr sub_frame = std::make_shared(frame, + (char *)ptr, + len , + 3); + inputFrame_l(sub_frame); + } + }); + } + +private: /** * 输入数据帧,并获取sps pps * @param frame 数据帧 */ - void inputFrame(const Frame::Ptr &frame) override { + void inputFrame_l(const Frame::Ptr &frame) { int type = H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0]); if (H265Frame::isKeyFrame(type)) { insertConfigFrame(frame); @@ -250,7 +279,7 @@ public: break; } } -private: + Track::Ptr clone() override { return std::make_shared::type>(*this); } diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index 24d83c70..a32e0506 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -134,7 +134,10 @@ int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) { return 0; } - //默认后面数据不是content而是header + //跨域 + _origin = _parser["Origin"]; + + //默认后面数据不是content而是header int64_t content_len = 0; auto &fun = it->second; try { @@ -775,6 +778,11 @@ inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iC if(iContentSize > 0){ headerOut.emplace("Content-Length", StrPrinter< reqCnt); - auto Origin = _parser["Origin"]; /////////////////////异步回复Invoker/////////////////////////////// weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - HttpResponseInvoker invoker = [weakSelf,bClose,Origin](const string &codeOut, const KeyValue &headerOut, const string &contentOut){ + HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const string &contentOut){ auto strongSelf = weakSelf.lock(); if(!strongSelf) { return; } - strongSelf->async([weakSelf,bClose,codeOut,headerOut,contentOut,Origin]() { + strongSelf->async([weakSelf,bClose,codeOut,headerOut,contentOut]() { auto strongSelf = weakSelf.lock(); if(!strongSelf) { return; } - strongSelf->responseDelay(Origin,bClose,codeOut,headerOut,contentOut); + strongSelf->responseDelay(bClose,codeOut,headerOut,contentOut); if(bClose){ strongSelf->shutdown(SockException(Err_shutdown,"Connection: close")); } @@ -906,19 +913,15 @@ inline void HttpSession::Handle_Req_POST(int64_t &content_len) { } //有后续content数据要处理,暂时不关闭连接 } -void HttpSession::responseDelay(const string &Origin,bool bClose, - const string &codeOut,const KeyValue &headerOut, +void HttpSession::responseDelay(bool bClose, + const string &codeOut, + const KeyValue &headerOut, const string &contentOut){ if(codeOut.empty()){ sendNotFound(bClose); return; } - auto headerOther=makeHttpHeader(bClose,contentOut.size(),"text/plain"); - if(!Origin.empty()){ - headerOther["Access-Control-Allow-Origin"] = Origin; - headerOther["Access-Control-Allow-Credentials"] = "true"; - } - + auto headerOther = makeHttpHeader(bClose,contentOut.size(),"text/plain"); for (auto &pr : headerOther){ //添加默认http头,默认http头不能覆盖用户自定义的头 const_cast(headerOut).emplace(pr.first,pr.second); diff --git a/src/Http/HttpSession.h b/src/Http/HttpSession.h index f710c4c3..9cd4bfbe 100644 --- a/src/Http/HttpSession.h +++ b/src/Http/HttpSession.h @@ -111,9 +111,8 @@ private: inline void urlDecode(Parser &parser); inline void sendNotFound(bool bClose); inline void sendResponse(const char *pcStatus,const KeyValue &header,const string &strContent); - inline static KeyValue makeHttpHeader(bool bClose=false,int64_t iContentSize=-1,const char *pcContentType="text/html"); - void responseDelay(const string &Origin, - bool bClose, + inline KeyValue makeHttpHeader(bool bClose=false,int64_t iContentSize=-1,const char *pcContentType="text/html"); + void responseDelay(bool bClose, const string &codeOut, const KeyValue &headerOut, const string &contentOut); @@ -139,6 +138,7 @@ private: */ inline string getClientUid(); private: + string _origin; Parser _parser; Ticker _ticker; uint32_t _iReqCnt = 0; diff --git a/src/Player/PlayerBase.h b/src/Player/PlayerBase.h index cb115ee7..50330b06 100644 --- a/src/Player/PlayerBase.h +++ b/src/Player/PlayerBase.h @@ -245,14 +245,9 @@ protected: _playResultCB = nullptr; return; } - //播放成功后,我们还必须等待各个Track初始化完毕才能回调告知已经初始化完毕 - if(isInited(0xFFFF)){ - //初始化完毕则立即回调 - _playResultCB(ex); - _playResultCB = nullptr; - return; - } - //播放成功却未初始化完毕,这个时候不回调汇报播放成功 + //播放成功 + _playResultCB(ex); + _playResultCB = nullptr; } void onResume() override{ @@ -260,16 +255,6 @@ protected: _resumeCB(); } } - - void checkInited(int analysisMs){ - if(!_playResultCB){ - return; - } - if(isInited(analysisMs)){ - _playResultCB(SockException(Err_success,"play success")); - _playResultCB = nullptr; - } - } protected: function _shutdownCB; function _playResultCB; diff --git a/src/Rtmp/RtmpPlayer.cpp b/src/Rtmp/RtmpPlayer.cpp index b22a2885..75ce6593 100644 --- a/src/Rtmp/RtmpPlayer.cpp +++ b/src/Rtmp/RtmpPlayer.cpp @@ -321,7 +321,6 @@ void RtmpPlayer::onCmd_onMetaData(AMFDecoder &dec) { if(!onCheckMeta(val)){ throw std::runtime_error("onCheckMeta faied"); } - onPlayResult_l(SockException(Err_success,"play rtmp success")); } void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) { @@ -329,6 +328,25 @@ void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) { onPlayResult_l(SockException(Err_other,"rtmp stream dry")); } +void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) { + _mediaTicker.resetTime(); + if(!_pPlayTimer){ + //已经触发了onPlayResult事件,直接触发onMediaData事件 + onMediaData(packet); + return; + } + + if(packet->isCfgFrame()){ + //输入配置帧以便初始化完成各个track + onMediaData(packet); + }else{ + //先触发onPlayResult事件,这个时候解码器才能初始化完毕 + onPlayResult_l(SockException(Err_success,"play rtmp success")); + //触发onPlayResult事件后,再把帧数据输入到解码器 + onMediaData(packet); + } +} + void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) { switch (chunkData.typeId) { @@ -351,6 +369,7 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) { case MSG_VIDEO: { auto idx = chunkData.typeId%2; if (_aNowStampTicker[idx].elapsedTime() > 500) { + //计算播放进度时间轴用 _aiNowStamp[idx] = chunkData.timeStamp; } onMediaData_l(std::make_shared(std::move(chunkData))); diff --git a/src/Rtmp/RtmpPlayer.h b/src/Rtmp/RtmpPlayer.h index 66e8ae66..142ab5fb 100644 --- a/src/Rtmp/RtmpPlayer.h +++ b/src/Rtmp/RtmpPlayer.h @@ -60,11 +60,7 @@ protected: uint32_t getProgressMilliSecond() const; void seekToMilliSecond(uint32_t ms); protected: - void onMediaData_l(const RtmpPacket::Ptr &chunkData) { - _mediaTicker.resetTime(); - onMediaData(chunkData); - } - + void onMediaData_l(const RtmpPacket::Ptr &chunkData); void onPlayResult_l(const SockException &ex); //for Tcpclient @@ -97,7 +93,7 @@ protected: inline void send_createStream(); inline void send_play(); inline void send_pause(bool bPause); - +private: string _strApp; string _strStream; string _strTcUrl; diff --git a/src/Rtmp/RtmpPlayerImp.h b/src/Rtmp/RtmpPlayerImp.h index 6774e076..fb8064dd 100644 --- a/src/Rtmp/RtmpPlayerImp.h +++ b/src/Rtmp/RtmpPlayerImp.h @@ -58,7 +58,6 @@ public: seekToMilliSecond(fProgress * getDuration() * 1000); }; void play(const string &strUrl) override { - _analysisMs = (*this)[kMaxAnalysisMS].as(); PlayerImp::play(strUrl); } private: @@ -76,16 +75,13 @@ private: _pRtmpMediaSrc->onWrite(chunkData); } if(!_parser){ - //这个流没有metedata,那么尝试在音视频包里面还原出相关信息 + //这个流没有metedata _parser.reset(new RtmpDemuxer()); - onPlayResult_l(SockException(Err_success,"play rtmp success")); } _parser->inputRtmp(chunkData); - checkInited(_analysisMs); } private: RtmpMediaSource::Ptr _pRtmpMediaSrc; - int _analysisMs; }; diff --git a/tests/test_player.cpp b/tests/test_player.cpp index f0ee2dad..6ddfb256 100644 --- a/tests/test_player.cpp +++ b/tests/test_player.cpp @@ -39,9 +39,9 @@ using namespace std; using namespace toolkit; using namespace mediakit; -std::string Utf8ToGbk(std::string src_str) -{ #ifdef WIN32 +std::string Utf8ToGbk(std::string src_str){ + int len = MultiByteToWideChar(CP_UTF8, 0, src_str.c_str(), -1, NULL, 0); wchar_t* wszGBK = new wchar_t[len + 1]; memset(wszGBK, 0, len * 2 + 2); @@ -54,9 +54,6 @@ std::string Utf8ToGbk(std::string src_str) if (wszGBK) delete[] wszGBK; if (szGBK) delete[] szGBK; return strTemp; -#else - return src_str; -#endif } class log4Channel : public LogChannel { @@ -75,6 +72,9 @@ public: printf("%s %s\n", logContext->_function, Utf8ToGbk(logContext->str()).c_str()); } }; +#else +typedef ConsoleChannel log4Channel; +#endif #ifdef WIN32 #include