全面整理转协议相关配置文件

This commit is contained in:
xiongziliang 2022-11-12 23:54:35 +08:00
parent 946945ce7b
commit 9bb6a2f828
20 changed files with 373 additions and 298 deletions

View File

@ -29,6 +29,56 @@ log=./ffmpeg/ffmpeg.log
# 自动重启的时间(秒), 默认为0, 也就是不自动重启. 主要是为了避免长时间ffmpeg拉流导致的不同步现象
restart_sec=0
#转协议相关开关如果addStreamProxy api和on_publish hook回复未指定转协议参数则采用这些配置项
[protocol]
#转协议时,是否开启帧级时间戳覆盖
modify_stamp=0
#转协议是否开启音频
enable_audio=1
#添加acc静音音频在关闭音频时此开关无效
add_mute_audio=1
#推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
#置0关闭此特性(推流断开会导致立即断开播放器)
#此参数不应大于播放器超时时间;单位毫秒
continue_push_ms=15000
#是否开启转换为hls
enable_hls=1
#是否开启MP4录制
enable_mp4=0
#是否开启转换为rtsp/webrtc
enable_rtsp=1
#是否开启转换为rtmp/flv
enable_rtmp=1
#是否开启转换为http-ts/ws-ts
enable_ts=1
#是否开启转换为http-fmp4/ws-fmp4
enable_fmp4=1
#是否将mp4录制当做观看者
mp4_as_player=0
#mp4切片大小单位秒
mp4_max_second=3600
#mp4录制保存路径
mp4_save_path=./www
#hls录制保存路径
hls_save_path=./www
###### 以下是按需转协议的开关在测试ZLMediaKit的接收推流性能时请把下面开关置1
###### 如果某种协议你用不到你可以把以下开关置1以便节省资源(但是还是可以播放,只是第一个播放者体验稍微差点)
###### 如果某种协议你想获取最好的用户体验请置0(第一个播放者可以秒开,且不花屏)
#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
[general]
#是否启用虚拟主机
enableVhost=0
@ -44,43 +94,14 @@ maxStreamWaitMS=15000
#某个流无人观看时触发hook.on_stream_none_reader事件的最大等待时间单位毫秒
#在配合hook.on_stream_none_reader事件时可以做到无人观看自动停止拉流或停止接收推流
streamNoneReaderDelayMS=20000
#是否全局添加静音aac音频转协议时有效
#有些播放器在打开单视频流时不能秒开,添加静音音频可以加快秒开速度
addMuteAudio=1
#拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
#如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
resetWhenRePlay=1
#是否默认推流时转换成hlshook接口(on_publish)中可以覆盖该设置
publishToHls=1
#是否默认推流时mp4录像hook接口(on_publish)中可以覆盖该设置
publishToMP4=0
#合并写缓存大小(单位毫秒)合并写指服务器缓存一定的数据后才会一次性写入socket这样能提高性能但是会提高延时
#开启后会同时关闭TCP_NODELAY并开启MSG_MORE
mergeWriteMS=0
#全局的时间戳覆盖开关在转协议时对frame进行时间戳覆盖
#该开关对rtsp/rtmp/rtp推流、rtsp/rtmp/hls拉流代理转协议时生效
#会直接影响rtsp/rtmp/hls/mp4/flv等协议的时间戳
#同协议情况下不影响(例如rtsp/rtmp推流那么播放rtsp/rtmp时不会影响时间戳)
modifyStamp=0
#服务器唯一id用于触发hook时区别是哪台服务器
mediaServerId=your_server_id
#转协议是否全局开启或关闭音频
enable_audio=1
###### 以下是按需转协议的开关在测试ZLMediaKit的接收推流性能时请把下面开关置1
###### 如果某种协议你用不到你可以把以下开关置1以便节省资源(但是还是可以播放,只是第一个播放者体验稍微差点)
###### 如果某种协议你想获取最好的用户体验请置0(第一个播放者可以秒开,且不花屏)
#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
#最多等待未初始化的Track时间单位毫秒超时之后会忽略未初始化的Track
wait_track_ready_ms=10000
@ -89,17 +110,10 @@ wait_track_ready_ms=10000
wait_add_track_ms=3000
#如果track未就绪我们先缓存帧数据但是有最大个数限制防止内存溢出
unready_frame_cache=100
#推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
#置0关闭此特性(推流断开会导致立即断开播放器)
#此参数不应大于播放器超时时间
continue_push_ms=15000
[hls]
#hls写文件的buf大小调整参数可以提高文件io性能
fileBufSize=65536
#hls保存文件路径
#可以为相对(相对于本可执行程序目录)或绝对路径
filePath=./www
#hls最大切片时间
segDur=2
#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个)
@ -155,7 +169,6 @@ on_server_started=https://127.0.0.1/index/hook/on_server_started
on_server_keepalive=https://127.0.0.1/index/hook/on_server_keepalive
#发送rtp(startSendRtp)被动关闭时回调
on_send_rtp_stopped=https://127.0.0.1/index/hook/on_send_rtp_stopped
#rtp server 超时未收到数据
on_rtp_server_timeout=https://127.0.0.1/index/hook/on_rtp_server_timeout
@ -232,11 +245,6 @@ udpTTL=64
appName=record
#mp4录制写文件缓存单位BYTE,调整参数可以提高文件io性能
fileBufSize=65536
#mp4录制保存、mp4点播根路径
#可以为相对(相对于本可执行程序目录)或绝对路径
filePath=./www
#mp4录制切片时间单位秒
fileSecond=3600
#mp4点播每次流化数据量单位毫秒
#减少该值可以让点播数据发送量更平滑增大该值则更节省cpu资源
sampleMS=500
@ -244,8 +252,6 @@ sampleMS=500
fastStart=0
#MP4点播(rtsp/rtmp/http-flv/ws-flv)是否循环播放文件
fileRepeat=0
#MP4录制是否当做播放器参与播放人数统计
mp4_as_player=0
[rtmp]
#rtmp必须在此时间内完成握手否则服务器会断开链接单位秒
@ -281,25 +287,18 @@ timeoutSec=15
#随机端口范围最少确保36个端口
#该范围同时限制rtsp服务器udp端口范围
port_range=30000-35000
#rtp h264 负载的pt
h264_pt=98
#rtp h265 负载的pt
h265_pt=99
#rtp ps 负载的pt
ps_pt=96
#rtp ts 负载的pt
ts_pt=33
#rtp opus 负载的pt
opus_pt=100
#rtp g711u 负载的pt
g711u_pt=0
#rtp g711a 负载的pt
g711a_pt=8
@ -330,10 +329,8 @@ timeoutSec=5
#srt udp服务器监听端口号所有srt客户端将通过该端口传输srt数据
#该端口是多线程的,同时支持客户端网络切换导致的连接迁移
port=9000
#srt 协议中延迟缓存的估算参数在握手阶段估算rtt ,然后latencyMul*rtt 为最大缓存时长,此参数越大,表示等待重传的时长就越大
latencyMul=4
#包缓存的大小
pktBufSize=8192

View File

@ -8,12 +8,13 @@
* may be found in the AUTHORS file in the root of the source tree.
*/
#include "MediaSource.h"
#include "Record/MP4Reader.h"
#include "Util/util.h"
#include "Util/NoticeCenter.h"
#include "Network/sockutil.h"
#include "Network/TcpSession.h"
#include "Util/NoticeCenter.h"
#include "MediaSource.h"
#include "Common/config.h"
#include "Record/MP4Reader.h"
using namespace std;
using namespace toolkit;
@ -49,6 +50,59 @@ string getOriginTypeString(MediaOriginType type){
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
ProtocolOption::ProtocolOption() {
GET_CONFIG(bool, s_modify_stamp, Protocol::kModifyStamp);
GET_CONFIG(bool, s_enabel_audio, Protocol::kEnableAudio);
GET_CONFIG(bool, s_add_mute_audio, Protocol::kAddMuteAudio);
GET_CONFIG(uint32_t, s_continue_push_ms, Protocol::kContinuePushMS);
GET_CONFIG(bool, s_enable_hls, Protocol::kEnableHls);
GET_CONFIG(bool, s_enable_mp4, Protocol::kEnableMP4);
GET_CONFIG(bool, s_enable_rtsp, Protocol::kEnableRtsp);
GET_CONFIG(bool, s_enable_rtmp, Protocol::kEnableRtmp);
GET_CONFIG(bool, s_enable_ts, Protocol::kEnableTS);
GET_CONFIG(bool, s_enable_fmp4, Protocol::kEnableFMP4);
GET_CONFIG(bool, s_hls_demand, Protocol::kHlsDemand);
GET_CONFIG(bool, s_rtsp_demand, Protocol::kRtspDemand);
GET_CONFIG(bool, s_rtmp_demand, Protocol::kRtmpDemand);
GET_CONFIG(bool, s_ts_demand, Protocol::kTSDemand);
GET_CONFIG(bool, s_fmp4_demand, Protocol::kFMP4Demand);
GET_CONFIG(bool, s_mp4_as_player, Protocol::kMP4AsPlayer);
GET_CONFIG(uint32_t, s_mp4_max_second, Protocol::kMP4MaxSecond);
GET_CONFIG(string, s_mp4_save_path, Protocol::kMP4SavePath);
GET_CONFIG(string, s_hls_save_path, Protocol::kHlsSavePath);
modify_stamp = s_modify_stamp;
enable_audio = s_enabel_audio;
add_mute_audio = s_add_mute_audio;
continue_push_ms = s_continue_push_ms;
enable_hls = s_enable_hls;
enable_mp4 = s_enable_mp4;
enable_rtsp = s_enable_rtsp;
enable_rtmp = s_enable_rtmp;
enable_ts = s_enable_ts;
enable_fmp4 = s_enable_fmp4;
hls_demand = s_hls_demand;
rtsp_demand = s_rtsp_demand;
rtmp_demand = s_rtmp_demand;
ts_demand = s_ts_demand;
fmp4_demand = s_fmp4_demand;
mp4_as_player = s_mp4_as_player;
mp4_max_second = s_mp4_max_second;
mp4_save_path = s_mp4_save_path;
hls_save_path = s_hls_save_path;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct MediaSourceNull : public MediaSource {
MediaSourceNull() : MediaSource("schema", "vhost", "app", "stream") {};
int readerCount() override { return 0; }

View File

@ -134,6 +134,91 @@ private:
toolkit::Timer::Ptr _async_close_timer;
};
class ProtocolOption {
public:
ProtocolOption();
//时间戳修复这一路流标志位
bool modify_stamp;
//转协议是否开启音频
bool enable_audio;
//添加静音音频,在关闭音频时,此开关无效
bool add_mute_audio;
//断连续推延时,单位毫秒,默认采用配置文件
uint32_t continue_push_ms;
//是否开启转换为hls
bool enable_hls;
//是否开启MP4录制
bool enable_mp4;
//是否开启转换为rtsp/webrtc
bool enable_rtsp;
//是否开启转换为rtmp/flv
bool enable_rtmp;
//是否开启转换为http-ts/ws-ts
bool enable_ts;
//是否开启转换为http-fmp4/ws-fmp4
bool enable_fmp4;
// hls协议是否按需生成如果hls.segNum配置为0(意味着hls录制)那么hls将一直生成(不管此开关)
bool hls_demand;
// rtsp[s]协议是否按需生成
bool rtsp_demand;
// rtmp[s]、http[s]-flv、ws[s]-flv协议是否按需生成
bool rtmp_demand;
// http[s]-ts协议是否按需生成
bool ts_demand;
// http[s]-fmp4、ws[s]-fmp4协议是否按需生成
bool fmp4_demand;
//是否将mp4录制当做观看者
bool mp4_as_player;
//mp4切片大小单位秒
size_t mp4_max_second;
//mp4录制保存路径
std::string mp4_save_path;
//hls录制保存路径
std::string hls_save_path;
template <typename MAP>
ProtocolOption(const MAP &allArgs) : ProtocolOption() {
#define GET_OPT_VALUE(key) getArgsValue(allArgs, #key, key)
GET_OPT_VALUE(modify_stamp);
GET_OPT_VALUE(enable_audio);
GET_OPT_VALUE(add_mute_audio);
GET_OPT_VALUE(continue_push_ms);
GET_OPT_VALUE(enable_hls);
GET_OPT_VALUE(enable_mp4);
GET_OPT_VALUE(enable_rtsp);
GET_OPT_VALUE(enable_rtmp);
GET_OPT_VALUE(enable_ts);
GET_OPT_VALUE(enable_fmp4);
GET_OPT_VALUE(hls_demand);
GET_OPT_VALUE(rtsp_demand);
GET_OPT_VALUE(rtmp_demand);
GET_OPT_VALUE(ts_demand);
GET_OPT_VALUE(fmp4_demand);
GET_OPT_VALUE(mp4_max_second);
GET_OPT_VALUE(mp4_as_player);
GET_OPT_VALUE(mp4_save_path);
GET_OPT_VALUE(hls_save_path);
}
private:
template <typename MAP, typename KEY, typename TYPE>
static void getArgsValue(const MAP &allArgs, const KEY &key, TYPE &value) {
auto val = ((MAP &)allArgs)[key];
if (!val.empty()) {
value = (TYPE)val;
}
}
};
//该对象用于拦截感兴趣的MediaSourceEvent事件
class MediaSourceEventInterceptor : public MediaSourceEvent {
public:

View File

@ -21,26 +21,8 @@ namespace toolkit {
namespace mediakit {
ProtocolOption::ProtocolOption() {
GET_CONFIG(bool, s_to_hls, General::kPublishToHls);
GET_CONFIG(bool, s_to_mp4, General::kPublishToMP4);
GET_CONFIG(bool, s_enabel_audio, General::kEnableAudio);
GET_CONFIG(bool, s_add_mute_audio, General::kAddMuteAudio);
GET_CONFIG(bool, s_mp4_as_player, Record::kMP4AsPlayer);
GET_CONFIG(uint32_t, s_continue_push_ms, General::kContinuePushMS);
GET_CONFIG(bool, s_modify_stamp, General::kModifyStamp);
enable_hls = s_to_hls;
enable_mp4 = s_to_mp4;
enable_audio = s_enabel_audio;
add_mute_audio = s_add_mute_audio;
continue_push_ms = s_continue_push_ms;
mp4_as_player = s_mp4_as_player;
modify_stamp = s_modify_stamp;
}
static std::shared_ptr<MediaSinkInterface> makeRecorder(MediaSource &sender, const vector<Track::Ptr> &tracks, Recorder::type type, const string &custom_path, size_t max_second){
auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId(), custom_path, max_second);
static std::shared_ptr<MediaSinkInterface> makeRecorder(MediaSource &sender, const vector<Track::Ptr> &tracks, Recorder::type type, const ProtocolOption &option){
auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId(), option);
for (auto &track : tracks) {
recorder->addTrack(track);
}
@ -106,23 +88,23 @@ MultiMediaSourceMuxer::MultiMediaSourceMuxer(const string &vhost, const string &
_option = option;
if (option.enable_rtmp) {
_rtmp = std::make_shared<RtmpMediaSourceMuxer>(vhost, app, stream, std::make_shared<TitleMeta>(dur_sec));
_rtmp = std::make_shared<RtmpMediaSourceMuxer>(vhost, app, stream, option, std::make_shared<TitleMeta>(dur_sec));
}
if (option.enable_rtsp) {
_rtsp = std::make_shared<RtspMediaSourceMuxer>(vhost, app, stream, std::make_shared<TitleSdp>(dur_sec));
_rtsp = std::make_shared<RtspMediaSourceMuxer>(vhost, app, stream, option, std::make_shared<TitleSdp>(dur_sec));
}
if (option.enable_hls) {
_hls = dynamic_pointer_cast<HlsRecorder>(Recorder::createRecorder(Recorder::type_hls, vhost, app, stream, option.hls_save_path));
_hls = dynamic_pointer_cast<HlsRecorder>(Recorder::createRecorder(Recorder::type_hls, vhost, app, stream, option));
}
if (option.enable_mp4) {
_mp4 = Recorder::createRecorder(Recorder::type_mp4, vhost, app, stream, option.mp4_save_path, option.mp4_max_second);
_mp4 = Recorder::createRecorder(Recorder::type_mp4, vhost, app, stream, option);
}
if (option.enable_ts) {
_ts = std::make_shared<TSMediaSourceMuxer>(vhost, app, stream);
_ts = std::make_shared<TSMediaSourceMuxer>(vhost, app, stream, option);
}
#if defined(ENABLE_MP4)
if (option.enable_fmp4) {
_fmp4 = std::make_shared<FMP4MediaSourceMuxer>(vhost, app, stream);
_fmp4 = std::make_shared<FMP4MediaSourceMuxer>(vhost, app, stream, option);
}
#endif
@ -212,7 +194,8 @@ bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type
case Recorder::type_hls : {
if (start && !_hls) {
//开始录制
auto hls = dynamic_pointer_cast<HlsRecorder>(makeRecorder(sender, getTracks(), type, custom_path, max_second));
_option.hls_save_path = custom_path;
auto hls = dynamic_pointer_cast<HlsRecorder>(makeRecorder(sender, getTracks(), type, _option));
if (hls) {
//设置HlsMediaSource的事件监听器
hls->setListener(shared_from_this());
@ -227,7 +210,9 @@ bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type
case Recorder::type_mp4 : {
if (start && !_mp4) {
//开始录制
_mp4 = makeRecorder(sender, getTracks(), type, custom_path, max_second);
_option.mp4_save_path = custom_path;
_option.mp4_max_second = max_second;
_mp4 = makeRecorder(sender, getTracks(), type, _option);
} else if (!start && _mp4) {
//停止录制
_mp4 = nullptr;

View File

@ -23,73 +23,6 @@
namespace mediakit {
class ProtocolOption {
public:
ProtocolOption();
//是否开启转换为hls
bool enable_hls = false;
//是否开启MP4录制
bool enable_mp4 = false;
//是否将mp4录制当做观看者
bool mp4_as_player = false;
//是否开启转换为rtsp/webrtc
bool enable_rtsp = true;
//是否开启转换为rtmp/flv
bool enable_rtmp = true;
//是否开启转换为http-ts/ws-ts
bool enable_ts = true;
//是否开启转换为http-fmp4/ws-fmp4
bool enable_fmp4 = true;
//转协议是否开启音频
bool enable_audio = true;
//添加静音音频,在关闭音频时,此开关无效
bool add_mute_audio = true;
//mp4录制保存路径
std::string mp4_save_path;
//mp4切片大小单位秒
size_t mp4_max_second = 0;
//hls录制保存路径
std::string hls_save_path;
//断连续推延时,单位毫秒,默认采用配置文件
uint32_t continue_push_ms;
//时间戳修复这一路流标志位
bool modify_stamp;
template <typename MAP>
ProtocolOption(const MAP &allArgs) : ProtocolOption() {
#define GET_OPT_VALUE(key) getArgsValue(allArgs, #key, key)
GET_OPT_VALUE(enable_hls);
GET_OPT_VALUE(enable_mp4);
GET_OPT_VALUE(mp4_as_player);
GET_OPT_VALUE(enable_rtsp);
GET_OPT_VALUE(enable_rtmp);
GET_OPT_VALUE(enable_ts);
GET_OPT_VALUE(enable_fmp4);
GET_OPT_VALUE(enable_audio);
GET_OPT_VALUE(add_mute_audio);
GET_OPT_VALUE(mp4_save_path);
GET_OPT_VALUE(mp4_max_second);
GET_OPT_VALUE(hls_save_path);
GET_OPT_VALUE(continue_push_ms);
GET_OPT_VALUE(modify_stamp);
}
private:
template <typename MAP, typename KEY, typename TYPE>
static void getArgsValue(const MAP &allArgs, const KEY &key, TYPE &value) {
auto val = ((MAP &)allArgs)[key];
if (!val.empty()) {
value = (TYPE)val;
}
}
};
class MultiMediaSourceMuxer : public MediaSourceEventInterceptor, public MediaSink, public std::enable_shared_from_this<MultiMediaSourceMuxer>{
public:
typedef std::shared_ptr<MultiMediaSourceMuxer> Ptr;

View File

@ -68,53 +68,84 @@ 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 kAddMuteAudio = GENERAL_FIELD "addMuteAudio";
const string kResetWhenRePlay = GENERAL_FIELD "resetWhenRePlay";
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";
const string kEnableAudio = GENERAL_FIELD "enable_audio";
const string kCheckNvidiaDev = GENERAL_FIELD "check_nvidia_dev";
const string kEnableFFmpegLog = GENERAL_FIELD "enable_ffmpeg_log";
const string kWaitTrackReadyMS = GENERAL_FIELD "wait_track_ready_ms";
const string kWaitAddTrackMS = GENERAL_FIELD "wait_add_track_ms";
const string kUnreadyFrameCache = GENERAL_FIELD "unready_frame_cache";
const string kContinuePushMS = GENERAL_FIELD "continue_push_ms";
static onceToken token([]() {
mINI::Instance()[kFlowThreshold] = 1024;
mINI::Instance()[kStreamNoneReaderDelayMS] = 20 * 1000;
mINI::Instance()[kMaxStreamWaitTimeMS] = 15 * 1000;
mINI::Instance()[kEnableVhost] = 0;
mINI::Instance()[kAddMuteAudio] = 1;
mINI::Instance()[kResetWhenRePlay] = 1;
mINI::Instance()[kPublishToHls] = 1;
mINI::Instance()[kPublishToMP4] = 0;
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;
mINI::Instance()[kEnableAudio] = 1;
mINI::Instance()[kCheckNvidiaDev] = 1;
mINI::Instance()[kEnableFFmpegLog] = 0;
mINI::Instance()[kWaitTrackReadyMS] = 10000;
mINI::Instance()[kWaitAddTrackMS] = 3000;
mINI::Instance()[kUnreadyFrameCache] = 100;
mINI::Instance()[kContinuePushMS] = 15 * 1000;
});
} // namespace General
namespace Protocol {
#define PROTOCOL_FIELD "protocol."
const string kModifyStamp = PROTOCOL_FIELD "modify_stamp";
const string kEnableAudio = PROTOCOL_FIELD "enable_audio";
const string kAddMuteAudio = PROTOCOL_FIELD "add_mute_audio";
const string kContinuePushMS = PROTOCOL_FIELD "continue_push_ms";
const string kEnableHls = PROTOCOL_FIELD "enable_hls";
const string kEnableMP4 = PROTOCOL_FIELD "enable_mp4";
const string kEnableRtsp = PROTOCOL_FIELD "enable_rtsp";
const string kEnableRtmp = PROTOCOL_FIELD "enable_rtmp";
const string kEnableTS = PROTOCOL_FIELD "enable_ts";
const string kEnableFMP4 = PROTOCOL_FIELD "enable_fmp4";
const string kMP4AsPlayer = PROTOCOL_FIELD "mp4_as_player";
const string kMP4MaxSecond = PROTOCOL_FIELD "mp4_max_second";
const string kMP4SavePath = PROTOCOL_FIELD "mp4_save_path";
const string kHlsSavePath = PROTOCOL_FIELD "hls_save_path";
const string kHlsDemand = PROTOCOL_FIELD "hls_demand";
const string kRtspDemand = PROTOCOL_FIELD "rtsp_demand";
const string kRtmpDemand = PROTOCOL_FIELD "rtmp_demand";
const string kTSDemand = PROTOCOL_FIELD "ts_demand";
const string kFMP4Demand = PROTOCOL_FIELD "fmp4_demand";
static onceToken token([]() {
mINI::Instance()[kModifyStamp] = 0;
mINI::Instance()[kEnableAudio] = 1;
mINI::Instance()[kAddMuteAudio] = 1;
mINI::Instance()[kContinuePushMS] = 15000;
mINI::Instance()[kEnableHls] = 1;
mINI::Instance()[kEnableMP4] = 0;
mINI::Instance()[kEnableRtsp] = 1;
mINI::Instance()[kEnableRtmp] = 1;
mINI::Instance()[kEnableTS] = 1;
mINI::Instance()[kEnableFMP4] = 1;
mINI::Instance()[kMP4AsPlayer] = 0;
mINI::Instance()[kMP4MaxSecond] = 3600;
mINI::Instance()[kMP4SavePath] = "./www";
mINI::Instance()[kHlsSavePath] = "./www";
mINI::Instance()[kHlsDemand] = 0;
mINI::Instance()[kRtspDemand] = 0;
mINI::Instance()[kRtmpDemand] = 0;
mINI::Instance()[kTSDemand] = 0;
mINI::Instance()[kFMP4Demand] = 0;
});
} // !Protocol
////////////HTTP配置///////////
namespace Http {
#define HTTP_FIELD "http."
@ -242,22 +273,16 @@ namespace Record {
#define RECORD_FIELD "record."
const string kAppName = RECORD_FIELD "appName";
const string kSampleMS = RECORD_FIELD "sampleMS";
const string kFileSecond = RECORD_FIELD "fileSecond";
const string kFilePath = RECORD_FIELD "filePath";
const string kFileBufSize = RECORD_FIELD "fileBufSize";
const string kFastStart = RECORD_FIELD "fastStart";
const string kFileRepeat = RECORD_FIELD "fileRepeat";
const string kMP4AsPlayer = RECORD_FIELD "mp4_as_player";
static onceToken token([]() {
mINI::Instance()[kAppName] = "record";
mINI::Instance()[kSampleMS] = 500;
mINI::Instance()[kFileSecond] = 60 * 60;
mINI::Instance()[kFilePath] = "./www";
mINI::Instance()[kFileBufSize] = 64 * 1024;
mINI::Instance()[kFastStart] = false;
mINI::Instance()[kFileRepeat] = false;
mINI::Instance()[kMP4AsPlayer] = false;
});
} // namespace Record
@ -269,7 +294,6 @@ const string kSegmentNum = HLS_FIELD "segNum";
const string kSegmentKeep = HLS_FIELD "segKeep";
const string kSegmentRetain = HLS_FIELD "segRetain";
const string kFileBufSize = HLS_FIELD "fileBufSize";
const string kFilePath = HLS_FIELD "filePath";
const string kBroadcastRecordTs = HLS_FIELD "broadcastRecordTs";
const string kDeleteDelaySec = HLS_FIELD "deleteDelaySec";
@ -279,7 +303,6 @@ static onceToken token([]() {
mINI::Instance()[kSegmentKeep] = false;
mINI::Instance()[kSegmentRetain] = 5;
mINI::Instance()[kFileBufSize] = 64 * 1024;
mINI::Instance()[kFilePath] = "./www";
mINI::Instance()[kBroadcastRecordTs] = false;
mINI::Instance()[kDeleteDelaySec] = 10;
});

View File

@ -45,14 +45,11 @@ extern const std::string kBroadcastRecordTs;
// 收到http api请求广播
extern const std::string kBroadcastHttpRequest;
#define BroadcastHttpRequestArgs \
const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, bool &consumed, SockInfo &sender
#define BroadcastHttpRequestArgs const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, bool &consumed, SockInfo &sender
// 在http文件服务器中,收到http访问文件或目录的广播,通过该事件控制访问http目录的权限
extern const std::string kBroadcastHttpAccess;
#define BroadcastHttpAccessArgs \
const Parser &parser, const std::string &path, const bool &is_dir, \
const HttpSession::HttpAccessPathInvoker &invoker, SockInfo &sender
#define BroadcastHttpAccessArgs const Parser &parser, const std::string &path, const bool &is_dir, const HttpSession::HttpAccessPathInvoker &invoker, SockInfo &sender
// 在http文件服务器中,收到http访问文件或目录前的广播,通过该事件可以控制http url到文件路径的映射
// 在该事件中通过自行覆盖path参数可以做到譬如根据虚拟主机或者app选择不同http根目录的目的
@ -66,9 +63,7 @@ extern const std::string kBroadcastOnGetRtspRealm;
// 请求认证用户密码事件user_name为用户名must_no_encrypt如果为true则必须提供明文密码(因为此时是base64认证方式),否则会导致认证失败
// 获取到密码后请调用invoker并输入对应类型的密码和密码类型invoker执行时会匹配密码
extern const std::string kBroadcastOnRtspAuth;
#define BroadcastOnRtspAuthArgs \
const MediaInfo &args, const std::string &realm, const std::string &user_name, const bool &must_no_encrypt, \
const RtspSession::onAuth &invoker, SockInfo &sender
#define BroadcastOnRtspAuthArgs const MediaInfo &args, const std::string &realm, const std::string &user_name, const bool &must_no_encrypt, const RtspSession::onAuth &invoker, SockInfo &sender
// 推流鉴权结果回调对象
// 如果err为空则代表鉴权成功
@ -76,8 +71,7 @@ using PublishAuthInvoker = std::function<void(const std::string &err, const Prot
// 收到rtsp/rtmp推流事件广播通过该事件控制推流鉴权
extern const std::string kBroadcastMediaPublish;
#define BroadcastMediaPublishArgs \
const MediaOriginType &type, const MediaInfo &args, const Broadcast::PublishAuthInvoker &invoker, SockInfo &sender
#define BroadcastMediaPublishArgs const MediaOriginType &type, const MediaInfo &args, const Broadcast::PublishAuthInvoker &invoker, SockInfo &sender
// 播放鉴权结果回调对象
// 如果err为空则代表鉴权成功
@ -89,14 +83,11 @@ extern const std::string kBroadcastMediaPlayed;
// shell登录鉴权
extern const std::string kBroadcastShellLogin;
#define BroadcastShellLoginArgs \
const std::string &user_name, const std::string &passwd, const Broadcast::AuthInvoker &invoker, SockInfo &sender
#define BroadcastShellLoginArgs const std::string &user_name, const std::string &passwd, const Broadcast::AuthInvoker &invoker, SockInfo &sender
// 停止rtsp/rtmp/http-flv会话后流量汇报事件广播
extern const std::string kBroadcastFlowReport;
#define BroadcastFlowReportArgs \
const MediaInfo &args, const uint64_t &totalBytes, const uint64_t &totalDuration, const bool &isPlayer, \
SockInfo &sender
#define BroadcastFlowReportArgs const MediaInfo &args, const uint64_t &totalBytes, const uint64_t &totalDuration, const bool &isPlayer, SockInfo &sender
// 未找到流后会广播该事件,请在监听该事件后去拉流或其他方式产生流,这样就能按需拉流了
extern const std::string kBroadcastNotFoundStream;
@ -173,28 +164,12 @@ extern const std::string kStreamNoneReaderDelayMS;
extern const std::string kMaxStreamWaitTimeMS;
// 是否启动虚拟主机
extern const std::string kEnableVhost;
// 拉流代理时是否添加静音音频
extern const std::string kAddMuteAudio;
// 拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
// 如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
extern const std::string kResetWhenRePlay;
// 是否默认推流时转换成hlshook接口(on_publish)中可以覆盖该设置
extern const std::string kPublishToHls;
// 是否默认推流时mp4录像hook接口(on_publish)中可以覆盖该设置
extern const std::string kPublishToMP4;
// 合并写缓存大小(单位毫秒)合并写指服务器缓存一定的数据后才会一次性写入socket这样能提高性能但是会提高延时
// 开启后会同时关闭TCP_NODELAY并开启MSG_MORE
extern const std::string kMergeWriteMS;
// 全局的时间戳覆盖开关在转协议时对frame进行时间戳覆盖
extern const std::string kModifyStamp;
// 按需转协议的开关
extern const std::string kHlsDemand;
extern const std::string kRtspDemand;
extern const std::string kRtmpDemand;
extern const std::string kTSDemand;
extern const std::string kFMP4Demand;
// 转协议是否全局开启或忽略音频
extern const std::string kEnableAudio;
// 在docker环境下不能通过英伟达驱动是否存在来判断是否支持硬件转码
extern const std::string kCheckNvidiaDev;
// 是否开启ffmpeg日志
@ -206,11 +181,49 @@ extern const std::string kWaitTrackReadyMS;
extern const std::string kWaitAddTrackMS;
// 如果track未就绪我们先缓存帧数据但是有最大个数限制(100帧时大约4秒),防止内存溢出
extern const std::string kUnreadyFrameCache;
// 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
// 置0关闭此特性(推流断开会导致立即断开播放器)
extern const std::string kContinuePushMS;
} // namespace General
namespace Protocol {
//时间戳修复这一路流标志位
extern const std::string kModifyStamp;
//转协议是否开启音频
extern const std::string kEnableAudio;
//添加静音音频,在关闭音频时,此开关无效
extern const std::string kAddMuteAudio;
//断连续推延时,单位毫秒,默认采用配置文件
extern const std::string kContinuePushMS;
//是否开启转换为hls
extern const std::string kEnableHls;
//是否开启MP4录制
extern const std::string kEnableMP4;
//是否开启转换为rtsp/webrtc
extern const std::string kEnableRtsp;
//是否开启转换为rtmp/flv
extern const std::string kEnableRtmp;
//是否开启转换为http-ts/ws-ts
extern const std::string kEnableTS;
//是否开启转换为http-fmp4/ws-fmp4
extern const std::string kEnableFMP4;
//是否将mp4录制当做观看者
extern const std::string kMP4AsPlayer;
//mp4切片大小单位秒
extern const std::string kMP4MaxSecond;
//mp4录制保存路径
extern const std::string kMP4SavePath;
//hls录制保存路径
extern const std::string kHlsSavePath;
// 按需转协议的开关
extern const std::string kHlsDemand;
extern const std::string kRtspDemand;
extern const std::string kRtmpDemand;
extern const std::string kTSDemand;
extern const std::string kFMP4Demand;
} // !Protocol
////////////HTTP配置///////////
namespace Http {
// http 文件发送缓存大小
@ -262,8 +275,6 @@ extern const std::string kLowLatency;
////////////RTMP服务器配置///////////
namespace Rtmp {
// rtmp推流时间戳覆盖开关
extern const std::string kModifyStamp;
// 握手超时时间默认15秒
extern const std::string kHandshakeSecond;
// 维持链接超时时间默认15秒
@ -298,18 +309,12 @@ namespace Record {
extern const std::string kAppName;
// 每次流化MP4文件的时长,单位毫秒
extern const std::string kSampleMS;
// MP4文件录制大小,默认一个小时
extern const std::string kFileSecond;
// 录制文件路径
extern const std::string kFilePath;
// mp4文件写缓存大小
extern const std::string kFileBufSize;
// mp4录制完成后是否进行二次关键帧索引写入头部
extern const std::string kFastStart;
// mp4文件是否重头循环读取
extern const std::string kFileRepeat;
// MP4录制是否当做播放器参与播放人数统计
extern const std::string kMP4AsPlayer;
} // namespace Record
////////////HLS相关配置///////////
@ -324,8 +329,6 @@ extern const std::string kSegmentKeep;
extern const std::string kSegmentRetain;
// HLS文件写缓存大小
extern const std::string kFileBufSize;
// 录制文件路径
extern const std::string kFilePath;
// 是否广播 ts 切片完成通知
extern const std::string kBroadcastRecordTs;
// hls直播文件删除延时单位秒

View File

@ -25,7 +25,9 @@ public:
FMP4MediaSourceMuxer(const std::string &vhost,
const std::string &app,
const std::string &stream_id) {
const std::string &stream_id,
const ProtocolOption &option) {
_option = option;
_media_src = std::make_shared<FMP4MediaSource>(vhost, app, stream_id);
}
@ -41,30 +43,27 @@ public:
}
void onReaderChanged(MediaSource &sender, int size) override {
GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand);
_enabled = fmp4_demand ? size : true;
if (!size && fmp4_demand) {
_enabled = _option.fmp4_demand ? size : true;
if (!size && _option.fmp4_demand) {
_clear_cache = true;
}
MediaSourceEventInterceptor::onReaderChanged(sender, size);
}
bool inputFrame(const Frame::Ptr &frame) override {
GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand);
if (_clear_cache && fmp4_demand) {
if (_clear_cache && _option.fmp4_demand) {
_clear_cache = false;
_media_src->clearCache();
}
if (_enabled || !fmp4_demand) {
if (_enabled || !_option.fmp4_demand) {
return MP4MuxerMemory::inputFrame(frame);
}
return false;
}
bool isEnabled() {
GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand);
//缓存尚未清空时还允许触发inputFrame函数以便及时清空缓存
return fmp4_demand ? (_clear_cache ? true : _enabled) : true;
return _option.fmp4_demand ? (_clear_cache ? true : _enabled) : true;
}
void onAllTrackReady() {
@ -84,6 +83,7 @@ protected:
private:
bool _enabled = true;
bool _clear_cache = false;
ProtocolOption _option;
FMP4MediaSource::Ptr _media_src;
};

View File

@ -20,11 +20,13 @@ class HlsRecorder final : public MediaSourceEventInterceptor, public MpegMuxer,
public:
using Ptr = std::shared_ptr<HlsRecorder>;
HlsRecorder(const std::string &m3u8_file, const std::string &params) : MpegMuxer(false) {
HlsRecorder(const std::string &m3u8_file, const std::string &params, const ProtocolOption &option) : MpegMuxer(false) {
GET_CONFIG(uint32_t, hlsNum, Hls::kSegmentNum);
GET_CONFIG(bool, hlsKeep, Hls::kSegmentKeep);
GET_CONFIG(uint32_t, hlsBufSize, Hls::kFileBufSize);
GET_CONFIG(float, hlsDuration, Hls::kSegmentDuration);
_option = option;
_hls = std::make_shared<HlsMakerImp>(m3u8_file, params, hlsBufSize, hlsDuration, hlsNum, hlsKeep);
//清空上次的残余文件
_hls->clearCache();
@ -44,10 +46,9 @@ public:
int readerCount() { return _hls->getMediaSource()->readerCount(); }
void onReaderChanged(MediaSource &sender, int size) override {
GET_CONFIG(bool, hls_demand, General::kHlsDemand);
// hls保留切片个数为0时代表为hls录制(不删除切片)那么不管有无观看者都一直生成hls
_enabled = hls_demand ? (_hls->isLive() ? size : true) : true;
if (!size && _hls->isLive() && hls_demand) {
_enabled = _option.hls_demand ? (_hls->isLive() ? size : true) : true;
if (!size && _hls->isLive() && _option.hls_demand) {
// hls直播时如果无人观看就删除视频缓存目的是为了防止视频跳跃
_clear_cache = true;
}
@ -55,23 +56,21 @@ public:
}
bool inputFrame(const Frame::Ptr &frame) override {
GET_CONFIG(bool, hls_demand, General::kHlsDemand);
if (_clear_cache && hls_demand) {
if (_clear_cache && _option.hls_demand) {
_clear_cache = false;
//清空旧的m3u8索引文件于ts切片
_hls->clearCache();
_hls->getMediaSource()->setIndexFile("");
}
if (_enabled || !hls_demand) {
if (_enabled || !_option.hls_demand) {
return MpegMuxer::inputFrame(frame);
}
return false;
}
bool isEnabled() {
GET_CONFIG(bool, hls_demand, General::kHlsDemand);
//缓存尚未清空时还允许触发inputFrame函数以便及时清空缓存
return hls_demand ? (_clear_cache ? true : _enabled) : true;
return _option.hls_demand ? (_clear_cache ? true : _enabled) : true;
}
private:
@ -86,6 +85,7 @@ private:
private:
bool _enabled = true;
bool _clear_cache = false;
ProtocolOption _option;
std::shared_ptr<HlsMakerImp> _hls;
};
}//namespace mediakit

View File

@ -24,7 +24,7 @@ MP4Reader::MP4Reader(const string &vhost, const string &app, const string &strea
_poller = WorkThreadPool::Instance().getPoller();
_file_path = file_path;
if (_file_path.empty()) {
GET_CONFIG(string, recordPath, Record::kFilePath);
GET_CONFIG(string, recordPath, Protocol::kMP4SavePath);
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
if (enableVhost) {
_file_path = vhost + "/" + app + "/" + stream_id;

View File

@ -28,8 +28,8 @@ MP4Recorder::MP4Recorder(const string &path, const string &vhost, const string &
_info.stream = stream_id;
_info.vhost = vhost;
_info.folder = path;
GET_CONFIG(size_t ,recordSec,Record::kFileSecond);
_max_second = max_second ? max_second : recordSec;
GET_CONFIG(uint32_t, s_max_second, Protocol::kMP4MaxSecond);
_max_second = max_second ? max_second : s_max_second;
}
MP4Recorder::~MP4Recorder() {

View File

@ -23,7 +23,7 @@ string Recorder::getRecordPath(Recorder::type type, const string &vhost, const s
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
switch (type) {
case Recorder::type_hls: {
GET_CONFIG(string, hlsPath, Hls::kFilePath);
GET_CONFIG(string, hlsPath, Protocol::kHlsSavePath);
string m3u8FilePath;
if (enableVhost) {
m3u8FilePath = vhost + "/" + app + "/" + stream_id + "/hls.m3u8";
@ -37,7 +37,7 @@ string Recorder::getRecordPath(Recorder::type type, const string &vhost, const s
return File::absolutePath(m3u8FilePath, hlsPath);
}
case Recorder::type_mp4: {
GET_CONFIG(string, recordPath, Record::kFilePath);
GET_CONFIG(string, recordPath, Protocol::kMP4SavePath);
GET_CONFIG(string, recordAppName, Record::kAppName);
string mp4FilePath;
if (enableVhost) {
@ -56,13 +56,13 @@ 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, size_t max_second){
auto path = Recorder::getRecordPath(type, vhost, app, stream_id, customized_path);
std::shared_ptr<MediaSinkInterface> Recorder::createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const ProtocolOption &option){
switch (type) {
case Recorder::type_hls: {
#if defined(ENABLE_HLS)
auto path = Recorder::getRecordPath(type, vhost, app, stream_id, option.hls_save_path);
GET_CONFIG(bool, enable_vhost, General::kEnableVhost);
auto ret = std::make_shared<HlsRecorder>(path, enable_vhost ? string(VHOST_KEY) + "=" + vhost : "");
auto ret = std::make_shared<HlsRecorder>(path, enable_vhost ? string(VHOST_KEY) + "=" + vhost : "", option);
ret->setMediaSource(vhost, app, stream_id);
return ret;
#else
@ -73,7 +73,8 @@ std::shared_ptr<MediaSinkInterface> Recorder::createRecorder(type type, const st
case Recorder::type_mp4: {
#if defined(ENABLE_MP4)
return std::make_shared<MP4Recorder>(path, vhost, app, stream_id, max_second);
auto path = Recorder::getRecordPath(type, vhost, app, stream_id, option.mp4_save_path);
return std::make_shared<MP4Recorder>(path, vhost, app, stream_id, option.mp4_max_second);
#else
throw std::invalid_argument("mp4相关功能未打开请开启ENABLE_MP4宏后编译再测试");
#endif

View File

@ -10,11 +10,13 @@
#ifndef SRC_MEDIAFILE_RECORDER_H_
#define SRC_MEDIAFILE_RECORDER_H_
#include <memory>
#include <string>
namespace mediakit {
class MediaSinkInterface;
class ProtocolOption;
class RecordInfo {
public:
@ -60,7 +62,7 @@ public:
* @param max_second mp4录制最大切片时间0
* @return nullptr
*/
static std::shared_ptr<MediaSinkInterface> createRecorder(type type, const std::string &vhost, const std::string &app, const std::string &stream_id, const std::string &customized_path = "", size_t max_second = 0);
static std::shared_ptr<MediaSinkInterface> createRecorder(type type, const std::string &vhost, const std::string &app, const std::string &stream_id, const ProtocolOption &option);
private:
Recorder() = delete;

View File

@ -24,7 +24,9 @@ public:
RtmpMediaSourceMuxer(const std::string &vhost,
const std::string &strApp,
const std::string &strId,
const ProtocolOption &option,
const TitleMeta::Ptr &title = nullptr) : RtmpMuxer(title) {
_option = option;
_media_src = std::make_shared<RtmpMediaSource>(vhost, strApp, strId);
getRtmpRing()->setDelegate(_media_src);
}
@ -50,35 +52,33 @@ public:
}
void onReaderChanged(MediaSource &sender, int size) override {
GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand);
_enabled = rtmp_demand ? size : true;
if (!size && rtmp_demand) {
_enabled = _option.rtmp_demand ? size : true;
if (!size && _option.rtmp_demand) {
_clear_cache = true;
}
MediaSourceEventInterceptor::onReaderChanged(sender, size);
}
bool inputFrame(const Frame::Ptr &frame) override {
GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand);
if (_clear_cache && rtmp_demand) {
if (_clear_cache && _option.rtmp_demand) {
_clear_cache = false;
_media_src->clearCache();
}
if (_enabled || !rtmp_demand) {
if (_enabled || !_option.rtmp_demand) {
return RtmpMuxer::inputFrame(frame);
}
return false;
}
bool isEnabled() {
GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand);
//缓存尚未清空时还允许触发inputFrame函数以便及时清空缓存
return rtmp_demand ? (_clear_cache ? true : _enabled) : true;
return _option.rtmp_demand ? (_clear_cache ? true : _enabled) : true;
}
private:
bool _enabled = true;
bool _clear_cache = false;
ProtocolOption _option;
RtmpMediaSource::Ptr _media_src;
};

View File

@ -530,12 +530,6 @@ void RtmpSession::onRtmpChunk(RtmpPacket::Ptr packet) {
WarnL << "Not a rtmp push!";
return;
}
GET_CONFIG(bool, rtmp_modify_stamp, Rtmp::kModifyStamp);
if (rtmp_modify_stamp) {
int64_t dts_out;
_stamp[chunk_data.type_id % 2].revise(chunk_data.time_stamp, chunk_data.time_stamp, dts_out, dts_out, true);
chunk_data.time_stamp = (uint32_t)dts_out;
}
if (!_set_meta_data) {
_set_meta_data = true;

View File

@ -96,8 +96,6 @@ private:
//消耗的总流量
uint64_t _total_bytes = 0;
std::string _tc_url;
//推流时间戳修整器
Stamp _stamp[2];
//数据接收超时计时器
toolkit::Ticker _ticker;
MediaInfo _media_info;

View File

@ -24,7 +24,9 @@ public:
RtspMediaSourceMuxer(const std::string &vhost,
const std::string &strApp,
const std::string &strId,
const ProtocolOption &option,
const TitleSdp::Ptr &title = nullptr) : RtspMuxer(title) {
_option = option;
_media_src = std::make_shared<RtspMediaSource>(vhost,strApp,strId);
getRtpRing()->setDelegate(_media_src);
}
@ -49,35 +51,33 @@ public:
}
void onReaderChanged(MediaSource &sender, int size) override {
GET_CONFIG(bool, rtsp_demand, General::kRtspDemand);
_enabled = rtsp_demand ? size : true;
if (!size && rtsp_demand) {
_enabled = _option.rtsp_demand ? size : true;
if (!size && _option.rtsp_demand) {
_clear_cache = true;
}
MediaSourceEventInterceptor::onReaderChanged(sender, size);
}
bool inputFrame(const Frame::Ptr &frame) override {
GET_CONFIG(bool, rtsp_demand, General::kRtspDemand);
if (_clear_cache && rtsp_demand) {
if (_clear_cache && _option.rtsp_demand) {
_clear_cache = false;
_media_src->clearCache();
}
if (_enabled || !rtsp_demand) {
if (_enabled || !_option.rtsp_demand) {
return RtspMuxer::inputFrame(frame);
}
return false;
}
bool isEnabled() {
GET_CONFIG(bool, rtsp_demand, General::kRtspDemand);
//缓存尚未清空时还允许触发inputFrame函数以便及时清空缓存
return rtsp_demand ? (_clear_cache ? true : _enabled) : true;
return _option.rtsp_demand ? (_clear_cache ? true : _enabled) : true;
}
private:
bool _enabled = true;
bool _clear_cache = false;
ProtocolOption _option;
RtspMediaSource::Ptr _media_src;
};

View File

@ -23,7 +23,9 @@ public:
TSMediaSourceMuxer(const std::string &vhost,
const std::string &app,
const std::string &stream_id) : MpegMuxer(false) {
const std::string &stream_id,
const ProtocolOption &option) : MpegMuxer(false) {
_option = option;
_media_src = std::make_shared<TSMediaSource>(vhost, app, stream_id);
}
@ -39,30 +41,27 @@ public:
}
void onReaderChanged(MediaSource &sender, int size) override {
GET_CONFIG(bool, ts_demand, General::kTSDemand);
_enabled = ts_demand ? size : true;
if (!size && ts_demand) {
_enabled = _option.ts_demand ? size : true;
if (!size && _option.ts_demand) {
_clear_cache = true;
}
MediaSourceEventInterceptor::onReaderChanged(sender, size);
}
bool inputFrame(const Frame::Ptr &frame) override {
GET_CONFIG(bool, ts_demand, General::kTSDemand);
if (_clear_cache && ts_demand) {
if (_clear_cache && _option.ts_demand) {
_clear_cache = false;
_media_src->clearCache();
}
if (_enabled || !ts_demand) {
if (_enabled || !_option.ts_demand) {
return MpegMuxer::inputFrame(frame);
}
return false;
}
bool isEnabled() {
GET_CONFIG(bool, ts_demand, General::kTSDemand);
//缓存尚未清空时还允许触发inputFrame函数以便及时清空缓存
return ts_demand ? (_clear_cache ? true : _enabled) : true;
return _option.ts_demand ? (_clear_cache ? true : _enabled) : true;
}
protected:
@ -78,6 +77,7 @@ protected:
private:
bool _enabled = true;
bool _clear_cache = false;
ProtocolOption _option;
TSMediaSource::Ptr _media_src;
};

View File

@ -125,11 +125,11 @@ int main(int argc, char *argv[]) {
//设置合并写
mINI::Instance()[General::kMergeWriteMS] = merge_ms;
mINI::Instance()[General::kRtspDemand] = demand;
mINI::Instance()[General::kRtmpDemand] = demand;
mINI::Instance()[General::kHlsDemand] = demand;
mINI::Instance()[General::kTSDemand] = demand;
mINI::Instance()[General::kFMP4Demand] = demand;
mINI::Instance()[Protocol::kRtspDemand] = demand;
mINI::Instance()[Protocol::kRtmpDemand] = demand;
mINI::Instance()[Protocol::kHlsDemand] = demand;
mINI::Instance()[Protocol::kTSDemand] = demand;
mINI::Instance()[Protocol::kFMP4Demand] = demand;
map<string, PlayerProxy::Ptr> proxyMap;
ProtocolOption option;

View File

@ -105,11 +105,11 @@ int domain(const string &filePath, const string &pushUrl) {
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
//循环点播mp4文件
mINI::Instance()[Record::kFileRepeat] = 1;
mINI::Instance()[General::kHlsDemand] = 1;
mINI::Instance()[General::kTSDemand] = 1;
mINI::Instance()[General::kFMP4Demand] = 1;
//mINI::Instance()[General::kRtspDemand] = 1;
//mINI::Instance()[General::kRtmpDemand] = 1;
mINI::Instance()[Protocol::kHlsDemand] = 1;
mINI::Instance()[Protocol::kTSDemand] = 1;
mINI::Instance()[Protocol::kFMP4Demand] = 1;
//mINI::Instance()[Protocol::kRtspDemand] = 1;
//mINI::Instance()[Protocol::kRtmpDemand] = 1;
auto poller = EventPollerPool::Instance().getPoller();
//vhost/app/stream可以随便自己填现在不限制app应用名了