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
fe575af0
Commit
fe575af0
authored
Dec 22, 2021
by
ziyue
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of github.com:ZLMediaKit/ZLMediaKit
parents
6a044f07
052cca07
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
159 行增加
和
53 行删除
+159
-53
server/WebApi.cpp
+59
-0
src/Common/MediaSink.h
+8
-1
src/Http/HlsPlayer.cpp
+6
-0
src/Http/HttpClient.cpp
+9
-2
src/Record/MP4Reader.cpp
+56
-39
src/Record/MP4Reader.h
+21
-11
没有找到文件。
server/WebApi.cpp
查看文件 @
fe575af0
...
...
@@ -42,6 +42,12 @@
#include "../webrtc/WebRtcPusher.h"
#include "../webrtc/WebRtcEchoTest.h"
#endif
#ifdef _WIN32
#include <io.h>
#include <iostream>
#include <tchar.h>
#endif // _WIN32
using
namespace
toolkit
;
using
namespace
mediakit
;
...
...
@@ -508,6 +514,59 @@ void installWebApi() {
});
val
[
"msg"
]
=
"服务器将在一秒后自动重启"
;
});
#else
//增加Windows下的重启代码
api_regist
(
"/index/api/restartServer"
,
[](
API_ARGS_MAP
)
{
CHECK_SECRET
();
//创建重启批处理脚本文件
FILE
*
pf
;
errno_t
err
=
::
_wfopen_s
(
&
pf
,
L"RestartServer.cmd"
,
L"w"
);
//“w”如果该文件存在,其内容将被覆盖
if
(
err
==
0
)
{
char
szExeName
[
1024
];
char
drive
[
_MAX_DRIVE
]
=
{
0
};
char
dir
[
_MAX_DIR
]
=
{
0
};
char
fname
[
_MAX_FNAME
]
=
{
0
};
char
ext
[
_MAX_EXT
]
=
{
0
};
char
exeName
[
_MAX_FNAME
]
=
{
0
};
GetModuleFileNameA
(
NULL
,
szExeName
,
1024
);
//获取进程的全路径
_splitpath
(
szExeName
,
drive
,
dir
,
fname
,
ext
);
strcpy
(
exeName
,
fname
);
strcat
(
exeName
,
ext
);
fprintf
(
pf
,
"@echo off
\n
taskkill /f /im %s
\n
start
\"\"
\"
%s
\"\n
del %%0"
,
exeName
,
szExeName
);
fclose
(
pf
);
// 1秒后执行创建的批处理脚本
EventPollerPool
::
Instance
().
getPoller
()
->
doDelayTask
(
1000
,
[]()
{
STARTUPINFO
si
;
PROCESS_INFORMATION
pi
;
ZeroMemory
(
&
si
,
sizeof
si
);
ZeroMemory
(
&
pi
,
sizeof
pi
);
si
.
cb
=
sizeof
si
;
si
.
dwFlags
=
STARTF_USESHOWWINDOW
;
si
.
wShowWindow
=
SW_HIDE
;
TCHAR
winSysDir
[
1024
];
ZeroMemory
(
winSysDir
,
sizeof
winSysDir
);
GetSystemDirectory
(
winSysDir
,
1024
);
TCHAR
appName
[
1024
];
ZeroMemory
(
appName
,
sizeof
appName
);
_stprintf
(
appName
,
"%s
\\
cmd.exe"
,
winSysDir
);
BOOL
bRet
=
CreateProcess
(
appName
,
" /c RestartServer.cmd"
,
NULL
,
NULL
,
FALSE
,
0
,
NULL
,
NULL
,
&
si
,
&
pi
);
if
(
bRet
==
FALSE
)
{
int
err
=
GetLastError
();
cout
<<
endl
<<
"无法执行重启操作,错误代码:"
<<
err
<<
endl
;
}
WaitForSingleObject
(
pi
.
hProcess
,
INFINITE
);
CloseHandle
(
pi
.
hProcess
);
CloseHandle
(
pi
.
hThread
);
return
0
;
});
val
[
"msg"
]
=
"服务器将在一秒后自动重启"
;
}
else
{
val
[
"msg"
]
=
"创建重启脚本文件失败"
;
val
[
"code"
]
=
API
::
OtherFailed
;
}
});
#endif//#if !defined(_WIN32)
//获取流列表,可选筛选参数
...
...
src/Common/MediaSink.h
查看文件 @
fe575af0
...
...
@@ -107,7 +107,14 @@ public:
* @param trackReady 是否获取已经准备好的Track
*/
vector
<
Track
::
Ptr
>
getTracks
(
bool
trackReady
=
true
)
const
override
;
/**
* 返回是否所有track已经准备完成
*/
bool
isAllTrackReady
()
const
{
return
_all_track_ready
;
}
/**
* 添加aac静音轨道
*/
...
...
src/Http/HlsPlayer.cpp
查看文件 @
fe575af0
...
...
@@ -324,6 +324,12 @@ void HlsDemuxer::start(const EventPoller::Ptr &poller, TrackListener *listener)
}
bool
HlsDemuxer
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
//为了避免track准备时间过长, 因此在没准备好之前, 直接消费掉所有的帧
if
(
!
_delegate
.
isAllTrackReady
())
{
_delegate
.
inputFrame
(
frame
);
return
true
;
}
//计算相对时间戳
int64_t
dts
,
pts
;
_stamp
[
frame
->
getTrackType
()].
revise
(
frame
->
dts
(),
frame
->
pts
(),
dts
,
pts
);
...
...
src/Http/HttpClient.cpp
查看文件 @
fe575af0
...
...
@@ -9,6 +9,7 @@
*/
#include <cstdlib>
#include "Util/base64.h"
#include "HttpClient.h"
#include "Common/config.h"
...
...
@@ -39,6 +40,13 @@ void HttpClient::sendRequest(const string &strUrl, float fTimeOutSec) {
if
(
_path
.
empty
())
{
_path
=
"/"
;
}
auto
pos
=
host
.
find
(
'@'
);
if
(
pos
!=
string
::
npos
)
{
//去除?后面的字符串
auto
authStr
=
host
.
substr
(
0
,
pos
);
host
=
host
.
substr
(
pos
+
1
,
host
.
size
());
_header
.
emplace
(
"Authorization"
,
"Basic "
+
encodeBase64
(
authStr
));
}
auto
host_header
=
host
;
uint16_t
port
=
atoi
(
FindField
(
host
.
data
(),
":"
,
NULL
).
data
());
if
(
port
<=
0
)
{
...
...
@@ -328,4 +336,4 @@ void HttpClient::checkCookie(HttpClient::HttpHeader &headers) {
}
}
}
/* namespace mediakit */
\ No newline at end of file
}
/* namespace mediakit */
src/Record/MP4Reader.cpp
查看文件 @
fe575af0
...
...
@@ -9,14 +9,16 @@
*/
#ifdef ENABLE_MP4
#include "MP4Reader.h"
#include "Common/config.h"
#include "Thread/WorkThreadPool.h"
using
namespace
toolkit
;
namespace
mediakit
{
MP4Reader
::
MP4Reader
(
const
string
&
vhost
,
const
string
&
app
,
const
string
&
stream_id
,
const
string
&
file_path
)
{
_poller
=
WorkThreadPool
::
Instance
().
getPoller
();
_file_path
=
file_path
;
if
(
_file_path
.
empty
())
{
GET_CONFIG
(
string
,
recordPath
,
Record
::
kFilePath
);
...
...
@@ -37,12 +39,12 @@ MP4Reader::MP4Reader(const string &vhost, const string &app, const string &strea
}
_muxer
=
std
::
make_shared
<
MultiMediaSourceMuxer
>
(
vhost
,
app
,
stream_id
,
_demuxer
->
getDurationMS
()
/
1000.0
f
,
true
,
true
,
false
,
false
);
auto
tracks
=
_demuxer
->
getTracks
(
false
);
if
(
tracks
.
empty
())
{
if
(
tracks
.
empty
())
{
throw
std
::
runtime_error
(
StrPrinter
<<
"该mp4文件没有有效的track:"
<<
_file_path
);
}
for
(
auto
&
track
:
tracks
)
{
for
(
auto
&
track
:
tracks
)
{
_muxer
->
addTrack
(
track
);
if
(
track
->
getTrackType
()
==
TrackVideo
)
{
if
(
track
->
getTrackType
()
==
TrackVideo
)
{
_have_video
=
true
;
}
}
...
...
@@ -70,8 +72,8 @@ bool MP4Reader::readSample() {
}
}
GET_CONFIG
(
bool
,
file
R
epeat
,
Record
::
kFileRepeat
);
if
(
eof
&&
(
file
R
epeat
||
_file_repeat
))
{
GET_CONFIG
(
bool
,
file
_r
epeat
,
Record
::
kFileRepeat
);
if
(
eof
&&
(
file
_r
epeat
||
_file_repeat
))
{
//需要从头开始看
seekTo
(
0
);
return
true
;
...
...
@@ -80,37 +82,53 @@ bool MP4Reader::readSample() {
return
!
eof
;
}
bool
MP4Reader
::
readNextSample
()
{
bool
keyFrame
=
false
;
bool
eof
=
false
;
auto
frame
=
_demuxer
->
readFrame
(
keyFrame
,
eof
);
if
(
!
frame
)
{
return
false
;
}
if
(
_muxer
)
{
_muxer
->
inputFrame
(
frame
);
}
setCurrentStamp
(
frame
->
dts
());
return
true
;
}
void
MP4Reader
::
stopReadMP4
()
{
_timer
=
nullptr
;
}
void
MP4Reader
::
startReadMP4
(
const
EventPoller
::
Ptr
&
poller
,
uint64_t
sample_ms
,
bool
ref_self
,
bool
file_repeat
)
{
void
MP4Reader
::
startReadMP4
(
const
EventPoller
::
Ptr
&
poller
_in
,
uint64_t
sample_ms
,
bool
ref_self
,
bool
file_repeat
)
{
GET_CONFIG
(
uint32_t
,
sampleMS
,
Record
::
kSampleMS
);
auto
strongSelf
=
shared_from_this
();
if
(
_muxer
)
{
_muxer
->
setMediaListener
(
strongSelf
);
}
auto
strong_self
=
shared_from_this
();
if
(
_muxer
)
{
_muxer
->
setMediaListener
(
strong_self
);
//一直读到所有track就绪为止
while
(
!
_muxer
->
isAllTrackReady
()
&&
readNextSample
())
{}
}
//先获取关键帧
seekTo
(
0
);
//读sampleMS毫秒的数据用于产生MediaSource
setCurrentStamp
(
getCurrentStamp
()
+
sampleMS
);
readSample
();
//未指定线程,那么使用后台线程(读写文件采用后台线程)
auto
poller
=
poller_in
?
poller_in
:
WorkThreadPool
::
Instance
().
getPoller
();
auto
timer_sec
=
(
sample_ms
?
sample_ms
:
sampleMS
)
/
1000.0
f
;
//启动定时器
if
(
ref_self
)
{
_timer
=
std
::
make_shared
<
Timer
>
(
(
sample_ms
?
sample_ms
:
sampleMS
)
/
1000.0
f
,
[
strongS
elf
]()
{
lock_guard
<
recursive_mutex
>
lck
(
strong
S
elf
->
_mtx
);
return
strong
S
elf
->
readSample
();
},
poller
?
poller
:
_poller
);
_timer
=
std
::
make_shared
<
Timer
>
(
timer_sec
,
[
strong_s
elf
]()
{
lock_guard
<
recursive_mutex
>
lck
(
strong
_s
elf
->
_mtx
);
return
strong
_s
elf
->
readSample
();
},
poller
);
}
else
{
weak_ptr
<
MP4Reader
>
weak_self
=
strong
S
elf
;
_timer
=
std
::
make_shared
<
Timer
>
(
(
sample_ms
?
sample_ms
:
sampleMS
)
/
1000.0
f
,
[
weak_self
]()
{
auto
strong
S
elf
=
weak_self
.
lock
();
if
(
!
strong
S
elf
)
{
weak_ptr
<
MP4Reader
>
weak_self
=
strong
_s
elf
;
_timer
=
std
::
make_shared
<
Timer
>
(
timer_sec
,
[
weak_self
]()
{
auto
strong
_s
elf
=
weak_self
.
lock
();
if
(
!
strong
_s
elf
)
{
return
false
;
}
lock_guard
<
recursive_mutex
>
lck
(
strong
S
elf
->
_mtx
);
return
strong
S
elf
->
readSample
();
},
poller
?
poller
:
_poller
);
lock_guard
<
recursive_mutex
>
lck
(
strong
_s
elf
->
_mtx
);
return
strong
_s
elf
->
readSample
();
},
poller
);
}
_file_repeat
=
file_repeat
;
...
...
@@ -121,10 +139,10 @@ const MP4Demuxer::Ptr &MP4Reader::getDemuxer() const {
}
uint32_t
MP4Reader
::
getCurrentStamp
()
{
return
(
uint32_t
)(
_seek_to
+
!
_paused
*
_speed
*
_seek_ticker
.
elapsedTime
());
return
(
uint32_t
)
(
_seek_to
+
!
_paused
*
_speed
*
_seek_ticker
.
elapsedTime
());
}
void
MP4Reader
::
setCurrentStamp
(
uint32_t
new_stamp
){
void
MP4Reader
::
setCurrentStamp
(
uint32_t
new_stamp
)
{
auto
old_stamp
=
getCurrentStamp
();
_seek_to
=
new_stamp
;
_last_dts
=
new_stamp
;
...
...
@@ -168,22 +186,21 @@ bool MP4Reader::speed(MediaSource &sender, float speed) {
return
true
;
}
bool
MP4Reader
::
seekTo
(
uint32_t
ui32Stamp
)
{
bool
MP4Reader
::
seekTo
(
uint32_t
stamp_seek
)
{
lock_guard
<
recursive_mutex
>
lck
(
_mtx
);
if
(
ui32Stamp
>
_demuxer
->
getDurationMS
())
{
if
(
stamp_seek
>
_demuxer
->
getDurationMS
())
{
//超过文件长度
return
false
;
}
auto
stamp
=
_demuxer
->
seekTo
(
ui32Stamp
);
if
(
stamp
==
-
1
)
{
auto
stamp
=
_demuxer
->
seekTo
(
stamp_seek
);
if
(
stamp
==
-
1
)
{
//seek失败
return
false
;
}
if
(
!
_have_video
){
//没有视频,不需要搜索关键帧
//设置当前时间戳
setCurrentStamp
((
uint32_t
)
stamp
);
if
(
!
_have_video
)
{
//没有视频,不需要搜索关键帧;设置当前时间戳
setCurrentStamp
((
uint32_t
)
stamp
);
return
true
;
}
//搜索到下一帧关键帧
...
...
@@ -191,11 +208,11 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp) {
bool
eof
=
false
;
while
(
!
eof
)
{
auto
frame
=
_demuxer
->
readFrame
(
keyFrame
,
eof
);
if
(
!
frame
)
{
if
(
!
frame
)
{
//文件读完了都未找到下一帧关键帧
continue
;
}
if
(
keyFrame
||
frame
->
keyFrame
()
||
frame
->
configFrame
())
{
if
(
keyFrame
||
frame
->
keyFrame
()
||
frame
->
configFrame
())
{
//定位到key帧
if
(
_muxer
)
{
_muxer
->
inputFrame
(
frame
);
...
...
@@ -208,8 +225,8 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp) {
return
false
;
}
bool
MP4Reader
::
close
(
MediaSource
&
sender
,
bool
force
)
{
if
(
!
_muxer
||
(
!
force
&&
_muxer
->
totalReaderCount
()))
{
bool
MP4Reader
::
close
(
MediaSource
&
sender
,
bool
force
)
{
if
(
!
_muxer
||
(
!
force
&&
_muxer
->
totalReaderCount
()))
{
return
false
;
}
_timer
.
reset
();
...
...
src/Record/MP4Reader.h
查看文件 @
fe575af0
...
...
@@ -16,27 +16,37 @@
using
namespace
toolkit
;
namespace
mediakit
{
class
MP4Reader
:
public
std
::
enable_shared_from_this
<
MP4Reader
>
,
public
MediaSourceEvent
{
class
MP4Reader
:
public
std
::
enable_shared_from_this
<
MP4Reader
>
,
public
MediaSourceEvent
{
public
:
typedef
std
::
shared_ptr
<
MP4Reader
>
Ptr
;
virtual
~
MP4Reader
()
=
default
;
using
Ptr
=
std
::
shared_ptr
<
MP4Reader
>
;
/**
*
流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource
*
点播一个mp4文件,使之转换成MediaSource流媒体
* @param vhost 虚拟主机
* @param app 应用名
* @param stream_id 流id
* @param stream_id 流id
,置空时,只解复用mp4,但是不生成MediaSource
* @param file_path 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件
*/
MP4Reader
(
const
string
&
vhost
,
const
string
&
app
,
const
string
&
stream_id
,
const
string
&
file_path
=
""
);
~
MP4Reader
()
override
=
default
;
/**
* 开始流化MP4文件,需要指出的是,MP4Reader对象一经过调用startReadMP4方法,它的强引用会自持有,
* 意思是在文件流化结束之前或中断之前,MP4Reader对象是不会被销毁的(不管有没有被外部对象持有)
* 开始解复用MP4文件
* @param poller 解复用mp4定时器所绑定线程,置空则随机采用一条后台线程
* @param sample_ms 每次读取文件数据量,单位毫秒,置0时采用配置文件配置
* @param ref_self 是否让定时器引用此对象本身,如果无其他对象引用本身,在不循环读文件时,读取文件结束后本对象将自动销毁
* @param file_repeat 是否循环读取文件,如果配置文件设置为循环读文件,此参数无效
*/
void
startReadMP4
(
const
EventPoller
::
Ptr
&
poller
=
nullptr
,
uint64_t
sample_ms
=
0
,
bool
ref_self
=
true
,
bool
file_repeat
=
false
);
/**
* 停止解复用MP4定时器
*/
void
stopReadMP4
();
/**
* 获取mp4解复用器
*/
const
MP4Demuxer
::
Ptr
&
getDemuxer
()
const
;
private
:
...
...
@@ -51,9 +61,10 @@ private:
string
getOriginUrl
(
MediaSource
&
sender
)
const
override
;
bool
readSample
();
bool
readNextSample
();
uint32_t
getCurrentStamp
();
void
setCurrentStamp
(
uint32_t
ui32S
tamp
);
bool
seekTo
(
uint32_t
ui32Stamp
);
void
setCurrentStamp
(
uint32_t
s
tamp
);
bool
seekTo
(
uint32_t
stamp_seek
);
private
:
bool
_file_repeat
=
false
;
...
...
@@ -61,12 +72,11 @@ private:
bool
_paused
=
false
;
float
_speed
=
1
.
0
;
uint32_t
_last_dts
=
0
;
uint32_t
_seek_to
;
uint32_t
_seek_to
=
0
;
string
_file_path
;
recursive_mutex
_mtx
;
Ticker
_seek_ticker
;
Timer
::
Ptr
_timer
;
EventPoller
::
Ptr
_poller
;
MP4Demuxer
::
Ptr
_demuxer
;
MultiMediaSourceMuxer
::
Ptr
_muxer
;
};
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论