Merge pull request #16 from xiongziliang/master

update
This commit is contained in:
baiyfcu 2020-04-29 18:26:06 +08:00 committed by GitHub
commit 6518e5d448
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 169 additions and 95 deletions

View File

@ -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) { 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); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
obj.setOnEvent(cb,user_data, type); 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) { 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); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
obj.setOnData(cb,user_data); obj.setOnData(cb,user_data);
} }

View File

@ -29,8 +29,6 @@ maxStreamWaitMS=15000
#某个流无人观看时触发hook.on_stream_none_reader事件的最大等待时间单位毫秒 #某个流无人观看时触发hook.on_stream_none_reader事件的最大等待时间单位毫秒
#在配合hook.on_stream_none_reader事件时可以做到无人观看自动停止拉流或停止接收推流 #在配合hook.on_stream_none_reader事件时可以做到无人观看自动停止拉流或停止接收推流
streamNoneReaderDelayMS=20000 streamNoneReaderDelayMS=20000
#是否开启低延时模式该模式下禁用MSG_MORE,启用TCP_NODEALY延时将降低但数据发送性能将降低
ultraLowDelay=1
#拉流代理是否添加静音音频(直接拉流模式本协议无效) #拉流代理是否添加静音音频(直接拉流模式本协议无效)
addMuteAudio=1 addMuteAudio=1
#拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始, #拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
@ -43,8 +41,8 @@ publishToHls=1
#是否默认推流时mp4录像hook接口(on_publish)中可以覆盖该设置 #是否默认推流时mp4录像hook接口(on_publish)中可以覆盖该设置
publishToMP4=0 publishToMP4=0
#合并写缓存大小(单位毫秒)合并写指服务器缓存一定的数据后才会一次性写入socket这样能提高性能但是会提高延时 #合并写缓存大小(单位毫秒)合并写指服务器缓存一定的数据后才会一次性写入socket这样能提高性能但是会提高延时
#在开启低延时模式后,该参数不起作用 #开启后会同时关闭TCP_NODELAY并开启MSG_MORE
mergeWriteMS=300 mergeWriteMS=0
[hls] [hls]
#hls写文件的buf大小调整参数可以提高文件io性能 #hls写文件的buf大小调整参数可以提高文件io性能
@ -150,6 +148,8 @@ keepAliveSecond=15
modifyStamp=0 modifyStamp=0
#rtmp服务器监听端口 #rtmp服务器监听端口
port=1935 port=1935
#rtmps服务器监听地址
sslport=19350
[rtp] [rtp]
#音频mtu大小该参数限制rtp最大字节数推荐不要超过1400 #音频mtu大小该参数限制rtp最大字节数推荐不要超过1400

View File

@ -75,8 +75,10 @@ onceToken token1([](){
namespace Rtmp { namespace Rtmp {
#define RTMP_FIELD "rtmp." #define RTMP_FIELD "rtmp."
const string kPort = RTMP_FIELD"port"; const string kPort = RTMP_FIELD"port";
const string kSSLPort = RTMP_FIELD"sslport";
onceToken token1([](){ onceToken token1([](){
mINI::Instance()[kPort] = 1935; mINI::Instance()[kPort] = 1935;
mINI::Instance()[kSSLPort] = 19350;
},nullptr); },nullptr);
} //namespace RTMP } //namespace RTMP
@ -255,9 +257,10 @@ int start_main(int argc,char *argv[]) {
uint16_t rtspPort = mINI::Instance()[Rtsp::kPort]; uint16_t rtspPort = mINI::Instance()[Rtsp::kPort];
uint16_t rtspsPort = mINI::Instance()[Rtsp::kSSLPort]; uint16_t rtspsPort = mINI::Instance()[Rtsp::kSSLPort];
uint16_t rtmpPort = mINI::Instance()[Rtmp::kPort]; uint16_t rtmpPort = mINI::Instance()[Rtmp::kPort];
uint16_t rtmpsPort = mINI::Instance()[Rtmp::kSSLPort];
uint16_t httpPort = mINI::Instance()[Http::kPort]; uint16_t httpPort = mINI::Instance()[Http::kPort];
uint16_t httpsPort = mINI::Instance()[Http::kSSLPort]; uint16_t httpsPort = mINI::Instance()[Http::kSSLPort];
uint16_t rtp_proxy = mINI::Instance()[RtpProxy::kPort]; uint16_t rtpPort = mINI::Instance()[RtpProxy::kPort];
//设置poller线程数,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效 //设置poller线程数,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效
EventPollerPool::setPoolSize(threads); EventPollerPool::setPoolSize(threads);
@ -265,38 +268,51 @@ int start_main(int argc,char *argv[]) {
//简单的telnet服务器可用于服务器调试但是不能使用23端口否则telnet上了莫名其妙的现象 //简单的telnet服务器可用于服务器调试但是不能使用23端口否则telnet上了莫名其妙的现象
//测试方法:telnet 127.0.0.1 9000 //测试方法:telnet 127.0.0.1 9000
TcpServer::Ptr shellSrv(new TcpServer()); TcpServer::Ptr shellSrv(new TcpServer());
//rtsp[s]服务器, 可用于诸如亚马逊echo show这样的设备访问
TcpServer::Ptr rtspSrv(new TcpServer()); 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()); 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) #if defined(ENABLE_RTPPROXY)
//GB28181 rtp推流端口支持UDP/TCP
UdpRecver recver; UdpRecver recver;
TcpServer::Ptr tcpRtpServer(new TcpServer()); TcpServer::Ptr tcpRtpServer(new TcpServer());
#endif//defined(ENABLE_RTPPROXY) #endif//defined(ENABLE_RTPPROXY)
try { try {
//rtsp服务器端口默认554 //rtsp服务器端口默认554
rtspSrv->start<RtspSession>(rtspPort);//默认554 if(rtspPort) { rtspSrv->start<RtspSession>(rtspPort); }
//rtsps服务器端口默认322 //rtsps服务器端口默认322
rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort); if(rtspsPort) { rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort); }
//rtmp服务器端口默认1935 //rtmp服务器端口默认1935
rtmpSrv->start<RtmpSession>(rtmpPort); if(rtmpPort) { rtmpSrv->start<RtmpSession>(rtmpPort); }
//rtmps服务器端口默认19350
if(rtmpsPort) { rtmpsSrv->start<RtmpSessionWithSSL>(rtmpsPort); }
//http服务器端口默认80 //http服务器端口默认80
httpSrv->start<HttpSession>(httpPort); if(httpPort) { httpSrv->start<HttpSession>(httpPort); }
//https服务器端口默认443 //https服务器端口默认443
httpsSrv->start<HttpsSession>(httpsPort); if(httpsPort) { httpsSrv->start<HttpsSession>(httpsPort); }
//telnet远程调试服务器 //telnet远程调试服务器
shellSrv->start<ShellSession>(shellPort); if(shellPort) { shellSrv->start<ShellSession>(shellPort); }
#if defined(ENABLE_RTPPROXY) #if defined(ENABLE_RTPPROXY)
if(rtpPort){
//创建rtp udp服务器 //创建rtp udp服务器
recver.initSock(rtp_proxy); recver.initSock(rtpPort);
//创建rtp tcp服务器 //创建rtp tcp服务器
tcpRtpServer->start<RtpSession>(rtp_proxy); tcpRtpServer->start<RtpSession>(rtpPort);
}
#endif//defined(ENABLE_RTPPROXY) #endif//defined(ENABLE_RTPPROXY)
}catch (std::exception &ex){ }catch (std::exception &ex){

View File

@ -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 FlushPolicy::isFlushAble(uint32_t new_stamp, int cache_size) {
bool ret = false; bool ret = false;
GET_CONFIG(bool, ultraLowDelay, General::kUltraLowDelay);
GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if (ultraLowDelay || mergeWriteMS <= 0) { if (mergeWriteMS <= 0) {
//关闭了合并写或者合并写阈值小于等于0 //关闭了合并写或者合并写阈值小于等于0
ret = isFlushAble_default(_is_audio, _last_stamp, new_stamp, cache_size); ret = isFlushAble_default(_is_audio, _last_stamp, new_stamp, cache_size);
} else { } else {

View File

@ -22,17 +22,21 @@ MultiMuxerPrivate::MultiMuxerPrivate(const string &vhost,
bool enable_mp4) { bool enable_mp4) {
if (enable_rtmp) { if (enable_rtmp) {
_rtmp = std::make_shared<RtmpMediaSourceMuxer>(vhost, app, stream, std::make_shared<TitleMeta>(dur_sec)); _rtmp = std::make_shared<RtmpMediaSourceMuxer>(vhost, app, stream, std::make_shared<TitleMeta>(dur_sec));
_enable_rtxp = true;
} }
if (enable_rtsp) { if (enable_rtsp) {
_rtsp = std::make_shared<RtspMediaSourceMuxer>(vhost, app, stream, std::make_shared<TitleSdp>(dur_sec)); _rtsp = std::make_shared<RtspMediaSourceMuxer>(vhost, app, stream, std::make_shared<TitleSdp>(dur_sec));
_enable_rtxp = true;
} }
if (enable_hls) { if (enable_hls) {
_hls = Recorder::createRecorder(Recorder::type_hls, vhost, app, stream); _hls = Recorder::createRecorder(Recorder::type_hls, vhost, app, stream);
_enable_record = true;
} }
if (enable_mp4) { if (enable_mp4) {
_mp4 = Recorder::createRecorder(Recorder::type_mp4, vhost, app, stream); _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); return (_rtsp ? _rtsp->readerCount() : 0) + (_rtmp ? _rtmp->readerCount() : 0) + (hls_src ? hls_src->readerCount() : 0);
} }
static std::shared_ptr<MediaSinkInterface> makeRecorder(const vector<Track::Ptr> &tracks, Recorder::type type, MediaSource &sender){ static std::shared_ptr<MediaSinkInterface> makeRecorder(const vector<Track::Ptr> &tracks, Recorder::type type, const string &custom_path, MediaSource &sender){
auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId()); auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId(), custom_path);
for (auto &track : tracks) { for (auto &track : tracks) {
recorder->addTrack(track); recorder->addTrack(track);
} }
@ -91,7 +95,7 @@ bool MultiMuxerPrivate::setupRecord(MediaSource &sender, Recorder::type type, bo
case Recorder::type_hls : { case Recorder::type_hls : {
if (start && !_hls) { if (start && !_hls) {
//开始录制 //开始录制
_hls = makeRecorder(getTracks(true), type, sender); _hls = makeRecorder(getTracks(true), type, custom_path, sender);
auto hls_src = getHlsMediaSource(); auto hls_src = getHlsMediaSource();
if (hls_src) { if (hls_src) {
//设置HlsMediaSource的事件监听器 //设置HlsMediaSource的事件监听器
@ -102,20 +106,21 @@ bool MultiMuxerPrivate::setupRecord(MediaSource &sender, Recorder::type type, bo
//停止录制 //停止录制
_hls = nullptr; _hls = nullptr;
} }
_enable_record = _hls || _mp4;
return true; return true;
} }
case Recorder::type_mp4 : { case Recorder::type_mp4 : {
if (start && !_mp4) { if (start && !_mp4) {
//开始录制 //开始录制
_mp4 = makeRecorder(getTracks(true), type, sender);; _mp4 = makeRecorder(getTracks(true), type, custom_path, sender);
} else if (!start && _mp4) { } else if (!start && _mp4) {
//停止录制 //停止录制
_mp4 = nullptr; _mp4 = nullptr;
} }
_enable_record = _hls || _mp4;
return true; return true;
} }
default: default : return false;
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) { void MultiMuxerPrivate::onTrackFrame(const Frame::Ptr &frame) {
if (_rtmp) { if (_rtmp) {
_rtmp->inputFrame(frame); _rtmp->inputFrame(frame);
@ -293,4 +302,9 @@ void MultiMediaSourceMuxer::inputFrame(const Frame::Ptr &frame) {
_muxer->inputFrame(frame); _muxer->inputFrame(frame);
} }
bool MultiMediaSourceMuxer::isEnabled(){
return _muxer->isEnabled();
}
}//namespace mediakit }//namespace mediakit

View File

@ -45,6 +45,7 @@ private:
void setTrackListener(Listener *listener); void setTrackListener(Listener *listener);
bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path); bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path);
bool isRecording(MediaSource &sender, Recorder::type type); bool isRecording(MediaSource &sender, Recorder::type type);
bool isEnabled();
private: private:
void onTrackReady(const Track::Ptr & track) override; void onTrackReady(const Track::Ptr & track) override;
void onTrackFrame(const Frame::Ptr &frame) override; void onTrackFrame(const Frame::Ptr &frame) override;
@ -57,6 +58,8 @@ private:
MediaSinkInterface::Ptr _mp4; MediaSinkInterface::Ptr _mp4;
Listener *_listener = nullptr; Listener *_listener = nullptr;
std::weak_ptr<MediaSourceEvent> _meida_listener; std::weak_ptr<MediaSourceEvent> _meida_listener;
bool _enable_rtxp = false;
bool _enable_record = false;
}; };
class MultiMediaSourceMuxer : public MediaSourceEvent, public MediaSinkInterface, public TrackSource, public std::enable_shared_from_this<MultiMediaSourceMuxer>{ class MultiMediaSourceMuxer : public MediaSourceEvent, public MediaSinkInterface, public TrackSource, public std::enable_shared_from_this<MultiMediaSourceMuxer>{
@ -167,6 +170,11 @@ public:
* @param frame * @param frame
*/ */
void inputFrame(const Frame::Ptr &frame) override; void inputFrame(const Frame::Ptr &frame) override;
/**
* ()
*/
bool isEnabled();
private: private:
MultiMuxerPrivate::Ptr _muxer; MultiMuxerPrivate::Ptr _muxer;
std::weak_ptr<MediaSourceEvent> _listener; std::weak_ptr<MediaSourceEvent> _listener;

View File

@ -96,58 +96,84 @@ int64_t Stamp::getRelativeStamp() const {
return _relativeStamp; return _relativeStamp;
} }
bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){ bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){
bool ret = false; bool ret = false;
if(pts == _last_pts){ if (pts == _last_pts) {
//pts未变返回上次结果 //pts未变说明dts也不会变返回上次dts
if(_last_dts){ if (_last_dts) {
dts = _last_dts; dts = _last_dts;
ret = true; ret = true;
} }
return ret; } else {
} //pts变了尝试计算dts
ret = getDts_l(pts, dts);
ret = getDts_l(pts,dts); if (ret) {
if(ret){ //获取到了dts保存本次结果
//保存本次结果
_last_dts = dts; _last_dts = dts;
} }
}
if (!ret) {
//pts排序列队长度还不知道也就是不知道有没有B帧
//那么先强制dts == pts这样可能导致有B帧的情况下起始画面有几帧回退
dts = pts;
}
//记录上次pts //记录上次pts
_last_pts = pts; _last_pts = pts;
return ret; return ret;
} }
//该算法核心思想是对pts进行排序排序好的pts就是dts。
//排序有一定的滞后性,那么需要加上排序导致的时间戳偏移量
bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){ bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){
if(_sorter_max_size == 1){ if(_sorter_max_size == 1){
//没有B帧 //没有B帧dts就等于pts
dts = pts; dts = pts;
return true; return true;
} }
if(!_sorter_max_size){ if(!_sorter_max_size){
//尚未计算出pts排序列队长度(也就是P帧间B帧个数)
if(pts > _last_max_pts){ if(pts > _last_max_pts){
//pts时间戳增加了那么说明这帧画面不是B帧(说明是P帧或关键帧)
if(_frames_since_last_max_pts && _count_sorter_max_size++ > 0){ if(_frames_since_last_max_pts && _count_sorter_max_size++ > 0){
//已经出现多次非B帧的情况那么我们就能知道P帧间B帧的个数
_sorter_max_size = _frames_since_last_max_pts; _sorter_max_size = _frames_since_last_max_pts;
//我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计)
_dts_pts_offset = (pts - _last_max_pts) / 2; _dts_pts_offset = (pts - _last_max_pts) / 2;
} }
//遇到P帧或关键帧连续B帧计数清零
_frames_since_last_max_pts = 0; _frames_since_last_max_pts = 0;
//记录上次非B帧的pts时间戳(同时也是dts)用于统计连续B帧时间戳增量
_last_max_pts = pts; _last_max_pts = pts;
} }
//如果pts时间戳小于上一个P帧那么断定这个是B帧,我们记录B帧连续个数
++_frames_since_last_max_pts; ++_frames_since_last_max_pts;
} }
//pts放入排序缓存列队缓存列队最大等于连续B帧个数
_pts_sorter.emplace(pts); _pts_sorter.emplace(pts);
if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){ if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){
//如果启用了pts排序(意味着存在B帧)并且pts排序缓存列队长度大于连续B帧个数
//意味着后续的pts都会比最早的pts大那么说明可以取出最早的pts了这个pts将当做该帧的dts基准
auto it = _pts_sorter.begin(); auto it = _pts_sorter.begin();
//由于该pts是前面偏移了个_sorter_max_size帧的pts(也就是那帧画面的dts),
//那么我们加上时间戳偏移量基本等于该帧的dts
dts = *it + _dts_pts_offset; dts = *it + _dts_pts_offset;
if(dts > pts){ if(dts > pts){
//dts不能大于pts(基本不可能到达这个逻辑) //dts不能大于pts(基本不可能到达这个逻辑)
dts = pts; dts = pts;
} }
//pts排序缓存出列
_pts_sorter.erase(it); _pts_sorter.erase(it);
return true; return true;
} }
//排序缓存尚未满
return false; return false;
} }

View File

@ -61,7 +61,6 @@ const string kFlowThreshold = GENERAL_FIELD"flowThreshold";
const string kStreamNoneReaderDelayMS = GENERAL_FIELD"streamNoneReaderDelayMS"; const string kStreamNoneReaderDelayMS = GENERAL_FIELD"streamNoneReaderDelayMS";
const string kMaxStreamWaitTimeMS = GENERAL_FIELD"maxStreamWaitMS"; const string kMaxStreamWaitTimeMS = GENERAL_FIELD"maxStreamWaitMS";
const string kEnableVhost = GENERAL_FIELD"enableVhost"; const string kEnableVhost = GENERAL_FIELD"enableVhost";
const string kUltraLowDelay = GENERAL_FIELD"ultraLowDelay";
const string kAddMuteAudio = GENERAL_FIELD"addMuteAudio"; const string kAddMuteAudio = GENERAL_FIELD"addMuteAudio";
const string kResetWhenRePlay = GENERAL_FIELD"resetWhenRePlay"; const string kResetWhenRePlay = GENERAL_FIELD"resetWhenRePlay";
const string kPublishToRtxp = GENERAL_FIELD"publishToRtxp"; const string kPublishToRtxp = GENERAL_FIELD"publishToRtxp";
@ -74,13 +73,12 @@ onceToken token([](){
mINI::Instance()[kStreamNoneReaderDelayMS] = 20 * 1000; mINI::Instance()[kStreamNoneReaderDelayMS] = 20 * 1000;
mINI::Instance()[kMaxStreamWaitTimeMS] = 15 * 1000; mINI::Instance()[kMaxStreamWaitTimeMS] = 15 * 1000;
mINI::Instance()[kEnableVhost] = 0; mINI::Instance()[kEnableVhost] = 0;
mINI::Instance()[kUltraLowDelay] = 1;
mINI::Instance()[kAddMuteAudio] = 1; mINI::Instance()[kAddMuteAudio] = 1;
mINI::Instance()[kResetWhenRePlay] = 1; mINI::Instance()[kResetWhenRePlay] = 1;
mINI::Instance()[kPublishToRtxp] = 1; mINI::Instance()[kPublishToRtxp] = 1;
mINI::Instance()[kPublishToHls] = 1; mINI::Instance()[kPublishToHls] = 1;
mINI::Instance()[kPublishToMP4] = 0; mINI::Instance()[kPublishToMP4] = 0;
mINI::Instance()[kMergeWriteMS] = 300; mINI::Instance()[kMergeWriteMS] = 0;
},nullptr); },nullptr);
}//namespace General }//namespace General

View File

@ -160,8 +160,6 @@ extern const string kStreamNoneReaderDelayMS;
extern const string kMaxStreamWaitTimeMS; extern const string kMaxStreamWaitTimeMS;
//是否启动虚拟主机 //是否启动虚拟主机
extern const string kEnableVhost; extern const string kEnableVhost;
//超低延时模式,默认打开,打开后会降低延时但是转发性能会稍差
extern const string kUltraLowDelay;
//拉流代理时是否添加静音音频 //拉流代理时是否添加静音音频
extern const string kAddMuteAudio; extern const string kAddMuteAudio;
//拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始, //拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
@ -174,7 +172,7 @@ extern const string kPublishToHls ;
//是否默认推流时mp4录像hook接口(on_publish)中可以覆盖该设置 //是否默认推流时mp4录像hook接口(on_publish)中可以覆盖该设置
extern const string kPublishToMP4 ; extern const string kPublishToMP4 ;
//合并写缓存大小(单位毫秒)合并写指服务器缓存一定的数据后才会一次性写入socket这样能提高性能但是会提高延时 //合并写缓存大小(单位毫秒)合并写指服务器缓存一定的数据后才会一次性写入socket这样能提高性能但是会提高延时
//在开启低延时模式后,该参数不起作用 //开启后会同时关闭TCP_NODELAY并开启MSG_MORE
extern const string kMergeWriteMS ; extern const string kMergeWriteMS ;
}//namespace General }//namespace General

View File

@ -50,6 +50,9 @@ void splitH264(const char *ptr, int len, const std::function<void(const char *,
while(true) { while(true) {
auto next_nal = memfind(nal + 3,end - nal - 3,"\x0\x0\x1",3); auto next_nal = memfind(nal + 3,end - nal - 3,"\x0\x0\x1",3);
if(next_nal){ if(next_nal){
if(*(next_nal - 1) == 0x00){
next_nal -= 1;
}
cb(nal,next_nal - nal); cb(nal,next_nal - nal);
nal = next_nal; nal = next_nal;
continue; continue;
@ -59,6 +62,18 @@ void splitH264(const char *ptr, int len, const std::function<void(const char *,
} }
} }
#if 0
//splitH264函数测试程序
static onceToken s_token([](){
char buf[] = "\x00\x00\x00\x01\x12\x23\x34\x45\x56"
"\x00\x00\x00\x01\x12\x23\x34\x45\x56"
"\x00\x00\x00\x01\x12\x23\x34\x45\x56"
"\x00\x00\x01\x12\x23\x34\x45\x56";
splitH264(buf, sizeof(buf) - 1, [](const char *ptr, int len){
cout << hexdump(ptr, len) << endl;
});
});
#endif //0
Sdp::Ptr H264Track::getSdp() { Sdp::Ptr H264Track::getSdp() {
if(!ready()){ if(!ready()){

View File

@ -191,19 +191,10 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
} }
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) { void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts); //rtsp没有dts那么根据pts排序算法生成dts
if(!flag){ _dts_generator.getDts(frame->_pts,frame->_dts);
if(frame->configFrame() || frame->keyFrame()){
flag = true;
frame->_dts = frame->_pts;
}
}
//根据pts计算dts
if(flag){
//写入环形缓存 //写入环形缓存
RtpCodec::inputFrame(frame); RtpCodec::inputFrame(frame);
}
_h264frame = obtainFrame(); _h264frame = obtainFrame();
} }

View File

@ -46,6 +46,9 @@ public:
NAL_IDR_W_RADL = 19, NAL_IDR_W_RADL = 19,
NAL_IDR_N_LP = 20, NAL_IDR_N_LP = 20,
NAL_CRA_NUT = 21, NAL_CRA_NUT = 21,
NAL_RSV_IRAP_VCL22 = 22,
NAL_RSV_IRAP_VCL23 = 23,
NAL_VPS = 32, NAL_VPS = 32,
NAL_SPS = 33, NAL_SPS = 33,
NAL_PPS = 34, NAL_PPS = 34,
@ -101,17 +104,7 @@ public:
} }
static bool isKeyFrame(int type) { static bool isKeyFrame(int type) {
switch (type) { return type >= NAL_BLA_W_LP && type <= NAL_RSV_IRAP_VCL23;
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;
}
} }
public: public:

View File

@ -127,18 +127,10 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
} }
void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) { void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) {
//计算dts //rtsp没有dts那么根据pts排序算法生成dts
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts); _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); RtpCodec::inputFrame(frame);
}
_h265frame = obtainFrame(); _h265frame = obtainFrame();
} }

View File

@ -606,8 +606,8 @@ void HttpSession::sendNotFound(bool bClose) {
} }
void HttpSession::setSocketFlags(){ void HttpSession::setSocketFlags(){
GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if(!ultraLowDelay) { if(mergeWriteMS > 0) {
//推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高 //推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);
//播放模式下开启MSG_MORE会增加延时但是能提高发送性能 //播放模式下开启MSG_MORE会增加延时但是能提高发送性能

View File

@ -56,7 +56,7 @@ string Recorder::getRecordPath(Recorder::type type, const string &vhost, const s
} }
std::shared_ptr<MediaSinkInterface> Recorder::createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path){ std::shared_ptr<MediaSinkInterface> 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) { switch (type) {
case Recorder::type_hls: { case Recorder::type_hls: {
#if defined(ENABLE_HLS) #if defined(ENABLE_HLS)

View File

@ -57,7 +57,14 @@ public:
* rtmp并解析 * rtmp并解析
*/ */
void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos = true) override { void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos = true) override {
if(_all_track_ready && !_muxer->isEnabled()){
//获取到所有Track后并且未开启转协议那么不需要解复用rtmp
key_pos = pkt->isVideoKeyFrame();
}else{
//需要解复用rtmp
key_pos = _demuxer->inputRtmp(pkt); key_pos = _demuxer->inputRtmp(pkt);
}
RtmpMediaSource::onWrite(pkt,key_pos); RtmpMediaSource::onWrite(pkt,key_pos);
} }
@ -138,10 +145,12 @@ public:
*/ */
void onAllTrackReady() override{ void onAllTrackReady() override{
setTrackSource(_muxer); setTrackSource(_muxer);
_all_track_ready = true;
} }
private: private:
RtmpDemuxer::Ptr _demuxer; RtmpDemuxer::Ptr _demuxer;
MultiMediaSourceMuxer::Ptr _muxer; MultiMediaSourceMuxer::Ptr _muxer;
bool _all_track_ready = false;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -228,8 +228,8 @@ inline void RtmpPusher::send_metaData(){
} }
void RtmpPusher::setSocketFlags(){ void RtmpPusher::setSocketFlags(){
GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if(!ultraLowDelay) { if(mergeWriteMS > 0) {
//提高发送性能 //提高发送性能
setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);

View File

@ -529,8 +529,8 @@ int RtmpSession::totalReaderCount(MediaSource &sender) {
} }
void RtmpSession::setSocketFlags(){ void RtmpSession::setSocketFlags(){
GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if(!ultraLowDelay) { if(mergeWriteMS > 0) {
//推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高 //推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);
//播放模式下开启MSG_MORE会增加延时但是能提高发送性能 //播放模式下开启MSG_MORE会增加延时但是能提高发送性能

View File

@ -91,6 +91,12 @@ private:
}; };
/**
* ssl加密的rtmp服务器
*/
typedef TcpSessionWithSSL<RtmpSession> RtmpSessionWithSSL;
} /* namespace mediakit */ } /* namespace mediakit */
#endif /* SRC_RTMP_RTMPSESSION_H_ */ #endif /* SRC_RTMP_RTMPSESSION_H_ */

View File

@ -48,7 +48,14 @@ public:
* rtp并解析 * rtp并解析
*/ */
void onWrite(const RtpPacket::Ptr &rtp, bool key_pos) override { void onWrite(const RtpPacket::Ptr &rtp, bool key_pos) override {
if(_all_track_ready && !_muxer->isEnabled()){
//获取到所有Track后并且未开启转协议那么不需要解复用rtp
//在关闭rtp解复用后无法知道是否为关键帧这样会导致无法秒开或者开播花屏
key_pos = rtp->type == TrackVideo;
}else{
//需要解复用rtp
key_pos = _demuxer->inputRtp(rtp); key_pos = _demuxer->inputRtp(rtp);
}
RtspMediaSource::onWrite(rtp, key_pos); RtspMediaSource::onWrite(rtp, key_pos);
} }
@ -129,10 +136,12 @@ public:
*/ */
void onAllTrackReady() override{ void onAllTrackReady() override{
setTrackSource(_muxer); setTrackSource(_muxer);
_all_track_ready = true;
} }
private: private:
RtspDemuxer::Ptr _demuxer; RtspDemuxer::Ptr _demuxer;
MultiMediaSourceMuxer::Ptr _muxer; MultiMediaSourceMuxer::Ptr _muxer;
bool _all_track_ready = false;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -392,8 +392,8 @@ void RtspPusher::sendRecord() {
} }
void RtspPusher::setSocketFlags(){ void RtspPusher::setSocketFlags(){
GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if(!ultraLowDelay) { if(mergeWriteMS > 0) {
//提高发送性能 //提高发送性能
setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);

View File

@ -1236,8 +1236,8 @@ void RtspSession::sendSenderReport(bool overTcp,int iTrackIndex) {
} }
void RtspSession::setSocketFlags(){ void RtspSession::setSocketFlags(){
GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if(!ultraLowDelay) { if(mergeWriteMS > 0) {
//推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高 //推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);
//播放模式下开启MSG_MORE会增加延时但是能提高发送性能 //播放模式下开启MSG_MORE会增加延时但是能提高发送性能