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
3 years ago
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)
//获取流列表,可选筛选参数
...
...
This diff is collapsed.
Click to expand it.
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静音轨道
*/
...
...
This diff is collapsed.
Click to expand it.
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
);
...
...
This diff is collapsed.
Click to expand it.
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 */
This diff is collapsed.
Click to expand it.
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
();
...
...
This diff is collapsed.
Click to expand it.
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
;
};
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论