From 57c5d2963af6f72383eb2622e174fe95b13b4549 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jan 2020 12:14:27 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E4=BC=98=E5=8C=96DevChannel=E5=86=85?= =?UTF-8?q?=E5=AD=98=E6=8B=B7=E8=B4=9D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Device.cpp | 16 ++++++++++++++-- src/Extension/AAC.h | 1 - src/Extension/AACRtp.cpp | 1 - src/Player/PlayerProxy.cpp | 16 +++++++++++++--- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index a04dba72..450ed9e3 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -104,7 +104,13 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32 } else { prefixeSize = 0; } - inputFrame(std::make_shared((char *)pcData,iDataLen,dts,pts,prefixeSize)); + + H264Frame::Ptr frame = std::make_shared(); + frame->timeStamp = dts; + frame->ptsStamp = pts; + frame->buffer.assign("\x00\x00\x00\x01",4); + frame->buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + inputFrame(frame); } void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) { @@ -122,7 +128,13 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32 } else { prefixeSize = 0; } - inputFrame(std::make_shared((char *)pcData,iDataLen,dts,pts,prefixeSize)); + + H265Frame::Ptr frame = std::make_shared(); + frame->timeStamp = dts; + frame->ptsStamp = pts; + frame->buffer.assign("\x00\x00\x00\x01",4); + frame->buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + inputFrame(frame); } void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) { diff --git a/src/Extension/AAC.h b/src/Extension/AAC.h index fe78509e..063756f6 100644 --- a/src/Extension/AAC.h +++ b/src/Extension/AAC.h @@ -104,7 +104,6 @@ public: //表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据) unsigned int no_raw_data_blocks_in_frame; //2 uimsfb unsigned char buffer[2 * 1024 + 7]; - uint16_t sequence; uint32_t timeStamp; uint32_t iPrefixSize = 7; } ; diff --git a/src/Extension/AACRtp.cpp b/src/Extension/AACRtp.cpp index 2f001959..7b436fb0 100644 --- a/src/Extension/AACRtp.cpp +++ b/src/Extension/AACRtp.cpp @@ -149,7 +149,6 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) { memcpy(_adts->buffer + _adts->aac_frame_length, rtp_packet_payload + next_aac_payload_offset, cur_aac_payload_len); _adts->aac_frame_length += (cur_aac_payload_len); if (rtppack->mark == true) { - _adts->sequence = rtppack->sequence; _adts->timeStamp = rtppack->timeStamp; writeAdtsHeader(*_adts, _adts->buffer); onGetAAC(_adts); diff --git a/src/Player/PlayerProxy.cpp b/src/Player/PlayerProxy.cpp index 5badcce0..250ea932 100644 --- a/src/Player/PlayerProxy.cpp +++ b/src/Player/PlayerProxy.cpp @@ -222,13 +222,23 @@ public: auto iAudioIndex = frame->stamp() / MUTE_ADTS_DATA_MS; if(_iAudioIndex != iAudioIndex){ _iAudioIndex = iAudioIndex; - auto aacFrame = std::make_shared((char *)MUTE_ADTS_DATA, - MUTE_ADTS_DATA_LEN, - _iAudioIndex * MUTE_ADTS_DATA_MS); + auto aacFrame = std::make_shared((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS); FrameDispatcher::inputFrame(aacFrame); } } } + +private: + class AACFrameCacheAble : public AACFrameNoCacheAble{ + public: + template + AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward(args)...){}; + virtual ~AACFrameCacheAble() = default; + + bool cacheAble() const override { + return true; + } + }; private: int _iAudioIndex = 0; }; From 5d2864cff20fd742f633e80690f1006d7989ab4a Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jan 2020 12:15:59 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E4=BC=98=E5=8C=96DevChannel=E5=86=85?= =?UTF-8?q?=E5=AD=98=E6=8B=B7=E8=B4=9D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Device.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 450ed9e3..39a76825 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -110,6 +110,7 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32 frame->ptsStamp = pts; frame->buffer.assign("\x00\x00\x00\x01",4); frame->buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->iPrefixSize = 4; inputFrame(frame); } @@ -134,6 +135,7 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32 frame->ptsStamp = pts; frame->buffer.assign("\x00\x00\x00\x01",4); frame->buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->iPrefixSize = 4; inputFrame(frame); } From ab32ca39a944dae4c1f74ca876273c4de2b77476 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jan 2020 14:00:53 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtmp/RtmpProtocol.cpp | 10 +++++----- src/Rtmp/RtmpSession.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Rtmp/RtmpProtocol.cpp b/src/Rtmp/RtmpProtocol.cpp index ad21351f..4de21a47 100644 --- a/src/Rtmp/RtmpProtocol.cpp +++ b/src/Rtmp/RtmpProtocol.cpp @@ -332,7 +332,7 @@ void RtmpProtocol::handle_C0C1() { //complex handsharke handle_C1_complex(); #else - WarnL << "未打开ENABLE_OPENSSL宏,复杂握手采用简单方式处理!"; + WarnL << "未打开ENABLE_OPENSSL宏,复杂握手采用简单方式处理,flash播放器可能无法播放!"; handle_C1_simple(); #endif//ENABLE_OPENSSL } @@ -372,10 +372,10 @@ void RtmpProtocol::handle_C1_complex(){ check_C1_Digest(digest,c1_joined); send_complex_S0S1S2(0,digest); - InfoL << "schema0"; +// InfoL << "schema0"; }catch(std::exception &ex){ //貌似flash从来都不用schema1 - WarnL << "try rtmp complex schema0 failed:" << ex.what(); +// WarnL << "try rtmp complex schema0 failed:" << ex.what(); try{ /* c1s1 schema1 time: 4bytes @@ -389,9 +389,9 @@ void RtmpProtocol::handle_C1_complex(){ check_C1_Digest(digest,c1_joined); send_complex_S0S1S2(1,digest); - InfoL << "schema1"; +// InfoL << "schema1"; }catch(std::exception &ex){ - WarnL << "try rtmp complex schema1 failed:" << ex.what(); +// WarnL << "try rtmp complex schema1 failed:" << ex.what(); handle_C1_simple(); } } diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index e7e93688..bf3aa217 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -452,7 +452,7 @@ void RtmpSession::onProcessCmd(AMFDecoder &dec) { std::string method = dec.load(); auto it = s_cmd_functions.find(method); if (it == s_cmd_functions.end()) { - TraceP(this) << "can not support cmd:" << method; +// TraceP(this) << "can not support cmd:" << method; return; } _dNowReqID = dec.load(); From 653132b38cdd59409c3bc067f57c4352b840afb8 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jan 2020 14:03:56 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtmp/RtmpSession.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index bf3aa217..6f067fea 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -473,10 +473,11 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) { case MSG_DATA3: { AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0); std::string type = dec.load(); - TraceP(this) << "notify:" << type; if (type == "@setDataFrame") { setMetaData(dec); - } + }else{ + TraceP(this) << "unknown notify:" << type; + } } break; case MSG_AUDIO: From bad036fdac2f1a48e99987d8a8f1ff298189b5e5 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 9 Jan 2020 10:06:30 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=87=B4=E8=B0=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 38731a39..c62cf3c8 100644 --- a/README.md +++ b/README.md @@ -376,6 +376,25 @@ git submodule update --init - 2、如果您的问题还没解决,可以提issue. - 3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提. - 4、QQ私聊一般不接受无偿技术咨询和支持(谈谈人生理想还是可以的😂),毕竟精力有限,谢谢理解. + +## 致谢 +感谢以下各位对本项目包括但不限于代码贡献、问题反馈、资金捐赠等各种方式的支持!以下排名不分先后: + +[老陈](https://github.com/ireader) +[Gemfield](https://github.com/gemfield) +[南冠彤](https://github.com/nanguantong2) +[凹凸慢](https://github.com/tsingeye) +[chenxiaolei](https://github.com/chenxiaolei) +[史前小虫](https://github.com/zqsong) +[清涩绿茶](https://github.com/baiyfcu) +[3503207480](https://github.com/3503207480) +[DroidChow](https://github.com/DroidChow) +[阿塞](https://github.com/HuoQiShuai) +[火宣](https://github.com/ChinaCCF) +[γ瑞γミ](https://github.com/JerryLinGd) +[linkingvision](https://www.linkingvision.com/) +[茄子](https://github.com/taotaobujue2008) +[好心情](<409257224@qq.com>) ## 捐赠 欢迎捐赠以便更好的推动项目的发展,谢谢您的支持! From 835d6bd9b590ea46e757f6c002fa101149b621eb Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 9 Jan 2020 17:03:29 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E5=85=81=E8=AE=B8=E6=9C=AC=E6=9C=BA?= =?UTF-8?q?=E5=92=8C=E8=B6=85=E7=BA=A7=E7=94=A8=E6=88=B7=E4=BB=BB=E6=84=8F?= =?UTF-8?q?=E8=AE=BF=E9=97=AEhttp=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebHook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/WebHook.cpp b/server/WebHook.cpp index 4eb54eec..e2e7824e 100644 --- a/server/WebHook.cpp +++ b/server/WebHook.cpp @@ -438,7 +438,7 @@ void installWebHook(){ //如果没有url参数,客户端又不支持cookie,那么会根据ip和端口追踪用户 //追踪用户的目的是为了缓存上次鉴权结果,减少鉴权次数,提高性能 NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastHttpAccess,[](BroadcastHttpAccessArgs){ - if(sender.get_peer_ip() == "127.0.0.1" && parser.Params() == hook_adminparams){ + if(sender.get_peer_ip() == "127.0.0.1" || parser.Params() == hook_adminparams){ //如果是本机或超级管理员访问,那么不做访问鉴权;权限有效期1个小时 invoker("","",60 * 60); return; From 8acb6e209358e2fe4a77dd51384928567bba4bbc Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 9 Jan 2020 17:17:48 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/include/mk_media.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/include/mk_media.h b/api/include/mk_media.h index d8162f6e..16516de4 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -87,7 +87,7 @@ API_EXPORT void API_CALL mk_media_init_aac(mk_media ctx, int channel, int sample * @param data 单帧H264数据 * @param len 单帧H264数据字节数 * @param dts 解码时间戳,单位毫秒 - * @param dts 播放时间戳,单位毫秒 + * @param pts 播放时间戳,单位毫秒 */ API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len, uint32_t dts, uint32_t pts); @@ -97,7 +97,7 @@ API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len, * @param data 单帧H265数据 * @param len 单帧H265数据字节数 * @param dts 解码时间戳,单位毫秒 - * @param dts 播放时间戳,单位毫秒 + * @param pts 播放时间戳,单位毫秒 */ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len, uint32_t dts, uint32_t pts); From db146406c31a3e8d618585908605f4f148d4d821 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Fri, 10 Jan 2020 15:29:21 +0800 Subject: [PATCH 08/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dgcc4.85=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E7=BC=96=E8=AF=91=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Http/WebSocketClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/WebSocketClient.h b/src/Http/WebSocketClient.h index 85051fc3..e3d215a7 100644 --- a/src/Http/WebSocketClient.h +++ b/src/Http/WebSocketClient.h @@ -303,7 +303,7 @@ private: //拦截websocket数据接收 _onRecv = [this](const Buffer::Ptr &pBuf){ //解析websocket数据包 - WebSocketSplitter::decode((uint8_t*)pBuf->data(),pBuf->size()); + this->WebSocketSplitter::decode((uint8_t*)pBuf->data(),pBuf->size()); }; return; } From 66ec67bfb9c752837496c83277c1f347f8ef5bdd Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Mon, 13 Jan 2020 11:51:29 +0800 Subject: [PATCH 09/15] =?UTF-8?q?1=E3=80=81=E4=BF=AE=E5=A4=8D=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=9A=84rtmp=E6=97=A0=E6=B3=95=E8=A2=ABflash=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E7=9A=84=E9=97=AE=E9=A2=98=202=E3=80=81=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DRTSP=E6=9C=89B=E5=B8=A7=E6=97=B6=EF=BC=8C=E7=9B=B8?= =?UTF-8?q?=E5=AF=B9=E6=97=B6=E9=97=B4=E6=88=B3=E8=AE=A1=E7=AE=97=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Stamp.cpp | 14 ++++++++------ src/Extension/H264.h | 1 + src/Extension/H264Rtmp.cpp | 6 +++++- src/Record/MP4Reader.cpp | 12 +++++++----- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index 9d2c2d45..7330de21 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -27,25 +27,27 @@ #include "Stamp.h" #define MAX_DELTA_STAMP 300 +#define ABS(x) ((x) > 0 ? (x) : (-x)) namespace mediakit { int64_t DeltaStamp::deltaStamp(int64_t stamp) { if(!_last_stamp){ //第一次计算时间戳增量,时间戳增量为0 - _last_stamp = stamp; + if(stamp){ + _last_stamp = stamp; + } return 0; } int64_t ret = stamp - _last_stamp; - if(ret >= 0){ - //时间戳增量为正,返回之 + if(ABS(ret) < MAX_DELTA_STAMP){ + //时间戳变化不明显 _last_stamp = stamp; - //在直播情况下,时间戳增量不得大于MAX_DELTA_STAMP - return ret < MAX_DELTA_STAMP ? ret : (_playback ? ret : 0); + return ret; } - //时间戳增量为负,说明时间戳回环了或回退了 + //时间戳变化太明显,可能回环了或者seek了 _last_stamp = stamp; return _playback ? ret : 0; } diff --git a/src/Extension/H264.h b/src/Extension/H264.h index 4bb8ea1c..3ffb058d 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -49,6 +49,7 @@ public: NAL_SPS = 7, NAL_PPS = 8, NAL_IDR = 5, + NAL_SEI = 6, } NalType; char *data() const override{ diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index 3ab77554..9ee877e7 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -140,6 +140,10 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { } } + if(type == H264Frame::NAL_SEI){ + return; + } + if(_lastPacket && _lastPacket->timeStamp != frame->stamp()) { RtmpCodec::inputRtmp(_lastPacket, _lastPacket->isVideoKeyFrame()); _lastPacket = nullptr; @@ -149,7 +153,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { //I or P or B frame int8_t flags = 7; //h.264 bool is_config = false; - flags |= ((frame->keyFrame() ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); + flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); _lastPacket = ResourcePoolHelper::obtainObj(); _lastPacket->strBuf.clear(); diff --git a/src/Record/MP4Reader.cpp b/src/Record/MP4Reader.cpp index 9bf20525..020fa6bc 100644 --- a/src/Record/MP4Reader.cpp +++ b/src/Record/MP4Reader.cpp @@ -225,8 +225,10 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) { uint32_t numBytes = _video_sample_max_size; MP4Duration pRenderingOffset; if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){ - if (!justSeekSyncFrame) { - uint32_t iOffset = 0; + if (!justSeekSyncFrame) { + uint32_t dts = (double) _video_ms * iIdx / _video_num_samples; + uint32_t pts = dts + pRenderingOffset / 90; + uint32_t iOffset = 0; while (iOffset < numBytes) { uint32_t iFrameLen; memcpy(&iFrameLen,pBytes + iOffset,4); @@ -235,8 +237,7 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) { break; } memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4); - uint32_t dts = (double) _video_ms * iIdx / _video_num_samples; - writeH264(pBytes + iOffset, iFrameLen + 4, dts, dts + pRenderingOffset / 90); + writeH264(pBytes + iOffset, iFrameLen + 4, dts, pts); iOffset += (iFrameLen + 4); } }else if(_bSyncSample){ @@ -260,9 +261,10 @@ inline bool MP4Reader::readAudioSample(int iTimeInc,bool justSeekSyncFrame) { uint8_t *pBytes = _adts.buffer + 7; if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){ if (!justSeekSyncFrame) { + uint32_t dts = (double) _audio_ms * i / _audio_num_samples; _adts.aac_frame_length = 7 + numBytes; writeAdtsHeader(_adts, _adts.buffer); - writeAAC(_adts.buffer, _adts.aac_frame_length, (double) _audio_ms * i / _audio_num_samples); + writeAAC(_adts.buffer, _adts.aac_frame_length, dts); } }else{ ErrorL << "读取音频失败:" << i+ 1; From b55db11de314b2321213275b2d01cf1900b7f5f0 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Mon, 13 Jan 2020 15:48:55 +0800 Subject: [PATCH 10/15] =?UTF-8?q?=E8=A7=A3=E5=86=B3rtmp=E8=BF=87=E6=97=A9?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/MediaSink.cpp | 82 ++++++++++++++++++++++++-------------- src/Common/MediaSink.h | 3 +- src/Common/Stamp.cpp | 5 ++- src/Rtmp/RtmpMediaSource.h | 11 ++--- src/Rtmp/RtmpPlayerImp.h | 6 +++ src/Rtmp/RtmpSession.cpp | 6 +++ src/Rtmp/RtmpSession.h | 1 + 7 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/Common/MediaSink.cpp b/src/Common/MediaSink.cpp index 64049dc5..eb7cf533 100644 --- a/src/Common/MediaSink.cpp +++ b/src/Common/MediaSink.cpp @@ -26,7 +26,11 @@ #include "MediaSink.h" //最多等待未初始化的Track 10秒,超时之后会忽略未初始化的Track -#define MAX_WAIT_MS 10000 +#define MAX_WAIT_MS_READY 10000 + +//如果添加Track,最多等待3秒 +#define MAX_WAIT_MS_ADD_TRACK 3000 + namespace mediakit{ @@ -34,23 +38,16 @@ void MediaSink::addTrack(const Track::Ptr &track_in) { lock_guard lck(_mtx); //克隆Track,只拷贝其数据,不拷贝其数据转发关系 auto track = track_in->clone(); - auto codec_id = track->getCodecId(); _track_map[codec_id] = track; - auto lam = [this,track](){ + _allTrackReady = false; + _trackReadyCallback[codec_id] = [this, track]() { onTrackReady(track); }; - if(track->ready()){ - lam(); - }else{ - _anyTrackUnReady = true; - _allTrackReady = false; - _trackReadyCallback[codec_id] = lam; - _ticker.resetTime(); - } + _ticker.resetTime(); - track->addDelegate(std::make_shared([this](const Frame::Ptr &frame){ - if(!_anyTrackUnReady){ + track->addDelegate(std::make_shared([this](const Frame::Ptr &frame) { + if (_allTrackReady) { onTrackFrame(frame); } })); @@ -58,7 +55,6 @@ void MediaSink::addTrack(const Track::Ptr &track_in) { void MediaSink::resetTracks() { lock_guard lck(_mtx); - _anyTrackUnReady = false; _allTrackReady = false; _track_map.clear(); _trackReadyCallback.clear(); @@ -83,26 +79,50 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) { } } - if(!_allTrackReady && (_trackReadyCallback.empty() || _ticker.elapsedTime() > MAX_WAIT_MS)){ - _allTrackReady = true; - _anyTrackUnReady = false; - if(!_trackReadyCallback.empty()){ - //这是超时强制忽略未准备好的Track - _trackReadyCallback.clear(); - //移除未准备好的Track - for(auto it = _track_map.begin() ; it != _track_map.end() ; ){ - if(!it->second->ready()){ - it = _track_map.erase(it); - continue; - } - ++it; - } + if(!_allTrackReady){ + if(_ticker.elapsedTime() > MAX_WAIT_MS_READY){ + //如果超过规定时间,那么不再等待并忽略未准备好的Track + emitAllTrackReady(); + return; } - if(!_track_map.empty()){ - //最少有一个有效的Track - onAllTrackReady(); + if(!_trackReadyCallback.empty()){ + //在超时时间内,如果存在未准备好的Track,那么继续等待 + return; } + + if(_track_map.size() == 2){ + //如果已经添加了音视频Track,并且不存在未准备好的Track,那么说明所有Track都准备好了 + emitAllTrackReady(); + return; + } + + if(_track_map.size() == 1 && _ticker.elapsedTime() > MAX_WAIT_MS_ADD_TRACK){ + //如果只有一个Track,那么在该Track添加后,我们最多还等待若干时间(可能后面还会添加Track) + emitAllTrackReady(); + return; + } + } +} + +void MediaSink::emitAllTrackReady() { + _allTrackReady = true; + if(!_trackReadyCallback.empty()){ + //这是超时强制忽略未准备好的Track + _trackReadyCallback.clear(); + //移除未准备好的Track + for(auto it = _track_map.begin() ; it != _track_map.end() ; ){ + if(!it->second->ready()){ + it = _track_map.erase(it); + continue; + } + ++it; + } + } + + if(!_track_map.empty()){ + //最少有一个有效的Track + onAllTrackReady(); } } diff --git a/src/Common/MediaSink.h b/src/Common/MediaSink.h index 64317385..e37980e1 100644 --- a/src/Common/MediaSink.h +++ b/src/Common/MediaSink.h @@ -109,12 +109,13 @@ protected: * @param frame */ virtual void onTrackFrame(const Frame::Ptr &frame) {}; +private: + void emitAllTrackReady(); private: mutable recursive_mutex _mtx; map _track_map; map > _trackReadyCallback; bool _allTrackReady = false; - bool _anyTrackUnReady = false; Ticker _ticker; }; diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index 7330de21..e01887e3 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -26,7 +26,8 @@ #include "Stamp.h" -#define MAX_DELTA_STAMP 300 +#define MAX_DELTA_STAMP 1000 +#define MAX_CTS 500 #define ABS(x) ((x) > 0 ? (x) : (-x)) namespace mediakit { @@ -77,7 +78,7 @@ void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, dts_out = _relativeStamp; //////////////以下是播放时间戳的计算////////////////// - if(pts_dts_diff > MAX_DELTA_STAMP || pts_dts_diff < -MAX_DELTA_STAMP){ + if(ABS(pts_dts_diff) > MAX_CTS){ //如果差值太大,则认为由于回环导致时间戳错乱了 pts_dts_diff = 0; } diff --git a/src/Rtmp/RtmpMediaSource.h b/src/Rtmp/RtmpMediaSource.h index 982d4401..928c9066 100644 --- a/src/Rtmp/RtmpMediaSource.h +++ b/src/Rtmp/RtmpMediaSource.h @@ -72,7 +72,6 @@ public: const string &stream_id, int ring_size = 0) : MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) { - _metadata = TitleMeta().getMetadata(); } virtual ~RtmpMediaSource() {} @@ -117,6 +116,9 @@ public: virtual void setMetaData(const AMFValue &metadata) { lock_guard lock(_mtx); _metadata = metadata; + if(_ring){ + regist(); + } } /** @@ -143,10 +145,9 @@ public: _ring = std::make_shared(_ring_size, std::move(lam)); onReaderChanged(0); - //如果输入了非config帧, - //那么说明不再可能获取config帧以及metadata, - //所以我们强制其为已注册 - regist(); + if(_metadata){ + regist(); + } } _track_stamps_map[pkt->typeId] = pkt->timeStamp; _ring->write(pkt, pkt->isVideoKeyFrame()); diff --git a/src/Rtmp/RtmpPlayerImp.h b/src/Rtmp/RtmpPlayerImp.h index b06be303..e90acc43 100644 --- a/src/Rtmp/RtmpPlayerImp.h +++ b/src/Rtmp/RtmpPlayerImp.h @@ -66,6 +66,7 @@ private: _pRtmpMediaSrc = dynamic_pointer_cast(_pMediaSrc); if(_pRtmpMediaSrc){ _pRtmpMediaSrc->setMetaData(val); + _set_meta_data = true; } _delegate.reset(new RtmpDemuxer); _delegate->loadMetaData(val); @@ -73,6 +74,10 @@ private: } void onMediaData(const RtmpPacket::Ptr &chunkData) override { if(_pRtmpMediaSrc){ + if(!_set_meta_data && !chunkData->isCfgFrame()){ + _set_meta_data = true; + _pRtmpMediaSrc->setMetaData(TitleMeta().getMetadata()); + } _pRtmpMediaSrc->onWrite(chunkData); } if(!_delegate){ @@ -83,6 +88,7 @@ private: } private: RtmpMediaSource::Ptr _pRtmpMediaSrc; + bool _set_meta_data = false; }; diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index 6f067fea..061e512a 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -434,6 +434,7 @@ void RtmpSession::setMetaData(AMFDecoder &dec) { auto metadata = dec.load(); // dumpMetadata(metadata); _pPublisherSrc->setMetaData(metadata); + _set_meta_data = true; } void RtmpSession::onProcessCmd(AMFDecoder &dec) { @@ -491,6 +492,11 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) { _stamp[chunkData.typeId % 2].revise(chunkData.timeStamp, chunkData.timeStamp, dts_out, dts_out, true); chunkData.timeStamp = dts_out; } + + if(!_set_meta_data && !chunkData.isCfgFrame()){ + _set_meta_data = true; + _pPublisherSrc->setMetaData(TitleMeta().getMetadata()); + } _pPublisherSrc->onWrite(std::make_shared(std::move(chunkData))); } break; diff --git a/src/Rtmp/RtmpSession.h b/src/Rtmp/RtmpSession.h index 572d40f8..f5b6df79 100644 --- a/src/Rtmp/RtmpSession.h +++ b/src/Rtmp/RtmpSession.h @@ -95,6 +95,7 @@ private: std::string _strTcUrl; MediaInfo _mediaInfo; double _dNowReqID = 0; + bool _set_meta_data = false; Ticker _ticker;//数据接收时间 RingBuffer::RingReader::Ptr _pRingReader; std::shared_ptr _pPublisherSrc; From 9fa6e9d8d9f75651fb7224a291d21237c3ec90e8 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 14 Jan 2020 10:04:24 +0800 Subject: [PATCH 11/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0dts=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=AE=97=E6=B3=95=EF=BC=8C=E5=85=BC=E5=AE=B9=E5=90=ABB?= =?UTF-8?q?=E5=B8=A7=E7=9A=84rtsp=E6=8E=A8=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Device.cpp | 20 ++++++------- src/Common/Stamp.cpp | 57 +++++++++++++++++++++++++++++++++++--- src/Common/Stamp.h | 24 +++++++++++++++- src/Extension/AACRtmp.cpp | 2 +- src/Extension/AACRtp.cpp | 2 +- src/Extension/Frame.h | 7 ----- src/Extension/H264.h | 38 ++++++++++++------------- src/Extension/H264Rtmp.cpp | 16 +++++------ src/Extension/H264Rtp.cpp | 42 +++++++++++++++------------- src/Extension/H264Rtp.h | 2 ++ src/Extension/H265.h | 46 +++++++++++++++--------------- src/Extension/H265Rtp.cpp | 38 +++++++++++++------------ src/Extension/H265Rtp.h | 2 ++ src/Player/PlayerProxy.cpp | 2 +- 14 files changed, 187 insertions(+), 111 deletions(-) diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 39a76825..58fd53cb 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -106,11 +106,11 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32 } H264Frame::Ptr frame = std::make_shared(); - frame->timeStamp = dts; - frame->ptsStamp = pts; - frame->buffer.assign("\x00\x00\x00\x01",4); - frame->buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); - frame->iPrefixSize = 4; + frame->_dts = dts; + frame->_pts = pts; + frame->_buffer.assign("\x00\x00\x00\x01",4); + frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->_prefix_size = 4; inputFrame(frame); } @@ -131,11 +131,11 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32 } H265Frame::Ptr frame = std::make_shared(); - frame->timeStamp = dts; - frame->ptsStamp = pts; - frame->buffer.assign("\x00\x00\x00\x01",4); - frame->buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); - frame->iPrefixSize = 4; + frame->_dts = dts; + frame->_pts = pts; + frame->_buffer.assign("\x00\x00\x00\x01",4); + frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->_prefix_size = 4; inputFrame(frame); } diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index e01887e3..3a0ed5bf 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -42,13 +42,14 @@ int64_t DeltaStamp::deltaStamp(int64_t stamp) { } int64_t ret = stamp - _last_stamp; - if(ABS(ret) < MAX_DELTA_STAMP){ - //时间戳变化不明显 + if(ret >= 0){ + //时间戳增量为正,返回之 _last_stamp = stamp; - return ret; + //在直播情况下,时间戳增量不得大于MAX_DELTA_STAMP + return ret < MAX_DELTA_STAMP ? ret : (_playback ? ret : 0); } - //时间戳变化太明显,可能回环了或者seek了 + //时间戳增量为负,说明时间戳回环了或回退了 _last_stamp = stamp; return _playback ? ret : 0; } @@ -99,4 +100,52 @@ int64_t Stamp::getRelativeStamp() const { } +bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){ + bool ret = false; + if(pts == _last_pts){ + //pts未变,返回上次结果 + if(_last_dts){ + dts = _last_dts; + ret = true; + } + return ret; + } + + ret = getDts_l(pts,dts); + if(ret){ + //保存本次结果 + _last_dts = dts; + } + //记录上次pts + _last_pts = pts; + return ret; +} + +bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){ + if(pts > _last_max_pts){ + if(!_sorter_max_size && _frames_since_last_max_pts && _count_sorter_max_size++ > 0){ + _sorter_max_size = _frames_since_last_max_pts; + _dts_pts_offset = (pts - _last_max_pts) / 2; + InfoL << _sorter_max_size << " " << _dts_pts_offset; + } + _frames_since_last_max_pts = 0; + _last_max_pts = pts; + } + + _pts_sorter.emplace(pts); + ++_frames_since_last_max_pts; + + if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){ + auto it = _pts_sorter.begin(); + dts = *it + _dts_pts_offset; + if(dts > pts){ + //dts不能大于pts(基本不可能到达这个逻辑) + dts = pts; + } + _pts_sorter.erase(it); + return true; + } + return false; +} + }//namespace mediakit \ No newline at end of file diff --git a/src/Common/Stamp.h b/src/Common/Stamp.h index 09e77338..43d11159 100644 --- a/src/Common/Stamp.h +++ b/src/Common/Stamp.h @@ -27,8 +27,9 @@ #ifndef ZLMEDIAKIT_STAMP_H #define ZLMEDIAKIT_STAMP_H -#include "Util/TimeTicker.h" +#include #include +#include "Util/TimeTicker.h" using namespace toolkit; namespace mediakit { @@ -88,6 +89,27 @@ private: SmoothTicker _ticker; }; + +class DtsGenerator{ +public: + DtsGenerator() = default; + ~DtsGenerator() = default; + bool getDts(uint32_t pts, uint32_t &dts); +private: + bool getDts_l(uint32_t pts, uint32_t &dts); +private: + uint32_t _dts_pts_offset = 0; + uint32_t _last_dts = 0; + uint32_t _last_pts = 0; + uint32_t _last_max_pts = 0; + int _frames_since_last_max_pts = 0; + int _sorter_max_size = 0; + int _count_sorter_max_size = 0; + set _pts_sorter; + + +}; + }//namespace mediakit #endif //ZLMEDIAKIT_STAMP_H diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index 71ea9e66..c3efddb1 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -102,7 +102,7 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) { rtmpPkt->bodySize = rtmpPkt->strBuf.size(); rtmpPkt->chunkId = CHUNK_AUDIO; rtmpPkt->streamId = STREAM_MEDIA; - rtmpPkt->timeStamp = frame->stamp(); + rtmpPkt->timeStamp = frame->dts(); rtmpPkt->typeId = MSG_AUDIO; RtmpCodec::inputRtmp(rtmpPkt, false); } diff --git a/src/Extension/AACRtp.cpp b/src/Extension/AACRtp.cpp index 7b436fb0..a84c22be 100644 --- a/src/Extension/AACRtp.cpp +++ b/src/Extension/AACRtp.cpp @@ -41,7 +41,7 @@ AACRtpEncoder::AACRtpEncoder(uint32_t ui32Ssrc, void AACRtpEncoder::inputFrame(const Frame::Ptr &frame) { GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS); - auto uiStamp = frame->stamp(); + auto uiStamp = frame->dts(); auto pcData = frame->data() + frame->prefixSize(); auto iLen = frame->size() - frame->prefixSize(); diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 5e5121f9..d4cbca6b 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -81,13 +81,6 @@ class Frame : public Buffer, public CodecInfo { public: typedef std::shared_ptr Ptr; virtual ~Frame(){} - /** - * 时间戳,已经废弃,请使用dts() 、pts()接口 - */ - inline uint32_t stamp() const { - return dts(); - }; - /** * 返回解码时间戳,单位毫秒 diff --git a/src/Extension/H264.h b/src/Extension/H264.h index 3ffb058d..b4c71a6b 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -53,21 +53,21 @@ public: } NalType; char *data() const override{ - return (char *)buffer.data(); + return (char *)_buffer.data(); } uint32_t size() const override { - return buffer.size(); + return _buffer.size(); } uint32_t dts() const override { - return timeStamp; + return _dts; } uint32_t pts() const override { - return ptsStamp ? ptsStamp : timeStamp; + return _pts ? _pts : _dts; } uint32_t prefixSize() const override{ - return iPrefixSize; + return _prefix_size; } TrackType getTrackType() const override{ @@ -79,11 +79,11 @@ public: } bool keyFrame() const override { - return H264_TYPE(buffer[iPrefixSize]) == H264Frame::NAL_IDR; + return H264_TYPE(_buffer[_prefix_size]) == H264Frame::NAL_IDR; } bool configFrame() const override{ - switch(H264_TYPE(buffer[iPrefixSize]) ){ + switch(H264_TYPE(_buffer[_prefix_size]) ){ case H264Frame::NAL_SPS: case H264Frame::NAL_PPS: return true; @@ -92,10 +92,10 @@ public: } } public: - uint32_t timeStamp; - uint32_t ptsStamp = 0; - string buffer; - uint32_t iPrefixSize = 4; + uint32_t _dts = 0; + uint32_t _pts = 0; + uint32_t _prefix_size = 4; + string _buffer; }; @@ -340,19 +340,19 @@ private: if(!_sps.empty()){ auto spsFrame = std::make_shared(); - spsFrame->iPrefixSize = 4; - spsFrame->buffer.assign("\x0\x0\x0\x1",4); - spsFrame->buffer.append(_sps); - spsFrame->timeStamp = frame->stamp(); + spsFrame->_prefix_size = 4; + spsFrame->_buffer.assign("\x0\x0\x0\x1",4); + spsFrame->_buffer.append(_sps); + spsFrame->_dts = frame->dts(); VideoTrack::inputFrame(spsFrame); } if(!_pps.empty()){ auto ppsFrame = std::make_shared(); - ppsFrame->iPrefixSize = 4; - ppsFrame->buffer.assign("\x0\x0\x0\x1",4); - ppsFrame->buffer.append(_pps); - ppsFrame->timeStamp = frame->stamp(); + ppsFrame->_prefix_size = 4; + ppsFrame->_buffer.assign("\x0\x0\x0\x1",4); + ppsFrame->_buffer.append(_pps); + ppsFrame->_dts = frame->dts(); VideoTrack::inputFrame(ppsFrame); } } diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index 9ee877e7..c995317f 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -35,8 +35,8 @@ H264RtmpDecoder::H264RtmpDecoder() { H264Frame::Ptr H264RtmpDecoder::obtainFrame() { //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = obtainObj(); - frame->buffer.clear(); - frame->iPrefixSize = 4; + frame->_buffer.clear(); + frame->_prefix_size = 4; return frame; } @@ -78,10 +78,10 @@ bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) { inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t dts,uint32_t pts) { #if 1 - _h264frame->timeStamp = dts; - _h264frame->ptsStamp = pts; - _h264frame->buffer.assign("\x0\x0\x0\x1", 4); //添加264头 - _h264frame->buffer.append(pcData, iLen); + _h264frame->_dts = dts; + _h264frame->_pts = pts; + _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); //添加264头 + _h264frame->_buffer.append(pcData, iLen); //写入环形缓存 RtmpCodec::inputFrame(_h264frame); @@ -144,7 +144,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { return; } - if(_lastPacket && _lastPacket->timeStamp != frame->stamp()) { + if(_lastPacket && _lastPacket->timeStamp != frame->dts()) { RtmpCodec::inputRtmp(_lastPacket, _lastPacket->isVideoKeyFrame()); _lastPacket = nullptr; } @@ -165,7 +165,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { _lastPacket->chunkId = CHUNK_VIDEO; _lastPacket->streamId = STREAM_MEDIA; - _lastPacket->timeStamp = frame->stamp(); + _lastPacket->timeStamp = frame->dts(); _lastPacket->typeId = MSG_VIDEO; } diff --git a/src/Extension/H264Rtp.cpp b/src/Extension/H264Rtp.cpp index c9861f16..f90f3c56 100644 --- a/src/Extension/H264Rtp.cpp +++ b/src/Extension/H264Rtp.cpp @@ -70,8 +70,8 @@ H264RtpDecoder::H264RtpDecoder() { H264Frame::Ptr H264RtpDecoder::obtainFrame() { //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = ResourcePoolHelper::obtainObj(); - frame->buffer.clear(); - frame->iPrefixSize = 4; + frame->_buffer.clear(); + frame->_prefix_size = 4; return frame; } @@ -113,9 +113,9 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { if (nal.type >= 0 && nal.type < 24) { //a full frame - _h264frame->buffer.assign("\x0\x0\x0\x1", 4); - _h264frame->buffer.append((char *)frame, length); - _h264frame->timeStamp = rtppack->timeStamp; + _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h264frame->_buffer.append((char *)frame, length); + _h264frame->_pts = rtppack->timeStamp; auto key = _h264frame->keyFrame(); onGetH264(_h264frame); return (key); //i frame @@ -142,9 +142,9 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { //过小的帧丢弃 NALU nal; MakeNalu(ptr[0], nal); - _h264frame->buffer.assign("\x0\x0\x0\x1", 4); - _h264frame->buffer.append((char *)ptr, len); - _h264frame->timeStamp = rtppack->timeStamp; + _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h264frame->_buffer.append((char *)ptr, len); + _h264frame->_pts = rtppack->timeStamp; if(nal.type == H264Frame::NAL_IDR){ haveIDR = true; } @@ -162,10 +162,10 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { if (fu.S) { //该帧的第一个rtp包 FU-A start char tmp = (nal.forbidden_zero_bit << 7 | nal.nal_ref_idc << 5 | fu.type); - _h264frame->buffer.assign("\x0\x0\x0\x1", 4); - _h264frame->buffer.push_back(tmp); - _h264frame->buffer.append((char *)frame + 2, length - 2); - _h264frame->timeStamp = rtppack->timeStamp; + _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h264frame->_buffer.push_back(tmp); + _h264frame->_buffer.append((char *)frame + 2, length - 2); + _h264frame->_pts = rtppack->timeStamp; //该函数return时,保存下当前sequence,以便下次对比seq是否连续 _lastSeq = rtppack->sequence; return _h264frame->keyFrame(); @@ -173,22 +173,22 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) { //中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃 - _h264frame->buffer.clear(); + _h264frame->_buffer.clear(); WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃"; return false; } if (!fu.E) { //该帧的中间rtp包 FU-A mid - _h264frame->buffer.append((char *)frame + 2, length - 2); + _h264frame->_buffer.append((char *)frame + 2, length - 2); //该函数return时,保存下当前sequence,以便下次对比seq是否连续 _lastSeq = rtppack->sequence; return false; } //该帧最后一个rtp包 FU-A end - _h264frame->buffer.append((char *)frame + 2, length - 2); - _h264frame->timeStamp = rtppack->timeStamp; + _h264frame->_buffer.append((char *)frame + 2, length - 2); + _h264frame->_pts = rtppack->timeStamp; auto key = _h264frame->keyFrame(); onGetH264(_h264frame); return key; @@ -209,8 +209,12 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { } void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) { - //写入环形缓存 - RtpCodec::inputFrame(frame); + //根据pts计算dts + auto flag = _dts_generator.getDts(frame->_pts,frame->_dts); + if(flag){ + //写入环形缓存 + RtpCodec::inputFrame(frame); + } _h264frame = obtainFrame(); } @@ -232,7 +236,7 @@ H264RtpEncoder::H264RtpEncoder(uint32_t ui32Ssrc, void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) { GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS); auto pcData = frame->data() + frame->prefixSize(); - auto uiStamp = frame->stamp(); + auto uiStamp = frame->pts(); auto iLen = frame->size() - frame->prefixSize(); //获取NALU的5bit 帧类型 unsigned char naluType = H264_TYPE(pcData[0]); diff --git a/src/Extension/H264Rtp.h b/src/Extension/H264Rtp.h index 5ccac81d..da4aa2d6 100644 --- a/src/Extension/H264Rtp.h +++ b/src/Extension/H264Rtp.h @@ -30,6 +30,7 @@ #include "Rtsp/RtpCodec.h" #include "Util/ResourcePool.h" #include "Extension/H264.h" +#include "Common/Stamp.h" using namespace toolkit; namespace mediakit{ @@ -66,6 +67,7 @@ private: H264Frame::Ptr obtainFrame(); private: H264Frame::Ptr _h264frame; + DtsGenerator _dts_generator; int _lastSeq = 0; }; diff --git a/src/Extension/H265.h b/src/Extension/H265.h index 021ef3d1..80591e32 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -74,23 +74,23 @@ public: } NaleType; char *data() const override { - return (char *) buffer.data(); + return (char *) _buffer.data(); } uint32_t size() const override { - return buffer.size(); + return _buffer.size(); } uint32_t dts() const override { - return timeStamp; + return _dts; } uint32_t pts() const override { - return ptsStamp ? ptsStamp : timeStamp; + return _pts ? _pts : _dts; } uint32_t prefixSize() const override { - return iPrefixSize; + return _prefix_size; } TrackType getTrackType() const override { @@ -102,11 +102,11 @@ public: } bool keyFrame() const override { - return isKeyFrame(H265_TYPE(buffer[iPrefixSize])); + return isKeyFrame(H265_TYPE(_buffer[_prefix_size])); } bool configFrame() const override{ - switch(H265_TYPE(buffer[iPrefixSize])){ + switch(H265_TYPE(_buffer[_prefix_size])){ case H265Frame::NAL_VPS: case H265Frame::NAL_SPS: case H265Frame::NAL_PPS: @@ -131,10 +131,10 @@ public: } public: - uint32_t timeStamp; - uint32_t ptsStamp = 0; - string buffer; - uint32_t iPrefixSize = 4; + uint32_t _dts = 0; + uint32_t _pts = 0; + uint32_t _prefix_size = 4; + string _buffer; }; @@ -356,27 +356,27 @@ private: } if(!_vps.empty()){ auto vpsFrame = std::make_shared(); - vpsFrame->iPrefixSize = 4; - vpsFrame->buffer.assign("\x0\x0\x0\x1", 4); - vpsFrame->buffer.append(_vps); - vpsFrame->timeStamp = frame->stamp(); + vpsFrame->_prefix_size = 4; + vpsFrame->_buffer.assign("\x0\x0\x0\x1", 4); + vpsFrame->_buffer.append(_vps); + vpsFrame->_dts = frame->dts(); VideoTrack::inputFrame(vpsFrame); } if (!_sps.empty()) { auto spsFrame = std::make_shared(); - spsFrame->iPrefixSize = 4; - spsFrame->buffer.assign("\x0\x0\x0\x1", 4); - spsFrame->buffer.append(_sps); - spsFrame->timeStamp = frame->stamp(); + spsFrame->_prefix_size = 4; + spsFrame->_buffer.assign("\x0\x0\x0\x1", 4); + spsFrame->_buffer.append(_sps); + spsFrame->_dts = frame->dts(); VideoTrack::inputFrame(spsFrame); } if (!_pps.empty()) { auto ppsFrame = std::make_shared(); - ppsFrame->iPrefixSize = 4; - ppsFrame->buffer.assign("\x0\x0\x0\x1", 4); - ppsFrame->buffer.append(_pps); - ppsFrame->timeStamp = frame->stamp(); + ppsFrame->_prefix_size = 4; + ppsFrame->_buffer.assign("\x0\x0\x0\x1", 4); + ppsFrame->_buffer.append(_pps); + ppsFrame->_dts = frame->dts(); VideoTrack::inputFrame(ppsFrame); } } diff --git a/src/Extension/H265Rtp.cpp b/src/Extension/H265Rtp.cpp index 6d164dde..4b8df94c 100644 --- a/src/Extension/H265Rtp.cpp +++ b/src/Extension/H265Rtp.cpp @@ -70,8 +70,8 @@ H265RtpDecoder::H265RtpDecoder() { H265Frame::Ptr H265RtpDecoder::obtainFrame() { //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = ResourcePoolHelper::obtainObj(); - frame->buffer.clear(); - frame->iPrefixSize = 4; + frame->_buffer.clear(); + frame->_prefix_size = 4; return frame; } @@ -99,11 +99,11 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { MakeFU(frame[2], fu); if (fu.S) { //该帧的第一个rtp包 - _h265frame->buffer.assign("\x0\x0\x0\x1", 4); - _h265frame->buffer.push_back(fu.type << 1); - _h265frame->buffer.push_back(0x01); - _h265frame->buffer.append((char *) frame + 3, length - 3); - _h265frame->timeStamp = rtppack->timeStamp; + _h265frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h265frame->_buffer.push_back(fu.type << 1); + _h265frame->_buffer.push_back(0x01); + _h265frame->_buffer.append((char *) frame + 3, length - 3); + _h265frame->_pts = rtppack->timeStamp; //该函数return时,保存下当前sequence,以便下次对比seq是否连续 _lastSeq = rtppack->sequence; return (_h265frame->keyFrame()); //i frame @@ -111,22 +111,22 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) { //中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃 - _h265frame->buffer.clear(); + _h265frame->_buffer.clear(); WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃"; return false; } if (!fu.E) { //该帧的中间rtp包 - _h265frame->buffer.append((char *) frame + 3, length - 3); + _h265frame->_buffer.append((char *) frame + 3, length - 3); //该函数return时,保存下当前sequence,以便下次对比seq是否连续 _lastSeq = rtppack->sequence; return false; } //该帧最后一个rtp包 - _h265frame->buffer.append((char *) frame + 3, length - 3); - _h265frame->timeStamp = rtppack->timeStamp; + _h265frame->_buffer.append((char *) frame + 3, length - 3); + _h265frame->_pts = rtppack->timeStamp; auto key = _h265frame->keyFrame(); onGetH265(_h265frame); return key; @@ -134,9 +134,9 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { default: // 4.4.1. Single NAL Unit Packets (p24) //a full frame - _h265frame->buffer.assign("\x0\x0\x0\x1", 4); - _h265frame->buffer.append((char *)frame, length); - _h265frame->timeStamp = rtppack->timeStamp; + _h265frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h265frame->_buffer.append((char *)frame, length); + _h265frame->_pts = rtppack->timeStamp; auto key = _h265frame->keyFrame(); onGetH265(_h265frame); return key; @@ -144,8 +144,12 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { } void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) { - //写入环形缓存 - RtpCodec::inputFrame(frame); + //计算dts + auto flag = _dts_generator.getDts(frame->_pts,frame->_dts); + if(flag){ + //写入环形缓存 + RtpCodec::inputFrame(frame); + } _h265frame = obtainFrame(); } @@ -167,7 +171,7 @@ H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc, void H265RtpEncoder::inputFrame(const Frame::Ptr &frame) { GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS); uint8_t *pcData = (uint8_t*)frame->data() + frame->prefixSize(); - auto uiStamp = frame->stamp(); + auto uiStamp = frame->pts(); auto iLen = frame->size() - frame->prefixSize(); unsigned char naluType = H265_TYPE(pcData[0]); //获取NALU的5bit 帧类型 uiStamp %= cycleMS; diff --git a/src/Extension/H265Rtp.h b/src/Extension/H265Rtp.h index 8b51f880..a2844092 100644 --- a/src/Extension/H265Rtp.h +++ b/src/Extension/H265Rtp.h @@ -30,6 +30,7 @@ #include "Rtsp/RtpCodec.h" #include "Util/ResourcePool.h" #include "Extension/H265.h" +#include "Common/Stamp.h" using namespace toolkit; @@ -67,6 +68,7 @@ private: H265Frame::Ptr obtainFrame(); private: H265Frame::Ptr _h265frame; + DtsGenerator _dts_generator; int _lastSeq = 0; }; diff --git a/src/Player/PlayerProxy.cpp b/src/Player/PlayerProxy.cpp index 250ea932..6b5fca6e 100644 --- a/src/Player/PlayerProxy.cpp +++ b/src/Player/PlayerProxy.cpp @@ -219,7 +219,7 @@ public: virtual ~MuteAudioMaker(){} void inputFrame(const Frame::Ptr &frame) override { if(frame->getTrackType() == TrackVideo){ - auto iAudioIndex = frame->stamp() / MUTE_ADTS_DATA_MS; + auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS; if(_iAudioIndex != iAudioIndex){ _iAudioIndex = iAudioIndex; auto aacFrame = std::make_shared((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS); From ec679006658002a62cb484b3d169a7b4d234eb76 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 14 Jan 2020 10:06:35 +0800 Subject: [PATCH 12/15] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=8D=E5=90=ABB?= =?UTF-8?q?=E5=B8=A7=E6=97=B6=E7=9A=84dts=E7=94=9F=E6=88=90=E6=80=A7?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Stamp.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index 3a0ed5bf..1c037d32 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -122,11 +122,16 @@ bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){ } bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){ + if(_sorter_max_size == 1){ + //没有B帧 + dts = pts; + return true; + } + if(pts > _last_max_pts){ if(!_sorter_max_size && _frames_since_last_max_pts && _count_sorter_max_size++ > 0){ _sorter_max_size = _frames_since_last_max_pts; _dts_pts_offset = (pts - _last_max_pts) / 2; - InfoL << _sorter_max_size << " " << _dts_pts_offset; } _frames_since_last_max_pts = 0; _last_max_pts = pts; From d8dbf434909335be49fb6228fa5390cd375227de Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 14 Jan 2020 10:25:14 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E4=BC=98=E5=8C=96dts=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Stamp.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index 1c037d32..a0017752 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -128,18 +128,19 @@ bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){ return true; } - if(pts > _last_max_pts){ - if(!_sorter_max_size && _frames_since_last_max_pts && _count_sorter_max_size++ > 0){ - _sorter_max_size = _frames_since_last_max_pts; - _dts_pts_offset = (pts - _last_max_pts) / 2; + if(!_sorter_max_size){ + if(pts > _last_max_pts){ + if(_frames_since_last_max_pts && _count_sorter_max_size++ > 0){ + _sorter_max_size = _frames_since_last_max_pts; + _dts_pts_offset = (pts - _last_max_pts) / 2; + } + _frames_since_last_max_pts = 0; + _last_max_pts = pts; } - _frames_since_last_max_pts = 0; - _last_max_pts = pts; + ++_frames_since_last_max_pts; } _pts_sorter.emplace(pts); - ++_frames_since_last_max_pts; - if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){ auto it = _pts_sorter.begin(); dts = *it + _dts_pts_offset; From 4a7d17334c218ee7f01739f5f1ebc60f1dd561c4 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 14 Jan 2020 10:29:27 +0800 Subject: [PATCH 14/15] =?UTF-8?q?rtsp=E4=B8=8D=E5=85=81=E8=AE=B8=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E6=97=B6=E9=97=B4=E6=88=B3(pts)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/config.ini | 2 -- src/Common/config.cpp | 2 -- src/Common/config.h | 2 -- 3 files changed, 6 deletions(-) diff --git a/conf/config.ini b/conf/config.ini index 8010e4e8..c158d843 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -191,8 +191,6 @@ keepAliveSecond=15 port=554 #rtsps服务器监听地址 sslport=322 -#在接收rtsp推流时,是否重新生成时间戳(很多推流器的时间戳着实很烂) -modifyStamp=0 [shell] #调试telnet服务器接受最大bufffer大小 diff --git a/src/Common/config.cpp b/src/Common/config.cpp index 74e92e72..89ad9bbf 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -158,7 +158,6 @@ const string kAuthBasic = RTSP_FIELD"authBasic"; const string kHandshakeSecond = RTSP_FIELD"handshakeSecond"; const string kKeepAliveSecond = RTSP_FIELD"keepAliveSecond"; const string kDirectProxy = RTSP_FIELD"directProxy"; -const string kModifyStamp = RTSP_FIELD"modifyStamp"; onceToken token([](){ //默认Md5方式认证 @@ -166,7 +165,6 @@ onceToken token([](){ mINI::Instance()[kHandshakeSecond] = 15; mINI::Instance()[kKeepAliveSecond] = 15; mINI::Instance()[kDirectProxy] = 1; - mINI::Instance()[kModifyStamp] = false; },nullptr); } //namespace Rtsp diff --git a/src/Common/config.h b/src/Common/config.h index 7cadbf70..d8d51e35 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -232,8 +232,6 @@ extern const string kKeepAliveSecond; //假定您的拉流源地址不是264或265或AAC,那么你可以使用直接代理的方式来支持rtsp代理 //默认开启rtsp直接代理,rtmp由于没有这些问题,是强制开启直接代理的 extern const string kDirectProxy; -//rtsp推流是否修改时间戳 -extern const string kModifyStamp; } //namespace Rtsp ////////////RTMP服务器配置/////////// From 491ed6f83d5933ce35d405156e1e08595c00efb6 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 14 Jan 2020 10:34:05 +0800 Subject: [PATCH 15/15] =?UTF-8?q?rtsp=E4=B8=8D=E5=85=81=E8=AE=B8=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E6=97=B6=E9=97=B4=E6=88=B3(pts)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/RtspSession.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index b9a3c424..6da40b06 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -932,12 +932,6 @@ inline void RtspSession::send_NotAcceptable() { void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) { - GET_CONFIG(bool,modify_stamp,Rtsp::kModifyStamp); - if(modify_stamp){ - int64_t dts_out; - _stamp[trackidx].revise(rtppt->timeStamp, rtppt->timeStamp, dts_out, dts_out, true); - rtppt->timeStamp = dts_out; - } _pushSrc->onWrite(rtppt, false); } inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {