mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 12:11:36 +08:00
全面整理转协议相关配置文件
This commit is contained in:
parent
946945ce7b
commit
9bb6a2f828
103
conf/config.ini
103
conf/config.ini
@ -29,6 +29,56 @@ log=./ffmpeg/ffmpeg.log
|
|||||||
# 自动重启的时间(秒), 默认为0, 也就是不自动重启. 主要是为了避免长时间ffmpeg拉流导致的不同步现象
|
# 自动重启的时间(秒), 默认为0, 也就是不自动重启. 主要是为了避免长时间ffmpeg拉流导致的不同步现象
|
||||||
restart_sec=0
|
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]
|
[general]
|
||||||
#是否启用虚拟主机
|
#是否启用虚拟主机
|
||||||
enableVhost=0
|
enableVhost=0
|
||||||
@ -44,43 +94,14 @@ 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
|
||||||
#是否全局添加静音aac音频,转协议时有效
|
|
||||||
#有些播放器在打开单视频流时不能秒开,添加静音音频可以加快秒开速度
|
|
||||||
addMuteAudio=1
|
|
||||||
#拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
|
#拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
|
||||||
#如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
|
#如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
|
||||||
resetWhenRePlay=1
|
resetWhenRePlay=1
|
||||||
#是否默认推流时转换成hls,hook接口(on_publish)中可以覆盖该设置
|
|
||||||
publishToHls=1
|
|
||||||
#是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置
|
|
||||||
publishToMP4=0
|
|
||||||
#合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时
|
#合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时
|
||||||
#开启后会同时关闭TCP_NODELAY并开启MSG_MORE
|
#开启后会同时关闭TCP_NODELAY并开启MSG_MORE
|
||||||
mergeWriteMS=0
|
mergeWriteMS=0
|
||||||
#全局的时间戳覆盖开关,在转协议时,对frame进行时间戳覆盖
|
|
||||||
#该开关对rtsp/rtmp/rtp推流、rtsp/rtmp/hls拉流代理转协议时生效
|
|
||||||
#会直接影响rtsp/rtmp/hls/mp4/flv等协议的时间戳
|
|
||||||
#同协议情况下不影响(例如rtsp/rtmp推流,那么播放rtsp/rtmp时不会影响时间戳)
|
|
||||||
modifyStamp=0
|
|
||||||
#服务器唯一id,用于触发hook时区别是哪台服务器
|
#服务器唯一id,用于触发hook时区别是哪台服务器
|
||||||
mediaServerId=your_server_id
|
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
|
#最多等待未初始化的Track时间,单位毫秒,超时之后会忽略未初始化的Track
|
||||||
wait_track_ready_ms=10000
|
wait_track_ready_ms=10000
|
||||||
@ -89,17 +110,10 @@ wait_track_ready_ms=10000
|
|||||||
wait_add_track_ms=3000
|
wait_add_track_ms=3000
|
||||||
#如果track未就绪,我们先缓存帧数据,但是有最大个数限制,防止内存溢出
|
#如果track未就绪,我们先缓存帧数据,但是有最大个数限制,防止内存溢出
|
||||||
unready_frame_cache=100
|
unready_frame_cache=100
|
||||||
#推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
|
|
||||||
#置0关闭此特性(推流断开会导致立即断开播放器)
|
|
||||||
#此参数不应大于播放器超时时间
|
|
||||||
continue_push_ms=15000
|
|
||||||
|
|
||||||
[hls]
|
[hls]
|
||||||
#hls写文件的buf大小,调整参数可以提高文件io性能
|
#hls写文件的buf大小,调整参数可以提高文件io性能
|
||||||
fileBufSize=65536
|
fileBufSize=65536
|
||||||
#hls保存文件路径
|
|
||||||
#可以为相对(相对于本可执行程序目录)或绝对路径
|
|
||||||
filePath=./www
|
|
||||||
#hls最大切片时间
|
#hls最大切片时间
|
||||||
segDur=2
|
segDur=2
|
||||||
#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个)
|
#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
|
on_server_keepalive=https://127.0.0.1/index/hook/on_server_keepalive
|
||||||
#发送rtp(startSendRtp)被动关闭时回调
|
#发送rtp(startSendRtp)被动关闭时回调
|
||||||
on_send_rtp_stopped=https://127.0.0.1/index/hook/on_send_rtp_stopped
|
on_send_rtp_stopped=https://127.0.0.1/index/hook/on_send_rtp_stopped
|
||||||
|
|
||||||
#rtp server 超时未收到数据
|
#rtp server 超时未收到数据
|
||||||
on_rtp_server_timeout=https://127.0.0.1/index/hook/on_rtp_server_timeout
|
on_rtp_server_timeout=https://127.0.0.1/index/hook/on_rtp_server_timeout
|
||||||
|
|
||||||
@ -232,11 +245,6 @@ udpTTL=64
|
|||||||
appName=record
|
appName=record
|
||||||
#mp4录制写文件缓存,单位BYTE,调整参数可以提高文件io性能
|
#mp4录制写文件缓存,单位BYTE,调整参数可以提高文件io性能
|
||||||
fileBufSize=65536
|
fileBufSize=65536
|
||||||
#mp4录制保存、mp4点播根路径
|
|
||||||
#可以为相对(相对于本可执行程序目录)或绝对路径
|
|
||||||
filePath=./www
|
|
||||||
#mp4录制切片时间,单位秒
|
|
||||||
fileSecond=3600
|
|
||||||
#mp4点播每次流化数据量,单位毫秒,
|
#mp4点播每次流化数据量,单位毫秒,
|
||||||
#减少该值可以让点播数据发送量更平滑,增大该值则更节省cpu资源
|
#减少该值可以让点播数据发送量更平滑,增大该值则更节省cpu资源
|
||||||
sampleMS=500
|
sampleMS=500
|
||||||
@ -244,8 +252,6 @@ sampleMS=500
|
|||||||
fastStart=0
|
fastStart=0
|
||||||
#MP4点播(rtsp/rtmp/http-flv/ws-flv)是否循环播放文件
|
#MP4点播(rtsp/rtmp/http-flv/ws-flv)是否循环播放文件
|
||||||
fileRepeat=0
|
fileRepeat=0
|
||||||
#MP4录制是否当做播放器参与播放人数统计
|
|
||||||
mp4_as_player=0
|
|
||||||
|
|
||||||
[rtmp]
|
[rtmp]
|
||||||
#rtmp必须在此时间内完成握手,否则服务器会断开链接,单位秒
|
#rtmp必须在此时间内完成握手,否则服务器会断开链接,单位秒
|
||||||
@ -281,25 +287,18 @@ timeoutSec=15
|
|||||||
#随机端口范围,最少确保36个端口
|
#随机端口范围,最少确保36个端口
|
||||||
#该范围同时限制rtsp服务器udp端口范围
|
#该范围同时限制rtsp服务器udp端口范围
|
||||||
port_range=30000-35000
|
port_range=30000-35000
|
||||||
|
|
||||||
#rtp h264 负载的pt
|
#rtp h264 负载的pt
|
||||||
h264_pt=98
|
h264_pt=98
|
||||||
|
|
||||||
#rtp h265 负载的pt
|
#rtp h265 负载的pt
|
||||||
h265_pt=99
|
h265_pt=99
|
||||||
|
|
||||||
#rtp ps 负载的pt
|
#rtp ps 负载的pt
|
||||||
ps_pt=96
|
ps_pt=96
|
||||||
|
|
||||||
#rtp ts 负载的pt
|
#rtp ts 负载的pt
|
||||||
ts_pt=33
|
ts_pt=33
|
||||||
|
|
||||||
#rtp opus 负载的pt
|
#rtp opus 负载的pt
|
||||||
opus_pt=100
|
opus_pt=100
|
||||||
|
|
||||||
#rtp g711u 负载的pt
|
#rtp g711u 负载的pt
|
||||||
g711u_pt=0
|
g711u_pt=0
|
||||||
|
|
||||||
#rtp g711a 负载的pt
|
#rtp g711a 负载的pt
|
||||||
g711a_pt=8
|
g711a_pt=8
|
||||||
|
|
||||||
@ -330,10 +329,8 @@ timeoutSec=5
|
|||||||
#srt udp服务器监听端口号,所有srt客户端将通过该端口传输srt数据,
|
#srt udp服务器监听端口号,所有srt客户端将通过该端口传输srt数据,
|
||||||
#该端口是多线程的,同时支持客户端网络切换导致的连接迁移
|
#该端口是多线程的,同时支持客户端网络切换导致的连接迁移
|
||||||
port=9000
|
port=9000
|
||||||
|
|
||||||
#srt 协议中延迟缓存的估算参数,在握手阶段估算rtt ,然后latencyMul*rtt 为最大缓存时长,此参数越大,表示等待重传的时长就越大
|
#srt 协议中延迟缓存的估算参数,在握手阶段估算rtt ,然后latencyMul*rtt 为最大缓存时长,此参数越大,表示等待重传的时长就越大
|
||||||
latencyMul=4
|
latencyMul=4
|
||||||
|
|
||||||
#包缓存的大小
|
#包缓存的大小
|
||||||
pktBufSize=8192
|
pktBufSize=8192
|
||||||
|
|
||||||
|
@ -8,12 +8,13 @@
|
|||||||
* may be found in the AUTHORS file in the root of the source tree.
|
* 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/util.h"
|
||||||
|
#include "Util/NoticeCenter.h"
|
||||||
#include "Network/sockutil.h"
|
#include "Network/sockutil.h"
|
||||||
#include "Network/TcpSession.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 std;
|
||||||
using namespace toolkit;
|
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 {
|
struct MediaSourceNull : public MediaSource {
|
||||||
MediaSourceNull() : MediaSource("schema", "vhost", "app", "stream") {};
|
MediaSourceNull() : MediaSource("schema", "vhost", "app", "stream") {};
|
||||||
int readerCount() override { return 0; }
|
int readerCount() override { return 0; }
|
||||||
|
@ -134,6 +134,91 @@ private:
|
|||||||
toolkit::Timer::Ptr _async_close_timer;
|
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事件
|
//该对象用于拦截感兴趣的MediaSourceEvent事件
|
||||||
class MediaSourceEventInterceptor : public MediaSourceEvent {
|
class MediaSourceEventInterceptor : public MediaSourceEvent {
|
||||||
public:
|
public:
|
||||||
|
@ -21,26 +21,8 @@ namespace toolkit {
|
|||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
ProtocolOption::ProtocolOption() {
|
static std::shared_ptr<MediaSinkInterface> makeRecorder(MediaSource &sender, const vector<Track::Ptr> &tracks, Recorder::type type, const ProtocolOption &option){
|
||||||
GET_CONFIG(bool, s_to_hls, General::kPublishToHls);
|
auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId(), option);
|
||||||
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);
|
|
||||||
for (auto &track : tracks) {
|
for (auto &track : tracks) {
|
||||||
recorder->addTrack(track);
|
recorder->addTrack(track);
|
||||||
}
|
}
|
||||||
@ -106,23 +88,23 @@ MultiMediaSourceMuxer::MultiMediaSourceMuxer(const string &vhost, const string &
|
|||||||
_option = option;
|
_option = option;
|
||||||
|
|
||||||
if (option.enable_rtmp) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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 defined(ENABLE_MP4)
|
||||||
if (option.enable_fmp4) {
|
if (option.enable_fmp4) {
|
||||||
_fmp4 = std::make_shared<FMP4MediaSourceMuxer>(vhost, app, stream);
|
_fmp4 = std::make_shared<FMP4MediaSourceMuxer>(vhost, app, stream, option);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -212,7 +194,8 @@ bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type
|
|||||||
case Recorder::type_hls : {
|
case Recorder::type_hls : {
|
||||||
if (start && !_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) {
|
if (hls) {
|
||||||
//设置HlsMediaSource的事件监听器
|
//设置HlsMediaSource的事件监听器
|
||||||
hls->setListener(shared_from_this());
|
hls->setListener(shared_from_this());
|
||||||
@ -227,7 +210,9 @@ bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type
|
|||||||
case Recorder::type_mp4 : {
|
case Recorder::type_mp4 : {
|
||||||
if (start && !_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) {
|
} else if (!start && _mp4) {
|
||||||
//停止录制
|
//停止录制
|
||||||
_mp4 = nullptr;
|
_mp4 = nullptr;
|
||||||
|
@ -23,73 +23,6 @@
|
|||||||
|
|
||||||
namespace mediakit {
|
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>{
|
class MultiMediaSourceMuxer : public MediaSourceEventInterceptor, public MediaSink, public std::enable_shared_from_this<MultiMediaSourceMuxer>{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<MultiMediaSourceMuxer> Ptr;
|
typedef std::shared_ptr<MultiMediaSourceMuxer> Ptr;
|
||||||
|
@ -68,53 +68,84 @@ 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 kAddMuteAudio = GENERAL_FIELD "addMuteAudio";
|
|
||||||
const string kResetWhenRePlay = GENERAL_FIELD "resetWhenRePlay";
|
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 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 kCheckNvidiaDev = GENERAL_FIELD "check_nvidia_dev";
|
||||||
const string kEnableFFmpegLog = GENERAL_FIELD "enable_ffmpeg_log";
|
const string kEnableFFmpegLog = GENERAL_FIELD "enable_ffmpeg_log";
|
||||||
const string kWaitTrackReadyMS = GENERAL_FIELD "wait_track_ready_ms";
|
const string kWaitTrackReadyMS = GENERAL_FIELD "wait_track_ready_ms";
|
||||||
const string kWaitAddTrackMS = GENERAL_FIELD "wait_add_track_ms";
|
const string kWaitAddTrackMS = GENERAL_FIELD "wait_add_track_ms";
|
||||||
const string kUnreadyFrameCache = GENERAL_FIELD "unready_frame_cache";
|
const string kUnreadyFrameCache = GENERAL_FIELD "unready_frame_cache";
|
||||||
const string kContinuePushMS = GENERAL_FIELD "continue_push_ms";
|
|
||||||
|
|
||||||
static onceToken token([]() {
|
static onceToken token([]() {
|
||||||
mINI::Instance()[kFlowThreshold] = 1024;
|
mINI::Instance()[kFlowThreshold] = 1024;
|
||||||
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()[kAddMuteAudio] = 1;
|
|
||||||
mINI::Instance()[kResetWhenRePlay] = 1;
|
mINI::Instance()[kResetWhenRePlay] = 1;
|
||||||
mINI::Instance()[kPublishToHls] = 1;
|
|
||||||
mINI::Instance()[kPublishToMP4] = 0;
|
|
||||||
mINI::Instance()[kMergeWriteMS] = 0;
|
mINI::Instance()[kMergeWriteMS] = 0;
|
||||||
mINI::Instance()[kModifyStamp] = 0;
|
|
||||||
mINI::Instance()[kMediaServerId] = makeRandStr(16);
|
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()[kCheckNvidiaDev] = 1;
|
||||||
mINI::Instance()[kEnableFFmpegLog] = 0;
|
mINI::Instance()[kEnableFFmpegLog] = 0;
|
||||||
mINI::Instance()[kWaitTrackReadyMS] = 10000;
|
mINI::Instance()[kWaitTrackReadyMS] = 10000;
|
||||||
mINI::Instance()[kWaitAddTrackMS] = 3000;
|
mINI::Instance()[kWaitAddTrackMS] = 3000;
|
||||||
mINI::Instance()[kUnreadyFrameCache] = 100;
|
mINI::Instance()[kUnreadyFrameCache] = 100;
|
||||||
mINI::Instance()[kContinuePushMS] = 15 * 1000;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} // namespace General
|
} // 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配置///////////
|
////////////HTTP配置///////////
|
||||||
namespace Http {
|
namespace Http {
|
||||||
#define HTTP_FIELD "http."
|
#define HTTP_FIELD "http."
|
||||||
@ -242,22 +273,16 @@ namespace Record {
|
|||||||
#define RECORD_FIELD "record."
|
#define RECORD_FIELD "record."
|
||||||
const string kAppName = RECORD_FIELD "appName";
|
const string kAppName = RECORD_FIELD "appName";
|
||||||
const string kSampleMS = RECORD_FIELD "sampleMS";
|
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 kFileBufSize = RECORD_FIELD "fileBufSize";
|
||||||
const string kFastStart = RECORD_FIELD "fastStart";
|
const string kFastStart = RECORD_FIELD "fastStart";
|
||||||
const string kFileRepeat = RECORD_FIELD "fileRepeat";
|
const string kFileRepeat = RECORD_FIELD "fileRepeat";
|
||||||
const string kMP4AsPlayer = RECORD_FIELD "mp4_as_player";
|
|
||||||
|
|
||||||
static onceToken token([]() {
|
static onceToken token([]() {
|
||||||
mINI::Instance()[kAppName] = "record";
|
mINI::Instance()[kAppName] = "record";
|
||||||
mINI::Instance()[kSampleMS] = 500;
|
mINI::Instance()[kSampleMS] = 500;
|
||||||
mINI::Instance()[kFileSecond] = 60 * 60;
|
|
||||||
mINI::Instance()[kFilePath] = "./www";
|
|
||||||
mINI::Instance()[kFileBufSize] = 64 * 1024;
|
mINI::Instance()[kFileBufSize] = 64 * 1024;
|
||||||
mINI::Instance()[kFastStart] = false;
|
mINI::Instance()[kFastStart] = false;
|
||||||
mINI::Instance()[kFileRepeat] = false;
|
mINI::Instance()[kFileRepeat] = false;
|
||||||
mINI::Instance()[kMP4AsPlayer] = false;
|
|
||||||
});
|
});
|
||||||
} // namespace Record
|
} // namespace Record
|
||||||
|
|
||||||
@ -269,7 +294,6 @@ const string kSegmentNum = HLS_FIELD "segNum";
|
|||||||
const string kSegmentKeep = HLS_FIELD "segKeep";
|
const string kSegmentKeep = HLS_FIELD "segKeep";
|
||||||
const string kSegmentRetain = HLS_FIELD "segRetain";
|
const string kSegmentRetain = HLS_FIELD "segRetain";
|
||||||
const string kFileBufSize = HLS_FIELD "fileBufSize";
|
const string kFileBufSize = HLS_FIELD "fileBufSize";
|
||||||
const string kFilePath = HLS_FIELD "filePath";
|
|
||||||
const string kBroadcastRecordTs = HLS_FIELD "broadcastRecordTs";
|
const string kBroadcastRecordTs = HLS_FIELD "broadcastRecordTs";
|
||||||
const string kDeleteDelaySec = HLS_FIELD "deleteDelaySec";
|
const string kDeleteDelaySec = HLS_FIELD "deleteDelaySec";
|
||||||
|
|
||||||
@ -279,7 +303,6 @@ static onceToken token([]() {
|
|||||||
mINI::Instance()[kSegmentKeep] = false;
|
mINI::Instance()[kSegmentKeep] = false;
|
||||||
mINI::Instance()[kSegmentRetain] = 5;
|
mINI::Instance()[kSegmentRetain] = 5;
|
||||||
mINI::Instance()[kFileBufSize] = 64 * 1024;
|
mINI::Instance()[kFileBufSize] = 64 * 1024;
|
||||||
mINI::Instance()[kFilePath] = "./www";
|
|
||||||
mINI::Instance()[kBroadcastRecordTs] = false;
|
mINI::Instance()[kBroadcastRecordTs] = false;
|
||||||
mINI::Instance()[kDeleteDelaySec] = 10;
|
mINI::Instance()[kDeleteDelaySec] = 10;
|
||||||
});
|
});
|
||||||
|
@ -45,14 +45,11 @@ extern const std::string kBroadcastRecordTs;
|
|||||||
|
|
||||||
// 收到http api请求广播
|
// 收到http api请求广播
|
||||||
extern const std::string kBroadcastHttpRequest;
|
extern const std::string kBroadcastHttpRequest;
|
||||||
#define BroadcastHttpRequestArgs \
|
#define BroadcastHttpRequestArgs const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, bool &consumed, SockInfo &sender
|
||||||
const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, bool &consumed, SockInfo &sender
|
|
||||||
|
|
||||||
// 在http文件服务器中,收到http访问文件或目录的广播,通过该事件控制访问http目录的权限
|
// 在http文件服务器中,收到http访问文件或目录的广播,通过该事件控制访问http目录的权限
|
||||||
extern const std::string kBroadcastHttpAccess;
|
extern const std::string kBroadcastHttpAccess;
|
||||||
#define BroadcastHttpAccessArgs \
|
#define BroadcastHttpAccessArgs const Parser &parser, const std::string &path, const bool &is_dir, const HttpSession::HttpAccessPathInvoker &invoker, SockInfo &sender
|
||||||
const Parser &parser, const std::string &path, const bool &is_dir, \
|
|
||||||
const HttpSession::HttpAccessPathInvoker &invoker, SockInfo &sender
|
|
||||||
|
|
||||||
// 在http文件服务器中,收到http访问文件或目录前的广播,通过该事件可以控制http url到文件路径的映射
|
// 在http文件服务器中,收到http访问文件或目录前的广播,通过该事件可以控制http url到文件路径的映射
|
||||||
// 在该事件中通过自行覆盖path参数,可以做到譬如根据虚拟主机或者app选择不同http根目录的目的
|
// 在该事件中通过自行覆盖path参数,可以做到譬如根据虚拟主机或者app选择不同http根目录的目的
|
||||||
@ -66,9 +63,7 @@ extern const std::string kBroadcastOnGetRtspRealm;
|
|||||||
// 请求认证用户密码事件,user_name为用户名,must_no_encrypt如果为true,则必须提供明文密码(因为此时是base64认证方式),否则会导致认证失败
|
// 请求认证用户密码事件,user_name为用户名,must_no_encrypt如果为true,则必须提供明文密码(因为此时是base64认证方式),否则会导致认证失败
|
||||||
// 获取到密码后请调用invoker并输入对应类型的密码和密码类型,invoker执行时会匹配密码
|
// 获取到密码后请调用invoker并输入对应类型的密码和密码类型,invoker执行时会匹配密码
|
||||||
extern const std::string kBroadcastOnRtspAuth;
|
extern const std::string kBroadcastOnRtspAuth;
|
||||||
#define BroadcastOnRtspAuthArgs \
|
#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
|
||||||
const MediaInfo &args, const std::string &realm, const std::string &user_name, const bool &must_no_encrypt, \
|
|
||||||
const RtspSession::onAuth &invoker, SockInfo &sender
|
|
||||||
|
|
||||||
// 推流鉴权结果回调对象
|
// 推流鉴权结果回调对象
|
||||||
// 如果err为空则代表鉴权成功
|
// 如果err为空则代表鉴权成功
|
||||||
@ -76,8 +71,7 @@ using PublishAuthInvoker = std::function<void(const std::string &err, const Prot
|
|||||||
|
|
||||||
// 收到rtsp/rtmp推流事件广播,通过该事件控制推流鉴权
|
// 收到rtsp/rtmp推流事件广播,通过该事件控制推流鉴权
|
||||||
extern const std::string kBroadcastMediaPublish;
|
extern const std::string kBroadcastMediaPublish;
|
||||||
#define BroadcastMediaPublishArgs \
|
#define BroadcastMediaPublishArgs const MediaOriginType &type, const MediaInfo &args, const Broadcast::PublishAuthInvoker &invoker, SockInfo &sender
|
||||||
const MediaOriginType &type, const MediaInfo &args, const Broadcast::PublishAuthInvoker &invoker, SockInfo &sender
|
|
||||||
|
|
||||||
// 播放鉴权结果回调对象
|
// 播放鉴权结果回调对象
|
||||||
// 如果err为空则代表鉴权成功
|
// 如果err为空则代表鉴权成功
|
||||||
@ -89,14 +83,11 @@ extern const std::string kBroadcastMediaPlayed;
|
|||||||
|
|
||||||
// shell登录鉴权
|
// shell登录鉴权
|
||||||
extern const std::string kBroadcastShellLogin;
|
extern const std::string kBroadcastShellLogin;
|
||||||
#define BroadcastShellLoginArgs \
|
#define BroadcastShellLoginArgs const std::string &user_name, const std::string &passwd, const Broadcast::AuthInvoker &invoker, SockInfo &sender
|
||||||
const std::string &user_name, const std::string &passwd, const Broadcast::AuthInvoker &invoker, SockInfo &sender
|
|
||||||
|
|
||||||
// 停止rtsp/rtmp/http-flv会话后流量汇报事件广播
|
// 停止rtsp/rtmp/http-flv会话后流量汇报事件广播
|
||||||
extern const std::string kBroadcastFlowReport;
|
extern const std::string kBroadcastFlowReport;
|
||||||
#define BroadcastFlowReportArgs \
|
#define BroadcastFlowReportArgs const MediaInfo &args, const uint64_t &totalBytes, const uint64_t &totalDuration, const bool &isPlayer, SockInfo &sender
|
||||||
const MediaInfo &args, const uint64_t &totalBytes, const uint64_t &totalDuration, const bool &isPlayer, \
|
|
||||||
SockInfo &sender
|
|
||||||
|
|
||||||
// 未找到流后会广播该事件,请在监听该事件后去拉流或其他方式产生流,这样就能按需拉流了
|
// 未找到流后会广播该事件,请在监听该事件后去拉流或其他方式产生流,这样就能按需拉流了
|
||||||
extern const std::string kBroadcastNotFoundStream;
|
extern const std::string kBroadcastNotFoundStream;
|
||||||
@ -173,28 +164,12 @@ extern const std::string kStreamNoneReaderDelayMS;
|
|||||||
extern const std::string kMaxStreamWaitTimeMS;
|
extern const std::string kMaxStreamWaitTimeMS;
|
||||||
// 是否启动虚拟主机
|
// 是否启动虚拟主机
|
||||||
extern const std::string kEnableVhost;
|
extern const std::string kEnableVhost;
|
||||||
// 拉流代理时是否添加静音音频
|
|
||||||
extern const std::string kAddMuteAudio;
|
|
||||||
// 拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
|
// 拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
|
||||||
// 如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
|
// 如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
|
||||||
extern const std::string kResetWhenRePlay;
|
extern const std::string kResetWhenRePlay;
|
||||||
// 是否默认推流时转换成hls,hook接口(on_publish)中可以覆盖该设置
|
|
||||||
extern const std::string kPublishToHls;
|
|
||||||
// 是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置
|
|
||||||
extern const std::string kPublishToMP4;
|
|
||||||
// 合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时
|
// 合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时
|
||||||
// 开启后会同时关闭TCP_NODELAY并开启MSG_MORE
|
// 开启后会同时关闭TCP_NODELAY并开启MSG_MORE
|
||||||
extern const std::string kMergeWriteMS;
|
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环境下,不能通过英伟达驱动是否存在来判断是否支持硬件转码
|
// 在docker环境下,不能通过英伟达驱动是否存在来判断是否支持硬件转码
|
||||||
extern const std::string kCheckNvidiaDev;
|
extern const std::string kCheckNvidiaDev;
|
||||||
// 是否开启ffmpeg日志
|
// 是否开启ffmpeg日志
|
||||||
@ -206,11 +181,49 @@ extern const std::string kWaitTrackReadyMS;
|
|||||||
extern const std::string kWaitAddTrackMS;
|
extern const std::string kWaitAddTrackMS;
|
||||||
// 如果track未就绪,我们先缓存帧数据,但是有最大个数限制(100帧时大约4秒),防止内存溢出
|
// 如果track未就绪,我们先缓存帧数据,但是有最大个数限制(100帧时大约4秒),防止内存溢出
|
||||||
extern const std::string kUnreadyFrameCache;
|
extern const std::string kUnreadyFrameCache;
|
||||||
// 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
|
|
||||||
// 置0关闭此特性(推流断开会导致立即断开播放器)
|
|
||||||
extern const std::string kContinuePushMS;
|
|
||||||
} // namespace General
|
} // 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配置///////////
|
////////////HTTP配置///////////
|
||||||
namespace Http {
|
namespace Http {
|
||||||
// http 文件发送缓存大小
|
// http 文件发送缓存大小
|
||||||
@ -262,8 +275,6 @@ extern const std::string kLowLatency;
|
|||||||
|
|
||||||
////////////RTMP服务器配置///////////
|
////////////RTMP服务器配置///////////
|
||||||
namespace Rtmp {
|
namespace Rtmp {
|
||||||
// rtmp推流时间戳覆盖开关
|
|
||||||
extern const std::string kModifyStamp;
|
|
||||||
// 握手超时时间,默认15秒
|
// 握手超时时间,默认15秒
|
||||||
extern const std::string kHandshakeSecond;
|
extern const std::string kHandshakeSecond;
|
||||||
// 维持链接超时时间,默认15秒
|
// 维持链接超时时间,默认15秒
|
||||||
@ -298,18 +309,12 @@ namespace Record {
|
|||||||
extern const std::string kAppName;
|
extern const std::string kAppName;
|
||||||
// 每次流化MP4文件的时长,单位毫秒
|
// 每次流化MP4文件的时长,单位毫秒
|
||||||
extern const std::string kSampleMS;
|
extern const std::string kSampleMS;
|
||||||
// MP4文件录制大小,默认一个小时
|
|
||||||
extern const std::string kFileSecond;
|
|
||||||
// 录制文件路径
|
|
||||||
extern const std::string kFilePath;
|
|
||||||
// mp4文件写缓存大小
|
// mp4文件写缓存大小
|
||||||
extern const std::string kFileBufSize;
|
extern const std::string kFileBufSize;
|
||||||
// mp4录制完成后是否进行二次关键帧索引写入头部
|
// mp4录制完成后是否进行二次关键帧索引写入头部
|
||||||
extern const std::string kFastStart;
|
extern const std::string kFastStart;
|
||||||
// mp4文件是否重头循环读取
|
// mp4文件是否重头循环读取
|
||||||
extern const std::string kFileRepeat;
|
extern const std::string kFileRepeat;
|
||||||
// MP4录制是否当做播放器参与播放人数统计
|
|
||||||
extern const std::string kMP4AsPlayer;
|
|
||||||
} // namespace Record
|
} // namespace Record
|
||||||
|
|
||||||
////////////HLS相关配置///////////
|
////////////HLS相关配置///////////
|
||||||
@ -324,8 +329,6 @@ extern const std::string kSegmentKeep;
|
|||||||
extern const std::string kSegmentRetain;
|
extern const std::string kSegmentRetain;
|
||||||
// HLS文件写缓存大小
|
// HLS文件写缓存大小
|
||||||
extern const std::string kFileBufSize;
|
extern const std::string kFileBufSize;
|
||||||
// 录制文件路径
|
|
||||||
extern const std::string kFilePath;
|
|
||||||
// 是否广播 ts 切片完成通知
|
// 是否广播 ts 切片完成通知
|
||||||
extern const std::string kBroadcastRecordTs;
|
extern const std::string kBroadcastRecordTs;
|
||||||
// hls直播文件删除延时,单位秒
|
// hls直播文件删除延时,单位秒
|
||||||
|
@ -25,7 +25,9 @@ public:
|
|||||||
|
|
||||||
FMP4MediaSourceMuxer(const std::string &vhost,
|
FMP4MediaSourceMuxer(const std::string &vhost,
|
||||||
const std::string &app,
|
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);
|
_media_src = std::make_shared<FMP4MediaSource>(vhost, app, stream_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,30 +43,27 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onReaderChanged(MediaSource &sender, int size) override {
|
void onReaderChanged(MediaSource &sender, int size) override {
|
||||||
GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand);
|
_enabled = _option.fmp4_demand ? size : true;
|
||||||
_enabled = fmp4_demand ? size : true;
|
if (!size && _option.fmp4_demand) {
|
||||||
if (!size && fmp4_demand) {
|
|
||||||
_clear_cache = true;
|
_clear_cache = true;
|
||||||
}
|
}
|
||||||
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inputFrame(const Frame::Ptr &frame) override {
|
bool inputFrame(const Frame::Ptr &frame) override {
|
||||||
GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand);
|
if (_clear_cache && _option.fmp4_demand) {
|
||||||
if (_clear_cache && fmp4_demand) {
|
|
||||||
_clear_cache = false;
|
_clear_cache = false;
|
||||||
_media_src->clearCache();
|
_media_src->clearCache();
|
||||||
}
|
}
|
||||||
if (_enabled || !fmp4_demand) {
|
if (_enabled || !_option.fmp4_demand) {
|
||||||
return MP4MuxerMemory::inputFrame(frame);
|
return MP4MuxerMemory::inputFrame(frame);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEnabled() {
|
bool isEnabled() {
|
||||||
GET_CONFIG(bool, fmp4_demand, General::kFMP4Demand);
|
|
||||||
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
||||||
return fmp4_demand ? (_clear_cache ? true : _enabled) : true;
|
return _option.fmp4_demand ? (_clear_cache ? true : _enabled) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAllTrackReady() {
|
void onAllTrackReady() {
|
||||||
@ -84,6 +83,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
bool _clear_cache = false;
|
bool _clear_cache = false;
|
||||||
|
ProtocolOption _option;
|
||||||
FMP4MediaSource::Ptr _media_src;
|
FMP4MediaSource::Ptr _media_src;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,11 +20,13 @@ class HlsRecorder final : public MediaSourceEventInterceptor, public MpegMuxer,
|
|||||||
public:
|
public:
|
||||||
using Ptr = std::shared_ptr<HlsRecorder>;
|
using Ptr = std::shared_ptr<HlsRecorder>;
|
||||||
|
|
||||||
HlsRecorder(const std::string &m3u8_file, const std::string ¶ms) : MpegMuxer(false) {
|
HlsRecorder(const std::string &m3u8_file, const std::string ¶ms, const ProtocolOption &option) : MpegMuxer(false) {
|
||||||
GET_CONFIG(uint32_t, hlsNum, Hls::kSegmentNum);
|
GET_CONFIG(uint32_t, hlsNum, Hls::kSegmentNum);
|
||||||
GET_CONFIG(bool, hlsKeep, Hls::kSegmentKeep);
|
GET_CONFIG(bool, hlsKeep, Hls::kSegmentKeep);
|
||||||
GET_CONFIG(uint32_t, hlsBufSize, Hls::kFileBufSize);
|
GET_CONFIG(uint32_t, hlsBufSize, Hls::kFileBufSize);
|
||||||
GET_CONFIG(float, hlsDuration, Hls::kSegmentDuration);
|
GET_CONFIG(float, hlsDuration, Hls::kSegmentDuration);
|
||||||
|
|
||||||
|
_option = option;
|
||||||
_hls = std::make_shared<HlsMakerImp>(m3u8_file, params, hlsBufSize, hlsDuration, hlsNum, hlsKeep);
|
_hls = std::make_shared<HlsMakerImp>(m3u8_file, params, hlsBufSize, hlsDuration, hlsNum, hlsKeep);
|
||||||
//清空上次的残余文件
|
//清空上次的残余文件
|
||||||
_hls->clearCache();
|
_hls->clearCache();
|
||||||
@ -44,10 +46,9 @@ public:
|
|||||||
int readerCount() { return _hls->getMediaSource()->readerCount(); }
|
int readerCount() { return _hls->getMediaSource()->readerCount(); }
|
||||||
|
|
||||||
void onReaderChanged(MediaSource &sender, int size) override {
|
void onReaderChanged(MediaSource &sender, int size) override {
|
||||||
GET_CONFIG(bool, hls_demand, General::kHlsDemand);
|
|
||||||
// hls保留切片个数为0时代表为hls录制(不删除切片),那么不管有无观看者都一直生成hls
|
// hls保留切片个数为0时代表为hls录制(不删除切片),那么不管有无观看者都一直生成hls
|
||||||
_enabled = hls_demand ? (_hls->isLive() ? size : true) : true;
|
_enabled = _option.hls_demand ? (_hls->isLive() ? size : true) : true;
|
||||||
if (!size && _hls->isLive() && hls_demand) {
|
if (!size && _hls->isLive() && _option.hls_demand) {
|
||||||
// hls直播时,如果无人观看就删除视频缓存,目的是为了防止视频跳跃
|
// hls直播时,如果无人观看就删除视频缓存,目的是为了防止视频跳跃
|
||||||
_clear_cache = true;
|
_clear_cache = true;
|
||||||
}
|
}
|
||||||
@ -55,23 +56,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool inputFrame(const Frame::Ptr &frame) override {
|
bool inputFrame(const Frame::Ptr &frame) override {
|
||||||
GET_CONFIG(bool, hls_demand, General::kHlsDemand);
|
if (_clear_cache && _option.hls_demand) {
|
||||||
if (_clear_cache && hls_demand) {
|
|
||||||
_clear_cache = false;
|
_clear_cache = false;
|
||||||
//清空旧的m3u8索引文件于ts切片
|
//清空旧的m3u8索引文件于ts切片
|
||||||
_hls->clearCache();
|
_hls->clearCache();
|
||||||
_hls->getMediaSource()->setIndexFile("");
|
_hls->getMediaSource()->setIndexFile("");
|
||||||
}
|
}
|
||||||
if (_enabled || !hls_demand) {
|
if (_enabled || !_option.hls_demand) {
|
||||||
return MpegMuxer::inputFrame(frame);
|
return MpegMuxer::inputFrame(frame);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEnabled() {
|
bool isEnabled() {
|
||||||
GET_CONFIG(bool, hls_demand, General::kHlsDemand);
|
|
||||||
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
||||||
return hls_demand ? (_clear_cache ? true : _enabled) : true;
|
return _option.hls_demand ? (_clear_cache ? true : _enabled) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -86,6 +85,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
bool _clear_cache = false;
|
bool _clear_cache = false;
|
||||||
|
ProtocolOption _option;
|
||||||
std::shared_ptr<HlsMakerImp> _hls;
|
std::shared_ptr<HlsMakerImp> _hls;
|
||||||
};
|
};
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -24,7 +24,7 @@ MP4Reader::MP4Reader(const string &vhost, const string &app, const string &strea
|
|||||||
_poller = WorkThreadPool::Instance().getPoller();
|
_poller = WorkThreadPool::Instance().getPoller();
|
||||||
_file_path = file_path;
|
_file_path = file_path;
|
||||||
if (_file_path.empty()) {
|
if (_file_path.empty()) {
|
||||||
GET_CONFIG(string, recordPath, Record::kFilePath);
|
GET_CONFIG(string, recordPath, Protocol::kMP4SavePath);
|
||||||
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
|
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
|
||||||
if (enableVhost) {
|
if (enableVhost) {
|
||||||
_file_path = vhost + "/" + app + "/" + stream_id;
|
_file_path = vhost + "/" + app + "/" + stream_id;
|
||||||
|
@ -28,8 +28,8 @@ MP4Recorder::MP4Recorder(const string &path, const string &vhost, const string &
|
|||||||
_info.stream = stream_id;
|
_info.stream = stream_id;
|
||||||
_info.vhost = vhost;
|
_info.vhost = vhost;
|
||||||
_info.folder = path;
|
_info.folder = path;
|
||||||
GET_CONFIG(size_t ,recordSec,Record::kFileSecond);
|
GET_CONFIG(uint32_t, s_max_second, Protocol::kMP4MaxSecond);
|
||||||
_max_second = max_second ? max_second : recordSec;
|
_max_second = max_second ? max_second : s_max_second;
|
||||||
}
|
}
|
||||||
|
|
||||||
MP4Recorder::~MP4Recorder() {
|
MP4Recorder::~MP4Recorder() {
|
||||||
|
@ -23,7 +23,7 @@ string Recorder::getRecordPath(Recorder::type type, const string &vhost, const s
|
|||||||
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
|
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Recorder::type_hls: {
|
case Recorder::type_hls: {
|
||||||
GET_CONFIG(string, hlsPath, Hls::kFilePath);
|
GET_CONFIG(string, hlsPath, Protocol::kHlsSavePath);
|
||||||
string m3u8FilePath;
|
string m3u8FilePath;
|
||||||
if (enableVhost) {
|
if (enableVhost) {
|
||||||
m3u8FilePath = vhost + "/" + app + "/" + stream_id + "/hls.m3u8";
|
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);
|
return File::absolutePath(m3u8FilePath, hlsPath);
|
||||||
}
|
}
|
||||||
case Recorder::type_mp4: {
|
case Recorder::type_mp4: {
|
||||||
GET_CONFIG(string, recordPath, Record::kFilePath);
|
GET_CONFIG(string, recordPath, Protocol::kMP4SavePath);
|
||||||
GET_CONFIG(string, recordAppName, Record::kAppName);
|
GET_CONFIG(string, recordAppName, Record::kAppName);
|
||||||
string mp4FilePath;
|
string mp4FilePath;
|
||||||
if (enableVhost) {
|
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){
|
std::shared_ptr<MediaSinkInterface> Recorder::createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const ProtocolOption &option){
|
||||||
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)
|
||||||
|
auto path = Recorder::getRecordPath(type, vhost, app, stream_id, option.hls_save_path);
|
||||||
GET_CONFIG(bool, enable_vhost, General::kEnableVhost);
|
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);
|
ret->setMediaSource(vhost, app, stream_id);
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
@ -73,7 +73,8 @@ std::shared_ptr<MediaSinkInterface> Recorder::createRecorder(type type, const st
|
|||||||
|
|
||||||
case Recorder::type_mp4: {
|
case Recorder::type_mp4: {
|
||||||
#if defined(ENABLE_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
|
#else
|
||||||
throw std::invalid_argument("mp4相关功能未打开,请开启ENABLE_MP4宏后编译再测试");
|
throw std::invalid_argument("mp4相关功能未打开,请开启ENABLE_MP4宏后编译再测试");
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,11 +10,13 @@
|
|||||||
|
|
||||||
#ifndef SRC_MEDIAFILE_RECORDER_H_
|
#ifndef SRC_MEDIAFILE_RECORDER_H_
|
||||||
#define SRC_MEDIAFILE_RECORDER_H_
|
#define SRC_MEDIAFILE_RECORDER_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
class MediaSinkInterface;
|
class MediaSinkInterface;
|
||||||
|
class ProtocolOption;
|
||||||
|
|
||||||
class RecordInfo {
|
class RecordInfo {
|
||||||
public:
|
public:
|
||||||
@ -60,7 +62,7 @@ public:
|
|||||||
* @param max_second mp4录制最大切片时间,单位秒,置0则采用配置文件配置
|
* @param max_second mp4录制最大切片时间,单位秒,置0则采用配置文件配置
|
||||||
* @return 对象指针,可能为nullptr
|
* @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:
|
private:
|
||||||
Recorder() = delete;
|
Recorder() = delete;
|
||||||
|
@ -24,7 +24,9 @@ public:
|
|||||||
RtmpMediaSourceMuxer(const std::string &vhost,
|
RtmpMediaSourceMuxer(const std::string &vhost,
|
||||||
const std::string &strApp,
|
const std::string &strApp,
|
||||||
const std::string &strId,
|
const std::string &strId,
|
||||||
|
const ProtocolOption &option,
|
||||||
const TitleMeta::Ptr &title = nullptr) : RtmpMuxer(title) {
|
const TitleMeta::Ptr &title = nullptr) : RtmpMuxer(title) {
|
||||||
|
_option = option;
|
||||||
_media_src = std::make_shared<RtmpMediaSource>(vhost, strApp, strId);
|
_media_src = std::make_shared<RtmpMediaSource>(vhost, strApp, strId);
|
||||||
getRtmpRing()->setDelegate(_media_src);
|
getRtmpRing()->setDelegate(_media_src);
|
||||||
}
|
}
|
||||||
@ -50,35 +52,33 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onReaderChanged(MediaSource &sender, int size) override {
|
void onReaderChanged(MediaSource &sender, int size) override {
|
||||||
GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand);
|
_enabled = _option.rtmp_demand ? size : true;
|
||||||
_enabled = rtmp_demand ? size : true;
|
if (!size && _option.rtmp_demand) {
|
||||||
if (!size && rtmp_demand) {
|
|
||||||
_clear_cache = true;
|
_clear_cache = true;
|
||||||
}
|
}
|
||||||
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inputFrame(const Frame::Ptr &frame) override {
|
bool inputFrame(const Frame::Ptr &frame) override {
|
||||||
GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand);
|
if (_clear_cache && _option.rtmp_demand) {
|
||||||
if (_clear_cache && rtmp_demand) {
|
|
||||||
_clear_cache = false;
|
_clear_cache = false;
|
||||||
_media_src->clearCache();
|
_media_src->clearCache();
|
||||||
}
|
}
|
||||||
if (_enabled || !rtmp_demand) {
|
if (_enabled || !_option.rtmp_demand) {
|
||||||
return RtmpMuxer::inputFrame(frame);
|
return RtmpMuxer::inputFrame(frame);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEnabled() {
|
bool isEnabled() {
|
||||||
GET_CONFIG(bool, rtmp_demand, General::kRtmpDemand);
|
|
||||||
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
||||||
return rtmp_demand ? (_clear_cache ? true : _enabled) : true;
|
return _option.rtmp_demand ? (_clear_cache ? true : _enabled) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
bool _clear_cache = false;
|
bool _clear_cache = false;
|
||||||
|
ProtocolOption _option;
|
||||||
RtmpMediaSource::Ptr _media_src;
|
RtmpMediaSource::Ptr _media_src;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -530,12 +530,6 @@ void RtmpSession::onRtmpChunk(RtmpPacket::Ptr packet) {
|
|||||||
WarnL << "Not a rtmp push!";
|
WarnL << "Not a rtmp push!";
|
||||||
return;
|
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) {
|
if (!_set_meta_data) {
|
||||||
_set_meta_data = true;
|
_set_meta_data = true;
|
||||||
|
@ -96,8 +96,6 @@ private:
|
|||||||
//消耗的总流量
|
//消耗的总流量
|
||||||
uint64_t _total_bytes = 0;
|
uint64_t _total_bytes = 0;
|
||||||
std::string _tc_url;
|
std::string _tc_url;
|
||||||
//推流时间戳修整器
|
|
||||||
Stamp _stamp[2];
|
|
||||||
//数据接收超时计时器
|
//数据接收超时计时器
|
||||||
toolkit::Ticker _ticker;
|
toolkit::Ticker _ticker;
|
||||||
MediaInfo _media_info;
|
MediaInfo _media_info;
|
||||||
|
@ -24,7 +24,9 @@ public:
|
|||||||
RtspMediaSourceMuxer(const std::string &vhost,
|
RtspMediaSourceMuxer(const std::string &vhost,
|
||||||
const std::string &strApp,
|
const std::string &strApp,
|
||||||
const std::string &strId,
|
const std::string &strId,
|
||||||
|
const ProtocolOption &option,
|
||||||
const TitleSdp::Ptr &title = nullptr) : RtspMuxer(title) {
|
const TitleSdp::Ptr &title = nullptr) : RtspMuxer(title) {
|
||||||
|
_option = option;
|
||||||
_media_src = std::make_shared<RtspMediaSource>(vhost,strApp,strId);
|
_media_src = std::make_shared<RtspMediaSource>(vhost,strApp,strId);
|
||||||
getRtpRing()->setDelegate(_media_src);
|
getRtpRing()->setDelegate(_media_src);
|
||||||
}
|
}
|
||||||
@ -49,35 +51,33 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onReaderChanged(MediaSource &sender, int size) override {
|
void onReaderChanged(MediaSource &sender, int size) override {
|
||||||
GET_CONFIG(bool, rtsp_demand, General::kRtspDemand);
|
_enabled = _option.rtsp_demand ? size : true;
|
||||||
_enabled = rtsp_demand ? size : true;
|
if (!size && _option.rtsp_demand) {
|
||||||
if (!size && rtsp_demand) {
|
|
||||||
_clear_cache = true;
|
_clear_cache = true;
|
||||||
}
|
}
|
||||||
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inputFrame(const Frame::Ptr &frame) override {
|
bool inputFrame(const Frame::Ptr &frame) override {
|
||||||
GET_CONFIG(bool, rtsp_demand, General::kRtspDemand);
|
if (_clear_cache && _option.rtsp_demand) {
|
||||||
if (_clear_cache && rtsp_demand) {
|
|
||||||
_clear_cache = false;
|
_clear_cache = false;
|
||||||
_media_src->clearCache();
|
_media_src->clearCache();
|
||||||
}
|
}
|
||||||
if (_enabled || !rtsp_demand) {
|
if (_enabled || !_option.rtsp_demand) {
|
||||||
return RtspMuxer::inputFrame(frame);
|
return RtspMuxer::inputFrame(frame);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEnabled() {
|
bool isEnabled() {
|
||||||
GET_CONFIG(bool, rtsp_demand, General::kRtspDemand);
|
|
||||||
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
||||||
return rtsp_demand ? (_clear_cache ? true : _enabled) : true;
|
return _option.rtsp_demand ? (_clear_cache ? true : _enabled) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
bool _clear_cache = false;
|
bool _clear_cache = false;
|
||||||
|
ProtocolOption _option;
|
||||||
RtspMediaSource::Ptr _media_src;
|
RtspMediaSource::Ptr _media_src;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,7 +23,9 @@ public:
|
|||||||
|
|
||||||
TSMediaSourceMuxer(const std::string &vhost,
|
TSMediaSourceMuxer(const std::string &vhost,
|
||||||
const std::string &app,
|
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);
|
_media_src = std::make_shared<TSMediaSource>(vhost, app, stream_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,30 +41,27 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onReaderChanged(MediaSource &sender, int size) override {
|
void onReaderChanged(MediaSource &sender, int size) override {
|
||||||
GET_CONFIG(bool, ts_demand, General::kTSDemand);
|
_enabled = _option.ts_demand ? size : true;
|
||||||
_enabled = ts_demand ? size : true;
|
if (!size && _option.ts_demand) {
|
||||||
if (!size && ts_demand) {
|
|
||||||
_clear_cache = true;
|
_clear_cache = true;
|
||||||
}
|
}
|
||||||
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
MediaSourceEventInterceptor::onReaderChanged(sender, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inputFrame(const Frame::Ptr &frame) override {
|
bool inputFrame(const Frame::Ptr &frame) override {
|
||||||
GET_CONFIG(bool, ts_demand, General::kTSDemand);
|
if (_clear_cache && _option.ts_demand) {
|
||||||
if (_clear_cache && ts_demand) {
|
|
||||||
_clear_cache = false;
|
_clear_cache = false;
|
||||||
_media_src->clearCache();
|
_media_src->clearCache();
|
||||||
}
|
}
|
||||||
if (_enabled || !ts_demand) {
|
if (_enabled || !_option.ts_demand) {
|
||||||
return MpegMuxer::inputFrame(frame);
|
return MpegMuxer::inputFrame(frame);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEnabled() {
|
bool isEnabled() {
|
||||||
GET_CONFIG(bool, ts_demand, General::kTSDemand);
|
|
||||||
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
|
||||||
return ts_demand ? (_clear_cache ? true : _enabled) : true;
|
return _option.ts_demand ? (_clear_cache ? true : _enabled) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -78,6 +77,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
bool _clear_cache = false;
|
bool _clear_cache = false;
|
||||||
|
ProtocolOption _option;
|
||||||
TSMediaSource::Ptr _media_src;
|
TSMediaSource::Ptr _media_src;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -125,11 +125,11 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
//设置合并写
|
//设置合并写
|
||||||
mINI::Instance()[General::kMergeWriteMS] = merge_ms;
|
mINI::Instance()[General::kMergeWriteMS] = merge_ms;
|
||||||
mINI::Instance()[General::kRtspDemand] = demand;
|
mINI::Instance()[Protocol::kRtspDemand] = demand;
|
||||||
mINI::Instance()[General::kRtmpDemand] = demand;
|
mINI::Instance()[Protocol::kRtmpDemand] = demand;
|
||||||
mINI::Instance()[General::kHlsDemand] = demand;
|
mINI::Instance()[Protocol::kHlsDemand] = demand;
|
||||||
mINI::Instance()[General::kTSDemand] = demand;
|
mINI::Instance()[Protocol::kTSDemand] = demand;
|
||||||
mINI::Instance()[General::kFMP4Demand] = demand;
|
mINI::Instance()[Protocol::kFMP4Demand] = demand;
|
||||||
|
|
||||||
map<string, PlayerProxy::Ptr> proxyMap;
|
map<string, PlayerProxy::Ptr> proxyMap;
|
||||||
ProtocolOption option;
|
ProtocolOption option;
|
||||||
|
@ -105,11 +105,11 @@ int domain(const string &filePath, const string &pushUrl) {
|
|||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
//循环点播mp4文件
|
//循环点播mp4文件
|
||||||
mINI::Instance()[Record::kFileRepeat] = 1;
|
mINI::Instance()[Record::kFileRepeat] = 1;
|
||||||
mINI::Instance()[General::kHlsDemand] = 1;
|
mINI::Instance()[Protocol::kHlsDemand] = 1;
|
||||||
mINI::Instance()[General::kTSDemand] = 1;
|
mINI::Instance()[Protocol::kTSDemand] = 1;
|
||||||
mINI::Instance()[General::kFMP4Demand] = 1;
|
mINI::Instance()[Protocol::kFMP4Demand] = 1;
|
||||||
//mINI::Instance()[General::kRtspDemand] = 1;
|
//mINI::Instance()[Protocol::kRtspDemand] = 1;
|
||||||
//mINI::Instance()[General::kRtmpDemand] = 1;
|
//mINI::Instance()[Protocol::kRtmpDemand] = 1;
|
||||||
|
|
||||||
auto poller = EventPollerPool::Instance().getPoller();
|
auto poller = EventPollerPool::Instance().getPoller();
|
||||||
//vhost/app/stream可以随便自己填,现在不限制app应用名了
|
//vhost/app/stream可以随便自己填,现在不限制app应用名了
|
||||||
|
Loading…
Reference in New Issue
Block a user