diff --git a/api/source/mk_player.cpp b/api/source/mk_player.cpp index 9fc0abc1..4d900c82 100755 --- a/api/source/mk_player.cpp +++ b/api/source/mk_player.cpp @@ -188,7 +188,7 @@ API_EXPORT void API_CALL mk_player_seektoByPos(mk_player ctx, int seekPos) } static void mk_player_set_on_event(mk_player ctx, on_mk_play_event cb, void *user_data, int type) { - assert(ctx && cb); + assert(ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); obj.setOnEvent(cb,user_data, type); } @@ -202,7 +202,7 @@ API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_eve } API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb, void *user_data) { - assert(ctx && cb); + assert(ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); obj.setOnData(cb,user_data); } diff --git a/conf/config.ini b/conf/config.ini index accde647..02fc096c 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -29,8 +29,6 @@ maxStreamWaitMS=15000 #某个流无人观看时,触发hook.on_stream_none_reader事件的最大等待时间,单位毫秒 #在配合hook.on_stream_none_reader事件时,可以做到无人观看自动停止拉流或停止接收推流 streamNoneReaderDelayMS=20000 -#是否开启低延时模式,该模式下禁用MSG_MORE,启用TCP_NODEALY,延时将降低,但数据发送性能将降低 -ultraLowDelay=1 #拉流代理是否添加静音音频(直接拉流模式本协议无效) addMuteAudio=1 #拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始, @@ -43,8 +41,8 @@ publishToHls=1 #是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置 publishToMP4=0 #合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时 -#在开启低延时模式后,该参数不起作用 -mergeWriteMS=300 +#开启后会同时关闭TCP_NODELAY并开启MSG_MORE +mergeWriteMS=0 [hls] #hls写文件的buf大小,调整参数可以提高文件io性能 @@ -150,6 +148,8 @@ keepAliveSecond=15 modifyStamp=0 #rtmp服务器监听端口 port=1935 +#rtmps服务器监听地址 +sslport=19350 [rtp] #音频mtu大小,该参数限制rtp最大字节数,推荐不要超过1400 diff --git a/server/main.cpp b/server/main.cpp index 55ea061e..cd1ee8a0 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -75,8 +75,10 @@ onceToken token1([](){ namespace Rtmp { #define RTMP_FIELD "rtmp." const string kPort = RTMP_FIELD"port"; +const string kSSLPort = RTMP_FIELD"sslport"; onceToken token1([](){ mINI::Instance()[kPort] = 1935; + mINI::Instance()[kSSLPort] = 19350; },nullptr); } //namespace RTMP @@ -255,9 +257,10 @@ int start_main(int argc,char *argv[]) { uint16_t rtspPort = mINI::Instance()[Rtsp::kPort]; uint16_t rtspsPort = mINI::Instance()[Rtsp::kSSLPort]; uint16_t rtmpPort = mINI::Instance()[Rtmp::kPort]; + uint16_t rtmpsPort = mINI::Instance()[Rtmp::kSSLPort]; uint16_t httpPort = mINI::Instance()[Http::kPort]; uint16_t httpsPort = mINI::Instance()[Http::kSSLPort]; - uint16_t rtp_proxy = mINI::Instance()[RtpProxy::kPort]; + uint16_t rtpPort = mINI::Instance()[RtpProxy::kPort]; //设置poller线程数,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效 EventPollerPool::setPoolSize(threads); @@ -265,38 +268,51 @@ int start_main(int argc,char *argv[]) { //简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象 //测试方法:telnet 127.0.0.1 9000 TcpServer::Ptr shellSrv(new TcpServer()); + + //rtsp[s]服务器, 可用于诸如亚马逊echo show这样的设备访问 TcpServer::Ptr rtspSrv(new TcpServer()); - TcpServer::Ptr rtmpSrv(new TcpServer()); - TcpServer::Ptr httpSrv(new TcpServer()); - //如果支持ssl,还可以开启https服务器 - TcpServer::Ptr httpsSrv(new TcpServer()); - //支持ssl加密的rtsp服务器,可用于诸如亚马逊echo show这样的设备访问 TcpServer::Ptr rtspSSLSrv(new TcpServer()); + //rtmp[s]服务器 + TcpServer::Ptr rtmpSrv(new TcpServer()); + TcpServer::Ptr rtmpsSrv(new TcpServer()); + + //http[s]服务器 + TcpServer::Ptr httpSrv(new TcpServer()); + TcpServer::Ptr httpsSrv(new TcpServer()); + #if defined(ENABLE_RTPPROXY) + //GB28181 rtp推流端口,支持UDP/TCP UdpRecver recver; TcpServer::Ptr tcpRtpServer(new TcpServer()); #endif//defined(ENABLE_RTPPROXY) try { //rtsp服务器,端口默认554 - rtspSrv->start(rtspPort);//默认554 + if(rtspPort) { rtspSrv->start(rtspPort); } //rtsps服务器,端口默认322 - rtspSSLSrv->start(rtspsPort); + if(rtspsPort) { rtspSSLSrv->start(rtspsPort); } + //rtmp服务器,端口默认1935 - rtmpSrv->start(rtmpPort); + if(rtmpPort) { rtmpSrv->start(rtmpPort); } + //rtmps服务器,端口默认19350 + if(rtmpsPort) { rtmpsSrv->start(rtmpsPort); } + //http服务器,端口默认80 - httpSrv->start(httpPort); + if(httpPort) { httpSrv->start(httpPort); } //https服务器,端口默认443 - httpsSrv->start(httpsPort); + if(httpsPort) { httpsSrv->start(httpsPort); } + //telnet远程调试服务器 - shellSrv->start(shellPort); + if(shellPort) { shellSrv->start(shellPort); } #if defined(ENABLE_RTPPROXY) - //创建rtp udp服务器 - recver.initSock(rtp_proxy); - //创建rtp tcp服务器 - tcpRtpServer->start(rtp_proxy); + if(rtpPort){ + //创建rtp udp服务器 + recver.initSock(rtpPort); + //创建rtp tcp服务器 + tcpRtpServer->start(rtpPort); + } #endif//defined(ENABLE_RTPPROXY) }catch (std::exception &ex){ diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index 3c41c0ec..fafb13dd 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -516,9 +516,8 @@ static bool isFlushAble_merge(bool is_audio, uint32_t last_stamp, uint32_t new_s bool FlushPolicy::isFlushAble(uint32_t new_stamp, int cache_size) { bool ret = false; - GET_CONFIG(bool, ultraLowDelay, General::kUltraLowDelay); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); - if (ultraLowDelay || mergeWriteMS <= 0) { + if (mergeWriteMS <= 0) { //关闭了合并写或者合并写阈值小于等于0 ret = isFlushAble_default(_is_audio, _last_stamp, new_stamp, cache_size); } else { diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp index 0f56ddbe..58217d2b 100644 --- a/src/Common/MultiMediaSourceMuxer.cpp +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -22,17 +22,21 @@ MultiMuxerPrivate::MultiMuxerPrivate(const string &vhost, bool enable_mp4) { if (enable_rtmp) { _rtmp = std::make_shared(vhost, app, stream, std::make_shared(dur_sec)); + _enable_rtxp = true; } if (enable_rtsp) { _rtsp = std::make_shared(vhost, app, stream, std::make_shared(dur_sec)); + _enable_rtxp = true; } if (enable_hls) { _hls = Recorder::createRecorder(Recorder::type_hls, vhost, app, stream); + _enable_record = true; } if (enable_mp4) { _mp4 = Recorder::createRecorder(Recorder::type_mp4, vhost, app, stream); + _enable_record = true; } } @@ -77,8 +81,8 @@ int MultiMuxerPrivate::totalReaderCount() const { return (_rtsp ? _rtsp->readerCount() : 0) + (_rtmp ? _rtmp->readerCount() : 0) + (hls_src ? hls_src->readerCount() : 0); } -static std::shared_ptr makeRecorder(const vector &tracks, Recorder::type type, MediaSource &sender){ - auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId()); +static std::shared_ptr makeRecorder(const vector &tracks, Recorder::type type, const string &custom_path, MediaSource &sender){ + auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId(), custom_path); for (auto &track : tracks) { recorder->addTrack(track); } @@ -91,7 +95,7 @@ bool MultiMuxerPrivate::setupRecord(MediaSource &sender, Recorder::type type, bo case Recorder::type_hls : { if (start && !_hls) { //开始录制 - _hls = makeRecorder(getTracks(true), type, sender); + _hls = makeRecorder(getTracks(true), type, custom_path, sender); auto hls_src = getHlsMediaSource(); if (hls_src) { //设置HlsMediaSource的事件监听器 @@ -102,20 +106,21 @@ bool MultiMuxerPrivate::setupRecord(MediaSource &sender, Recorder::type type, bo //停止录制 _hls = nullptr; } + _enable_record = _hls || _mp4; return true; } case Recorder::type_mp4 : { if (start && !_mp4) { //开始录制 - _mp4 = makeRecorder(getTracks(true), type, sender);; + _mp4 = makeRecorder(getTracks(true), type, custom_path, sender); } else if (!start && _mp4) { //停止录制 _mp4 = nullptr; } + _enable_record = _hls || _mp4; return true; } - default: - return false; + default : return false; } } @@ -163,6 +168,10 @@ void MultiMuxerPrivate::onTrackReady(const Track::Ptr &track) { } } +bool MultiMuxerPrivate::isEnabled(){ + return _enable_rtxp || _enable_record; +} + void MultiMuxerPrivate::onTrackFrame(const Frame::Ptr &frame) { if (_rtmp) { _rtmp->inputFrame(frame); @@ -293,4 +302,9 @@ void MultiMediaSourceMuxer::inputFrame(const Frame::Ptr &frame) { _muxer->inputFrame(frame); } +bool MultiMediaSourceMuxer::isEnabled(){ + return _muxer->isEnabled(); +} + + }//namespace mediakit \ No newline at end of file diff --git a/src/Common/MultiMediaSourceMuxer.h b/src/Common/MultiMediaSourceMuxer.h index 5ba6b8fe..04109745 100644 --- a/src/Common/MultiMediaSourceMuxer.h +++ b/src/Common/MultiMediaSourceMuxer.h @@ -45,6 +45,7 @@ private: void setTrackListener(Listener *listener); bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path); bool isRecording(MediaSource &sender, Recorder::type type); + bool isEnabled(); private: void onTrackReady(const Track::Ptr & track) override; void onTrackFrame(const Frame::Ptr &frame) override; @@ -57,6 +58,8 @@ private: MediaSinkInterface::Ptr _mp4; Listener *_listener = nullptr; std::weak_ptr _meida_listener; + bool _enable_rtxp = false; + bool _enable_record = false; }; class MultiMediaSourceMuxer : public MediaSourceEvent, public MediaSinkInterface, public TrackSource, public std::enable_shared_from_this{ @@ -167,6 +170,11 @@ public: * @param frame 帧 */ void inputFrame(const Frame::Ptr &frame) override; + + /** + * 判断是否生效(是否正在转其他协议) + */ + bool isEnabled(); private: MultiMuxerPrivate::Ptr _muxer; std::weak_ptr _listener; diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index 7ed1474f..0bbaf958 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -96,58 +96,84 @@ int64_t Stamp::getRelativeStamp() const { return _relativeStamp; } - bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){ bool ret = false; - if(pts == _last_pts){ - //pts未变,返回上次结果 - if(_last_dts){ + if (pts == _last_pts) { + //pts未变,说明dts也不会变,返回上次dts + if (_last_dts) { dts = _last_dts; ret = true; } - return ret; + } else { + //pts变了,尝试计算dts + ret = getDts_l(pts, dts); + if (ret) { + //获取到了dts,保存本次结果 + _last_dts = dts; + } } - ret = getDts_l(pts,dts); - if(ret){ - //保存本次结果 - _last_dts = dts; + if (!ret) { + //pts排序列队长度还不知道,也就是不知道有没有B帧, + //那么先强制dts == pts,这样可能导致有B帧的情况下,起始画面有几帧回退 + dts = pts; } + //记录上次pts _last_pts = pts; return ret; } +//该算法核心思想是对pts进行排序,排序好的pts就是dts。 +//排序有一定的滞后性,那么需要加上排序导致的时间戳偏移量 bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){ if(_sorter_max_size == 1){ - //没有B帧 + //没有B帧,dts就等于pts dts = pts; return true; } if(!_sorter_max_size){ + //尚未计算出pts排序列队长度(也就是P帧间B帧个数) if(pts > _last_max_pts){ + //pts时间戳增加了,那么说明这帧画面不是B帧(说明是P帧或关键帧) if(_frames_since_last_max_pts && _count_sorter_max_size++ > 0){ + //已经出现多次非B帧的情况,那么我们就能知道P帧间B帧的个数 _sorter_max_size = _frames_since_last_max_pts; + //我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计) _dts_pts_offset = (pts - _last_max_pts) / 2; } + //遇到P帧或关键帧,连续B帧计数清零 _frames_since_last_max_pts = 0; + //记录上次非B帧的pts时间戳(同时也是dts),用于统计连续B帧时间戳增量 _last_max_pts = pts; } + //如果pts时间戳小于上一个P帧,那么断定这个是B帧,我们记录B帧连续个数 ++_frames_since_last_max_pts; } + //pts放入排序缓存列队,缓存列队最大等于连续B帧个数 _pts_sorter.emplace(pts); + if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){ + //如果启用了pts排序(意味着存在B帧),并且pts排序缓存列队长度大于连续B帧个数, + //意味着后续的pts都会比最早的pts大,那么说明可以取出最早的pts了,这个pts将当做该帧的dts基准 auto it = _pts_sorter.begin(); + + //由于该pts是前面偏移了个_sorter_max_size帧的pts(也就是那帧画面的dts), + //那么我们加上时间戳偏移量,基本等于该帧的dts dts = *it + _dts_pts_offset; if(dts > pts){ //dts不能大于pts(基本不可能到达这个逻辑) dts = pts; } + + //pts排序缓存出列 _pts_sorter.erase(it); return true; } + + //排序缓存尚未满 return false; } diff --git a/src/Common/config.cpp b/src/Common/config.cpp index 819901fb..8a22bea1 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -61,7 +61,6 @@ const string kFlowThreshold = GENERAL_FIELD"flowThreshold"; const string kStreamNoneReaderDelayMS = GENERAL_FIELD"streamNoneReaderDelayMS"; const string kMaxStreamWaitTimeMS = GENERAL_FIELD"maxStreamWaitMS"; const string kEnableVhost = GENERAL_FIELD"enableVhost"; -const string kUltraLowDelay = GENERAL_FIELD"ultraLowDelay"; const string kAddMuteAudio = GENERAL_FIELD"addMuteAudio"; const string kResetWhenRePlay = GENERAL_FIELD"resetWhenRePlay"; const string kPublishToRtxp = GENERAL_FIELD"publishToRtxp"; @@ -74,13 +73,12 @@ onceToken token([](){ mINI::Instance()[kStreamNoneReaderDelayMS] = 20 * 1000; mINI::Instance()[kMaxStreamWaitTimeMS] = 15 * 1000; mINI::Instance()[kEnableVhost] = 0; - mINI::Instance()[kUltraLowDelay] = 1; mINI::Instance()[kAddMuteAudio] = 1; mINI::Instance()[kResetWhenRePlay] = 1; mINI::Instance()[kPublishToRtxp] = 1; mINI::Instance()[kPublishToHls] = 1; mINI::Instance()[kPublishToMP4] = 0; - mINI::Instance()[kMergeWriteMS] = 300; + mINI::Instance()[kMergeWriteMS] = 0; },nullptr); }//namespace General diff --git a/src/Common/config.h b/src/Common/config.h index aa42acaa..3948879f 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -160,8 +160,6 @@ extern const string kStreamNoneReaderDelayMS; extern const string kMaxStreamWaitTimeMS; //是否启动虚拟主机 extern const string kEnableVhost; -//超低延时模式,默认打开,打开后会降低延时但是转发性能会稍差 -extern const string kUltraLowDelay; //拉流代理时是否添加静音音频 extern const string kAddMuteAudio; //拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始, @@ -174,7 +172,7 @@ extern const string kPublishToHls ; //是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置 extern const string kPublishToMP4 ; //合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时 -//在开启低延时模式后,该参数不起作用 +//开启后会同时关闭TCP_NODELAY并开启MSG_MORE extern const string kMergeWriteMS ; }//namespace General diff --git a/src/Extension/H264.cpp b/src/Extension/H264.cpp index d1f66f9a..7cfb086a 100644 --- a/src/Extension/H264.cpp +++ b/src/Extension/H264.cpp @@ -50,6 +50,9 @@ void splitH264(const char *ptr, int len, const std::function_pts,frame->_dts); - if(!flag){ - if(frame->configFrame() || frame->keyFrame()){ - flag = true; - frame->_dts = frame->_pts; - } - } - - //根据pts计算dts - if(flag){ - //写入环形缓存 - RtpCodec::inputFrame(frame); - } + //rtsp没有dts,那么根据pts排序算法生成dts + _dts_generator.getDts(frame->_pts,frame->_dts); + //写入环形缓存 + RtpCodec::inputFrame(frame); _h264frame = obtainFrame(); } diff --git a/src/Extension/H265.h b/src/Extension/H265.h index 71069d11..fca162c3 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -46,6 +46,9 @@ public: NAL_IDR_W_RADL = 19, NAL_IDR_N_LP = 20, NAL_CRA_NUT = 21, + NAL_RSV_IRAP_VCL22 = 22, + NAL_RSV_IRAP_VCL23 = 23, + NAL_VPS = 32, NAL_SPS = 33, NAL_PPS = 34, @@ -101,17 +104,7 @@ public: } static bool isKeyFrame(int type) { - switch (type) { - case NAL_BLA_N_LP: - case NAL_BLA_W_LP: - case NAL_BLA_W_RADL: - case NAL_CRA_NUT: - case NAL_IDR_N_LP: - case NAL_IDR_W_RADL: - return true; - default: - return false; - } + return type >= NAL_BLA_W_LP && type <= NAL_RSV_IRAP_VCL23; } public: diff --git a/src/Extension/H265Rtp.cpp b/src/Extension/H265Rtp.cpp index b41b4cfa..daa190a0 100644 --- a/src/Extension/H265Rtp.cpp +++ b/src/Extension/H265Rtp.cpp @@ -127,18 +127,10 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { } void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) { - //计算dts - auto flag = _dts_generator.getDts(frame->_pts,frame->_dts); - if(!flag){ - if(frame->configFrame() || frame->keyFrame()){ - flag = true; - frame->_dts = frame->_pts; - } - } - if(flag){ - //写入环形缓存 - RtpCodec::inputFrame(frame); - } + //rtsp没有dts,那么根据pts排序算法生成dts + _dts_generator.getDts(frame->_pts,frame->_dts); + //写入环形缓存 + RtpCodec::inputFrame(frame); _h265frame = obtainFrame(); } diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index 26056ed0..65ed9b3a 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -606,8 +606,8 @@ void HttpSession::sendNotFound(bool bClose) { } void HttpSession::setSocketFlags(){ - GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); - if(!ultraLowDelay) { + GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); + if(mergeWriteMS > 0) { //推流模式下,关闭TCP_NODELAY会增加推流端的延时,但是服务器性能将提高 SockUtil::setNoDelay(_sock->rawFD(), false); //播放模式下,开启MSG_MORE会增加延时,但是能提高发送性能 diff --git a/src/Record/Recorder.cpp b/src/Record/Recorder.cpp index 38d6b98a..2ab341b7 100644 --- a/src/Record/Recorder.cpp +++ b/src/Record/Recorder.cpp @@ -56,7 +56,7 @@ string Recorder::getRecordPath(Recorder::type type, const string &vhost, const s } std::shared_ptr Recorder::createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path){ - auto path = Recorder::getRecordPath(type, vhost, app, stream_id); + auto path = Recorder::getRecordPath(type, vhost, app, stream_id, customized_path); switch (type) { case Recorder::type_hls: { #if defined(ENABLE_HLS) diff --git a/src/Rtmp/RtmpMediaSourceImp.h b/src/Rtmp/RtmpMediaSourceImp.h index 954180b9..e78f1286 100644 --- a/src/Rtmp/RtmpMediaSourceImp.h +++ b/src/Rtmp/RtmpMediaSourceImp.h @@ -57,7 +57,14 @@ public: * 输入rtmp并解析 */ void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos = true) override { - key_pos = _demuxer->inputRtmp(pkt); + if(_all_track_ready && !_muxer->isEnabled()){ + //获取到所有Track后,并且未开启转协议,那么不需要解复用rtmp + key_pos = pkt->isVideoKeyFrame(); + }else{ + //需要解复用rtmp + key_pos = _demuxer->inputRtmp(pkt); + } + RtmpMediaSource::onWrite(pkt,key_pos); } @@ -138,10 +145,12 @@ public: */ void onAllTrackReady() override{ setTrackSource(_muxer); + _all_track_ready = true; } private: RtmpDemuxer::Ptr _demuxer; MultiMediaSourceMuxer::Ptr _muxer; + bool _all_track_ready = false; }; } /* namespace mediakit */ diff --git a/src/Rtmp/RtmpPusher.cpp b/src/Rtmp/RtmpPusher.cpp index 3722e23d..725868b5 100644 --- a/src/Rtmp/RtmpPusher.cpp +++ b/src/Rtmp/RtmpPusher.cpp @@ -228,8 +228,8 @@ inline void RtmpPusher::send_metaData(){ } void RtmpPusher::setSocketFlags(){ - GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); - if(!ultraLowDelay) { + GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); + if(mergeWriteMS > 0) { //提高发送性能 setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); SockUtil::setNoDelay(_sock->rawFD(), false); diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index d606f118..a062c5d6 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -529,8 +529,8 @@ int RtmpSession::totalReaderCount(MediaSource &sender) { } void RtmpSession::setSocketFlags(){ - GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); - if(!ultraLowDelay) { + GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); + if(mergeWriteMS > 0) { //推流模式下,关闭TCP_NODELAY会增加推流端的延时,但是服务器性能将提高 SockUtil::setNoDelay(_sock->rawFD(), false); //播放模式下,开启MSG_MORE会增加延时,但是能提高发送性能 diff --git a/src/Rtmp/RtmpSession.h b/src/Rtmp/RtmpSession.h index da76c627..f88d2eb6 100644 --- a/src/Rtmp/RtmpSession.h +++ b/src/Rtmp/RtmpSession.h @@ -91,6 +91,12 @@ private: }; + +/** + * 支持ssl加密的rtmp服务器 + */ +typedef TcpSessionWithSSL RtmpSessionWithSSL; + } /* namespace mediakit */ #endif /* SRC_RTMP_RTMPSESSION_H_ */ diff --git a/src/Rtsp/RtspMediaSourceImp.h b/src/Rtsp/RtspMediaSourceImp.h index 495158f3..91a97992 100644 --- a/src/Rtsp/RtspMediaSourceImp.h +++ b/src/Rtsp/RtspMediaSourceImp.h @@ -48,7 +48,14 @@ public: * 输入rtp并解析 */ void onWrite(const RtpPacket::Ptr &rtp, bool key_pos) override { - key_pos = _demuxer->inputRtp(rtp); + if(_all_track_ready && !_muxer->isEnabled()){ + //获取到所有Track后,并且未开启转协议,那么不需要解复用rtp + //在关闭rtp解复用后,无法知道是否为关键帧,这样会导致无法秒开,或者开播花屏 + key_pos = rtp->type == TrackVideo; + }else{ + //需要解复用rtp + key_pos = _demuxer->inputRtp(rtp); + } RtspMediaSource::onWrite(rtp, key_pos); } @@ -129,10 +136,12 @@ public: */ void onAllTrackReady() override{ setTrackSource(_muxer); + _all_track_ready = true; } private: RtspDemuxer::Ptr _demuxer; MultiMediaSourceMuxer::Ptr _muxer; + bool _all_track_ready = false; }; } /* namespace mediakit */ diff --git a/src/Rtsp/RtspPusher.cpp b/src/Rtsp/RtspPusher.cpp index 5243be4c..f259a0d6 100644 --- a/src/Rtsp/RtspPusher.cpp +++ b/src/Rtsp/RtspPusher.cpp @@ -392,8 +392,8 @@ void RtspPusher::sendRecord() { } void RtspPusher::setSocketFlags(){ - GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); - if(!ultraLowDelay) { + GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); + if(mergeWriteMS > 0) { //提高发送性能 setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); SockUtil::setNoDelay(_sock->rawFD(), false); diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index f8591e6c..a9cbcffb 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -1236,8 +1236,8 @@ void RtspSession::sendSenderReport(bool overTcp,int iTrackIndex) { } void RtspSession::setSocketFlags(){ - GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); - if(!ultraLowDelay) { + GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); + if(mergeWriteMS > 0) { //推流模式下,关闭TCP_NODELAY会增加推流端的延时,但是服务器性能将提高 SockUtil::setNoDelay(_sock->rawFD(), false); //播放模式下,开启MSG_MORE会增加延时,但是能提高发送性能