Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Z
ZLMediaKit
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
张翔宇
ZLMediaKit
Commits
9bb6a2f8
Commit
9bb6a2f8
authored
Nov 12, 2022
by
xiongziliang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
全面整理转协议相关配置文件
parent
946945ce
隐藏空白字符变更
内嵌
并排
正在显示
20 个修改的文件
包含
373 行增加
和
298 行删除
+373
-298
conf/config.ini
+50
-53
src/Common/MediaSource.cpp
+57
-3
src/Common/MediaSource.h
+85
-0
src/Common/MultiMediaSourceMuxer.cpp
+13
-28
src/Common/MultiMediaSourceMuxer.h
+0
-67
src/Common/config.cpp
+53
-30
src/Common/config.h
+47
-44
src/FMP4/FMP4MediaSourceMuxer.h
+9
-9
src/Record/HlsRecorder.h
+9
-9
src/Record/MP4Reader.cpp
+1
-1
src/Record/MP4Recorder.cpp
+2
-2
src/Record/Recorder.cpp
+7
-6
src/Record/Recorder.h
+3
-1
src/Rtmp/RtmpMediaSourceMuxer.h
+9
-9
src/Rtmp/RtmpSession.cpp
+0
-6
src/Rtmp/RtmpSession.h
+0
-2
src/Rtsp/RtspMediaSourceMuxer.h
+9
-9
src/TS/TSMediaSourceMuxer.h
+9
-9
tests/test_bench_proxy.cpp
+5
-5
tests/test_pusherMp4.cpp
+5
-5
没有找到文件。
conf/config.ini
查看文件 @
9bb6a2f8
...
...
@@ -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
#是否默认推流时转换成hls,hook接口(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
...
...
src/Common/MediaSource.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
;
}
...
...
src/Common/MediaSource.h
查看文件 @
9bb6a2f8
...
...
@@ -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
:
...
...
src/Common/MultiMediaSourceMuxer.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
;
...
...
src/Common/MultiMediaSourceMuxer.h
查看文件 @
9bb6a2f8
...
...
@@ -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
;
...
...
src/Common/config.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
;
});
...
...
src/Common/config.h
查看文件 @
9bb6a2f8
...
...
@@ -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
;
// 是否默认推流时转换成hls,hook接口(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直播文件删除延时,单位秒
...
...
src/FMP4/FMP4MediaSourceMuxer.h
查看文件 @
9bb6a2f8
...
...
@@ -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
;
};
...
...
src/Record/HlsRecorder.h
查看文件 @
9bb6a2f8
...
...
@@ -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
...
...
src/Record/MP4Reader.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
::
kFil
ePath
);
GET_CONFIG
(
string
,
recordPath
,
Protocol
::
kMP4Sav
ePath
);
GET_CONFIG
(
bool
,
enableVhost
,
General
::
kEnableVhost
);
if
(
enableVhost
)
{
_file_path
=
vhost
+
"/"
+
app
+
"/"
+
stream_id
;
...
...
src/Record/MP4Recorder.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
::
kFile
Second
);
_max_second
=
max_second
?
max_second
:
recordSec
;
GET_CONFIG
(
uint32_t
,
s_max_second
,
Protocol
::
kMP4Max
Second
);
_max_second
=
max_second
?
max_second
:
s_max_second
;
}
MP4Recorder
::~
MP4Recorder
()
{
...
...
src/Record/Recorder.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
::
kFil
ePath
);
GET_CONFIG
(
string
,
hlsPath
,
Protocol
::
kHlsSav
ePath
);
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
::
kFil
ePath
);
GET_CONFIG
(
string
,
recordPath
,
Protocol
::
kMP4Sav
ePath
);
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
...
...
src/Record/Recorder.h
查看文件 @
9bb6a2f8
...
...
@@ -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
;
...
...
src/Rtmp/RtmpMediaSourceMuxer.h
查看文件 @
9bb6a2f8
...
...
@@ -24,7 +24,9 @@ public:
RtmpMediaSourceMuxer
(
const
std
::
string
&
vhost
,
const
std
::
string
&
strApp
,
const
std
::
string
&
strId
,
const
TitleMeta
::
Ptr
&
title
=
nullptr
)
:
RtmpMuxer
(
title
){
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
;
};
...
...
src/Rtmp/RtmpSession.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
;
...
...
src/Rtmp/RtmpSession.h
查看文件 @
9bb6a2f8
...
...
@@ -96,8 +96,6 @@ private:
//消耗的总流量
uint64_t
_total_bytes
=
0
;
std
::
string
_tc_url
;
//推流时间戳修整器
Stamp
_stamp
[
2
];
//数据接收超时计时器
toolkit
::
Ticker
_ticker
;
MediaInfo
_media_info
;
...
...
src/Rtsp/RtspMediaSourceMuxer.h
查看文件 @
9bb6a2f8
...
...
@@ -24,7 +24,9 @@ public:
RtspMediaSourceMuxer
(
const
std
::
string
&
vhost
,
const
std
::
string
&
strApp
,
const
std
::
string
&
strId
,
const
TitleSdp
::
Ptr
&
title
=
nullptr
)
:
RtspMuxer
(
title
){
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
;
};
...
...
src/TS/TSMediaSourceMuxer.h
查看文件 @
9bb6a2f8
...
...
@@ -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
;
};
...
...
tests/test_bench_proxy.cpp
查看文件 @
9bb6a2f8
...
...
@@ -125,11 +125,11 @@ int main(int argc, char *argv[]) {
//设置合并写
mINI
::
Instance
()[
General
::
kMergeWriteMS
]
=
merge_ms
;
mINI
::
Instance
()[
Genera
l
::
kRtspDemand
]
=
demand
;
mINI
::
Instance
()[
Genera
l
::
kRtmpDemand
]
=
demand
;
mINI
::
Instance
()[
Genera
l
::
kHlsDemand
]
=
demand
;
mINI
::
Instance
()[
Genera
l
::
kTSDemand
]
=
demand
;
mINI
::
Instance
()[
Genera
l
::
kFMP4Demand
]
=
demand
;
mINI
::
Instance
()[
Protoco
l
::
kRtspDemand
]
=
demand
;
mINI
::
Instance
()[
Protoco
l
::
kRtmpDemand
]
=
demand
;
mINI
::
Instance
()[
Protoco
l
::
kHlsDemand
]
=
demand
;
mINI
::
Instance
()[
Protoco
l
::
kTSDemand
]
=
demand
;
mINI
::
Instance
()[
Protoco
l
::
kFMP4Demand
]
=
demand
;
map
<
string
,
PlayerProxy
::
Ptr
>
proxyMap
;
ProtocolOption
option
;
...
...
tests/test_pusherMp4.cpp
查看文件 @
9bb6a2f8
...
...
@@ -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
()[
Genera
l
::
kHlsDemand
]
=
1
;
mINI
::
Instance
()[
Genera
l
::
kTSDemand
]
=
1
;
mINI
::
Instance
()[
Genera
l
::
kFMP4Demand
]
=
1
;
//mINI::Instance()[
Genera
l::kRtspDemand] = 1;
//mINI::Instance()[
Genera
l::kRtmpDemand] = 1;
mINI
::
Instance
()[
Protoco
l
::
kHlsDemand
]
=
1
;
mINI
::
Instance
()[
Protoco
l
::
kTSDemand
]
=
1
;
mINI
::
Instance
()[
Protoco
l
::
kFMP4Demand
]
=
1
;
//mINI::Instance()[
Protoco
l::kRtspDemand] = 1;
//mINI::Instance()[
Protoco
l::kRtmpDemand] = 1;
auto
poller
=
EventPollerPool
::
Instance
().
getPoller
();
//vhost/app/stream可以随便自己填,现在不限制app应用名了
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论