diff --git a/conf/config.ini b/conf/config.ini index cf2a2631..d0a34f99 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -55,6 +55,21 @@ modifyStamp=0 #服务器唯一id,用于触发hook时区别是哪台服务器 mediaServerId=your_server_id +###### 以下是按需转协议的开关,在测试ZLMediaKit的接收推流性能时,请关闭以下全部开关 +###### 如果某种协议你用不到,你可以把以下开关置1以便节省资源(但是还是可以播放,只是第一个播放者体验稍微差点), +###### 如果某种协议你想获取最好的用户体验,请置1(第一个播放者可以秒开,且不花屏) + +#hls协议是否按需生成,如果hls.segNum配置为0(意味着hls录制),那么hls将一直生成(不管此开关) +hls_demand=0 +#rtsp[s]协议是否按需生成 +rtsp_demand=0 +#rtmp[s]、http[s]-flv、ws[s]-flv协议是否按需生成 +rtmp_demand=0 +#http[s]-ts协议是否按需生成 +ts_demand=0 +#http[s]-fmp4、ws[s]-fmp4协议是否按需生成 +fmp4_demand=0 + [hls] #hls写文件的buf大小,调整参数可以提高文件io性能 fileBufSize=65536 diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp index ddc8cd48..816993bd 100644 --- a/src/Common/MultiMediaSourceMuxer.cpp +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -9,6 +9,7 @@ */ #include +#include "Common/config.h" #include "MultiMediaSourceMuxer.h" namespace mediakit { @@ -480,11 +481,21 @@ void MultiMediaSourceMuxer::inputFrame(const Frame::Ptr &frame_in) { } bool MultiMediaSourceMuxer::isEnabled(){ + GET_CONFIG(uint32_t, stream_none_reader_delay_ms, General::kStreamNoneReaderDelayMS); + if (!_is_enable || _last_check.elapsedTime() > stream_none_reader_delay_ms) { + //无人观看时,每次检查是否真的无人观看 + //有人观看时,则延迟一定时间检查一遍是否无人观看了(节省性能) #if defined(ENABLE_RTPPROXY) - return (_muxer->isEnabled() || _rtp_sender); + _is_enable = (_muxer->isEnabled() || _rtp_sender); #else - return _muxer->isEnabled(); + _is_enable = _muxer->isEnabled(); #endif //ENABLE_RTPPROXY + if (_is_enable) { + //无人观看时,不刷新计时器,因为无人观看时每次都会检查一遍,所以刷新计数器无意义且浪费cpu + _last_check.resetTime(); + } + } + return _is_enable; } diff --git a/src/Common/MultiMediaSourceMuxer.h b/src/Common/MultiMediaSourceMuxer.h index c8c56402..c257d3d2 100644 --- a/src/Common/MultiMediaSourceMuxer.h +++ b/src/Common/MultiMediaSourceMuxer.h @@ -184,6 +184,8 @@ public: void onAllTrackReady() override; private: + bool _is_enable = false; + Ticker _last_check; Stamp _stamp[2]; MultiMuxerPrivate::Ptr _muxer; std::weak_ptr _track_listener; diff --git a/src/Common/config.cpp b/src/Common/config.cpp index 8209689f..c2a4edf9 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -71,6 +71,11 @@ const string kPublishToHls = GENERAL_FIELD"publishToHls"; const string kPublishToMP4 = GENERAL_FIELD"publishToMP4"; const string kMergeWriteMS = GENERAL_FIELD"mergeWriteMS"; const string kModifyStamp = GENERAL_FIELD"modifyStamp"; +const string kHlsDemand = GENERAL_FIELD"hls_demand"; +const string kRtspDemand = GENERAL_FIELD"rtsp_demand"; +const string kRtmpDemand = GENERAL_FIELD"rtmp_demand"; +const string kTSDemand = GENERAL_FIELD"ts_demand"; +const string kFMP4Demand = GENERAL_FIELD"fmp4_demand"; onceToken token([](){ mINI::Instance()[kFlowThreshold] = 1024; @@ -84,6 +89,12 @@ onceToken token([](){ mINI::Instance()[kMergeWriteMS] = 0; mINI::Instance()[kModifyStamp] = 0; mINI::Instance()[kMediaServerId] = makeRandStr(16); + mINI::Instance()[kHlsDemand] = 0; + mINI::Instance()[kRtspDemand] = 0; + mINI::Instance()[kRtmpDemand] = 0; + mINI::Instance()[kTSDemand] = 0; + mINI::Instance()[kFMP4Demand] = 0; + },nullptr); }//namespace General diff --git a/src/Common/config.h b/src/Common/config.h index cd62953b..841780c1 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -189,6 +189,12 @@ extern const string kPublishToMP4 ; extern const string kMergeWriteMS ; //全局的时间戳覆盖开关,在转协议时,对frame进行时间戳覆盖 extern const string kModifyStamp; +//按需转协议的开关 +extern const string kHlsDemand; +extern const string kRtspDemand; +extern const string kRtmpDemand; +extern const string kTSDemand; +extern const string kFMP4Demand; }//namespace General diff --git a/src/FMP4/FMP4MediaSourceMuxer.h b/src/FMP4/FMP4MediaSourceMuxer.h index 3d8482a0..6d133db5 100644 --- a/src/FMP4/FMP4MediaSourceMuxer.h +++ b/src/FMP4/FMP4MediaSourceMuxer.h @@ -41,26 +41,29 @@ public: } void onReaderChanged(MediaSource &sender, int size) override { - _enabled = size; - if (!size) { + GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand); + _enabled = fmp4_demand ? size : true; + if (!size && fmp4_demand) { _clear_cache = true; } MediaSourceEventInterceptor::onReaderChanged(sender, size); } void inputFrame(const Frame::Ptr &frame) override { - if (_clear_cache) { + GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand); + if (_clear_cache && fmp4_demand) { _clear_cache = false; _media_src->clearCache(); } - if (_enabled) { + if (_enabled || !fmp4_demand) { MP4MuxerMemory::inputFrame(frame); } } bool isEnabled() { + GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand); //缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存 - return _clear_cache ? true : _enabled; + return fmp4_demand ? (_clear_cache ? true : _enabled) : true; } void onAllTrackReady() { diff --git a/src/Player/PlayerProxy.cpp b/src/Player/PlayerProxy.cpp index 03e4b8cf..ee81e952 100644 --- a/src/Player/PlayerProxy.cpp +++ b/src/Player/PlayerProxy.cpp @@ -169,10 +169,10 @@ bool PlayerProxy::close(MediaSource &sender,bool force) { strongSelf->_muxer.reset(); strongSelf->setMediaSource(nullptr); strongSelf->teardown(); - if (strongSelf->_on_close) { - strongSelf->_on_close(); - } }); + if (_on_close) { + _on_close(); + } WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; return true; } diff --git a/src/Record/HlsRecorder.h b/src/Record/HlsRecorder.h index c1d01296..ec246c7c 100644 --- a/src/Record/HlsRecorder.h +++ b/src/Record/HlsRecorder.h @@ -45,9 +45,10 @@ public: } void onReaderChanged(MediaSource &sender, int size) override { + GET_CONFIG(bool, hls_demand, General::kHlsDemand); //hls保留切片个数为0时代表为hls录制(不删除切片),那么不管有无观看者都一直生成hls - _enabled = _hls->isLive() ? size : true; - if (!size && _hls->isLive()) { + _enabled = hls_demand ? (_hls->isLive() ? size : true) : true; + if (!size && _hls->isLive() && hls_demand) { //hls直播时,如果无人观看就删除视频缓存,目的是为了防止视频跳跃 _clear_cache = true; } @@ -55,16 +56,18 @@ public: } bool isEnabled() { + GET_CONFIG(bool, hls_demand, General::kHlsDemand); //缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存 - return _clear_cache ? true : _enabled; + return hls_demand ? (_clear_cache ? true : _enabled) : true; } - void inputFrame(const Frame::Ptr &frame) override{ - if (_clear_cache) { + void inputFrame(const Frame::Ptr &frame) override { + GET_CONFIG(bool, hls_demand, General::kHlsDemand); + if (_clear_cache && hls_demand) { _clear_cache = false; _hls->clearCache(); } - if (_enabled) { + if (_enabled || !hls_demand) { TsMuxer::inputFrame(frame); } } diff --git a/src/Rtmp/RtmpMediaSourceMuxer.h b/src/Rtmp/RtmpMediaSourceMuxer.h index c8ef9652..f998a3a2 100644 --- a/src/Rtmp/RtmpMediaSourceMuxer.h +++ b/src/Rtmp/RtmpMediaSourceMuxer.h @@ -50,26 +50,29 @@ public: } void onReaderChanged(MediaSource &sender, int size) override { - _enabled = size; - if (!size) { + GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand); + _enabled = rtmp_demand ? size : true; + if (!size && rtmp_demand) { _clear_cache = true; } MediaSourceEventInterceptor::onReaderChanged(sender, size); } void inputFrame(const Frame::Ptr &frame) override { - if (_clear_cache) { + GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand); + if (_clear_cache && rtmp_demand) { _clear_cache = false; _media_src->clearCache(); } - if (_enabled) { + if (_enabled || !rtmp_demand) { RtmpMuxer::inputFrame(frame); } } bool isEnabled() { + GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand); //缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存 - return _clear_cache ? true : _enabled; + return rtmp_demand ? (_clear_cache ? true : _enabled) : true; } private: diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index 58398c54..66957ae8 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -101,6 +101,14 @@ bool RtpProcess::inputRtp(bool is_udp, const Socket::Ptr &sock, const char *data if (!_process) { _process = std::make_shared(_media_info, this); } + + GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir); + if (!_muxer->isEnabled() && !dts_out && dump_dir.empty()) { + //无人访问、且不取时间戳、不导出调试文件时,我们可以直接丢弃数据 + _last_frame_time.resetTime(); + return false; + } + bool ret = _process ? _process->inputRtp(is_udp, data, len) : false; if (dts_out) { *dts_out = _dts; diff --git a/src/Rtsp/RtspMediaSourceMuxer.h b/src/Rtsp/RtspMediaSourceMuxer.h index eb2a4bd4..18059910 100644 --- a/src/Rtsp/RtspMediaSourceMuxer.h +++ b/src/Rtsp/RtspMediaSourceMuxer.h @@ -49,26 +49,29 @@ public: } void onReaderChanged(MediaSource &sender, int size) override { - _enabled = size; - if (!size) { + GET_CONFIG(bool, rtsp_demand, General::kRtspDemand); + _enabled = rtsp_demand ? size : true; + if (!size && rtsp_demand) { _clear_cache = true; } MediaSourceEventInterceptor::onReaderChanged(sender, size); } void inputFrame(const Frame::Ptr &frame) override { - if (_clear_cache) { + GET_CONFIG(bool, rtsp_demand, General::kRtspDemand); + if (_clear_cache && rtsp_demand) { _clear_cache = false; _media_src->clearCache(); } - if (_enabled) { + if (_enabled || !rtsp_demand) { RtspMuxer::inputFrame(frame); } } bool isEnabled() { + GET_CONFIG(bool, rtsp_demand, General::kRtspDemand); //缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存 - return _clear_cache ? true : _enabled; + return rtsp_demand ? (_clear_cache ? true : _enabled) : true; } private: diff --git a/src/TS/TSMediaSourceMuxer.h b/src/TS/TSMediaSourceMuxer.h index 34051808..a8cf9efc 100644 --- a/src/TS/TSMediaSourceMuxer.h +++ b/src/TS/TSMediaSourceMuxer.h @@ -40,26 +40,29 @@ public: } void onReaderChanged(MediaSource &sender, int size) override { - _enabled = size; - if (!size) { + GET_CONFIG(bool, ts_demand, General::kTSDemand); + _enabled = ts_demand ? size : true; + if (!size && ts_demand) { _clear_cache = true; } MediaSourceEventInterceptor::onReaderChanged(sender, size); } void inputFrame(const Frame::Ptr &frame) override { - if (_clear_cache) { + GET_CONFIG(bool, ts_demand, General::kTSDemand); + if (_clear_cache && ts_demand) { _clear_cache = false; _media_src->clearCache(); } - if (_enabled) { + if (_enabled || !ts_demand) { TsMuxer::inputFrame(frame); } } bool isEnabled() { + GET_CONFIG(bool, ts_demand, General::kTSDemand); //缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存 - return _clear_cache ? true : _enabled; + return ts_demand ? (_clear_cache ? true : _enabled) : true; } protected: