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
0fce108d
Commit
0fce108d
authored
Sep 20, 2020
by
xiongziliang
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/on-record-ts' of
https://github.com/wasphin/ZLMediaKit
into pr
parents
51042524
748bb8e4
隐藏空白字符变更
内嵌
并排
正在显示
12 个修改的文件
包含
147 行增加
和
31 行删除
+147
-31
api/source/mk_events_objects.cpp
+11
-11
conf/config.ini
+4
-0
server/WebHook.cpp
+22
-0
src/Common/config.cpp
+4
-0
src/Common/config.h
+7
-1
src/Record/HlsMaker.cpp
+5
-0
src/Record/HlsMaker.h
+20
-0
src/Record/HlsMakerImp.cpp
+31
-2
src/Record/HlsMakerImp.h
+4
-0
src/Record/MP4Recorder.cpp
+2
-2
src/Record/MP4Recorder.h
+3
-15
src/Record/RecordInfo.h
+34
-0
没有找到文件。
api/source/mk_events_objects.cpp
查看文件 @
0fce108d
...
...
@@ -18,64 +18,64 @@
#include "Rtsp/RtspSession.h"
using
namespace
mediakit
;
///////////////////////////////////////////
MP4
Info/////////////////////////////////////////////
///////////////////////////////////////////
Record
Info/////////////////////////////////////////////
API_EXPORT
uint64_t
API_CALL
mk_mp4_info_get_start_time
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
ui64StartedTime
;
}
API_EXPORT
uint64_t
API_CALL
mk_mp4_info_get_time_len
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
ui64TimeLen
;
}
API_EXPORT
uint64_t
API_CALL
mk_mp4_info_get_file_size
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
ui64FileSize
;
}
API_EXPORT
const
char
*
API_CALL
mk_mp4_info_get_file_path
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
strFilePath
.
c_str
();
}
API_EXPORT
const
char
*
API_CALL
mk_mp4_info_get_file_name
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
strFileName
.
c_str
();
}
API_EXPORT
const
char
*
API_CALL
mk_mp4_info_get_folder
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
strFolder
.
c_str
();
}
API_EXPORT
const
char
*
API_CALL
mk_mp4_info_get_url
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
strUrl
.
c_str
();
}
API_EXPORT
const
char
*
API_CALL
mk_mp4_info_get_vhost
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
strVhost
.
c_str
();
}
API_EXPORT
const
char
*
API_CALL
mk_mp4_info_get_app
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
strAppName
.
c_str
();
}
API_EXPORT
const
char
*
API_CALL
mk_mp4_info_get_stream
(
const
mk_mp4_info
ctx
){
assert
(
ctx
);
MP4Info
*
info
=
(
MP4
Info
*
)
ctx
;
RecordInfo
*
info
=
(
Record
Info
*
)
ctx
;
return
info
->
strStreamId
.
c_str
();
}
...
...
conf/config.ini
查看文件 @
0fce108d
...
...
@@ -66,6 +66,8 @@ segDur=2
segNum
=
3
#HLS切片从m3u8文件中移除后,继续保留在磁盘上的个数
segRetain
=
5
# 是否广播 ts 切片完成通知
broadcastRecordTs
=
0
[hook]
#在推流时,如果url参数匹对admin_params,那么可以不经过hook鉴权直接推流成功,播放时亦然
...
...
@@ -83,6 +85,8 @@ on_play=https://127.0.0.1/index/hook/on_play
on_publish
=
https://127.0.0.1/index/hook/on_publish
#录制mp4切片完成事件
on_record_mp4
=
https://127.0.0.1/index/hook/on_record_mp4
# 录制 hls ts 切片完成事件
on_record_ts
=
https://127.0.0.1/index/hook/on_record_ts
#rtsp播放鉴权事件,此事件中比对rtsp的用户名密码
on_rtsp_auth
=
https://127.0.0.1/index/hook/on_rtsp_auth
#rtsp播放是否开启专属鉴权事件,置空则关闭rtsp鉴权。rtsp播放鉴权还支持url方式鉴权
...
...
server/WebHook.cpp
查看文件 @
0fce108d
...
...
@@ -53,6 +53,7 @@ const string kOnRtspAuth = HOOK_FIELD"on_rtsp_auth";
const
string
kOnStreamChanged
=
HOOK_FIELD
"on_stream_changed"
;
const
string
kOnStreamNotFound
=
HOOK_FIELD
"on_stream_not_found"
;
const
string
kOnRecordMp4
=
HOOK_FIELD
"on_record_mp4"
;
const
string
kOnRecordTs
=
HOOK_FIELD
"on_record_ts"
;
const
string
kOnShellLogin
=
HOOK_FIELD
"on_shell_login"
;
const
string
kOnStreamNoneReader
=
HOOK_FIELD
"on_stream_none_reader"
;
const
string
kOnHttpAccess
=
HOOK_FIELD
"on_http_access"
;
...
...
@@ -70,6 +71,7 @@ onceToken token([](){
mINI
::
Instance
()[
kOnStreamChanged
]
=
"https://127.0.0.1/index/hook/on_stream_changed"
;
mINI
::
Instance
()[
kOnStreamNotFound
]
=
"https://127.0.0.1/index/hook/on_stream_not_found"
;
mINI
::
Instance
()[
kOnRecordMp4
]
=
"https://127.0.0.1/index/hook/on_record_mp4"
;
mINI
::
Instance
()[
kOnRecordTs
]
=
"https://127.0.0.1/index/hook/on_record_ts"
;
mINI
::
Instance
()[
kOnShellLogin
]
=
"https://127.0.0.1/index/hook/on_shell_login"
;
mINI
::
Instance
()[
kOnStreamNoneReader
]
=
"https://127.0.0.1/index/hook/on_stream_none_reader"
;
mINI
::
Instance
()[
kOnHttpAccess
]
=
"https://127.0.0.1/index/hook/on_http_access"
;
...
...
@@ -190,6 +192,7 @@ void installWebHook(){
GET_CONFIG
(
string
,
hook_stream_chaned
,
Hook
::
kOnStreamChanged
);
GET_CONFIG
(
string
,
hook_stream_not_found
,
Hook
::
kOnStreamNotFound
);
GET_CONFIG
(
string
,
hook_record_mp4
,
Hook
::
kOnRecordMp4
);
GET_CONFIG
(
string
,
hook_record_ts
,
Hook
::
kOnRecordTs
);
GET_CONFIG
(
string
,
hook_shell_login
,
Hook
::
kOnShellLogin
);
GET_CONFIG
(
string
,
hook_stream_none_reader
,
Hook
::
kOnStreamNoneReader
);
GET_CONFIG
(
string
,
hook_http_access
,
Hook
::
kOnHttpAccess
);
...
...
@@ -361,6 +364,25 @@ void installWebHook(){
});
#endif //ENABLE_MP4
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastRecordTs
,
[](
BroadcastRecordTsArgs
)
{
if
(
!
hook_enable
||
hook_record_ts
.
empty
())
{
return
;
}
ArgsType
body
;
body
[
"start_time"
]
=
(
Json
::
UInt64
)
info
.
ui64StartedTime
;
body
[
"time_len"
]
=
(
Json
::
UInt64
)
info
.
ui64TimeLen
;
body
[
"file_size"
]
=
(
Json
::
UInt64
)
info
.
ui64FileSize
;
body
[
"file_path"
]
=
info
.
strFilePath
;
body
[
"file_name"
]
=
info
.
strFileName
;
body
[
"folder"
]
=
info
.
strFolder
;
body
[
"url"
]
=
info
.
strUrl
;
body
[
"app"
]
=
info
.
strAppName
;
body
[
"stream"
]
=
info
.
strStreamId
;
body
[
"vhost"
]
=
info
.
strVhost
;
// 执行 hook
do_http_hook
(
hook_record_ts
,
body
,
nullptr
);
});
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastShellLogin
,[](
BroadcastShellLoginArgs
){
if
(
!
hook_enable
||
hook_shell_login
.
empty
()
||
sender
.
get_peer_ip
()
==
"127.0.0.1"
){
invoker
(
""
);
...
...
src/Common/config.cpp
查看文件 @
0fce108d
...
...
@@ -40,6 +40,7 @@ bool loadIniConfig(const char *ini_path){
namespace
Broadcast
{
const
string
kBroadcastMediaChanged
=
"kBroadcastMediaChanged"
;
const
string
kBroadcastRecordMP4
=
"kBroadcastRecordMP4"
;
const
string
kBroadcastRecordTs
=
"kBroadcastRecoredTs"
;
const
string
kBroadcastHttpRequest
=
"kBroadcastHttpRequest"
;
const
string
kBroadcastHttpAccess
=
"kBroadcastHttpAccess"
;
const
string
kBroadcastOnGetRtspRealm
=
"kBroadcastOnGetRtspRealm"
;
...
...
@@ -251,6 +252,8 @@ const string kSegmentRetain = HLS_FIELD"segRetain";
const
string
kFileBufSize
=
HLS_FIELD
"fileBufSize"
;
//录制文件路径
const
string
kFilePath
=
HLS_FIELD
"filePath"
;
// 是否广播 ts 切片完成通知
const
string
kBroadcastRecordTs
=
HLS_FIELD
"broadcastRecordTs"
;
onceToken
token
([](){
mINI
::
Instance
()[
kSegmentDuration
]
=
2
;
...
...
@@ -258,6 +261,7 @@ onceToken token([](){
mINI
::
Instance
()[
kSegmentRetain
]
=
5
;
mINI
::
Instance
()[
kFileBufSize
]
=
64
*
1024
;
mINI
::
Instance
()[
kFilePath
]
=
"./www"
;
mINI
::
Instance
()[
kBroadcastRecordTs
]
=
false
;
},
nullptr
);
}
//namespace Hls
...
...
src/Common/config.h
查看文件 @
0fce108d
...
...
@@ -58,7 +58,11 @@ extern const string kBroadcastMediaChanged;
//录制mp4文件成功后广播
extern
const
string
kBroadcastRecordMP4
;
#define BroadcastRecordMP4Args const MP4Info &info
#define BroadcastRecordMP4Args const RecordInfo &info
// 录制 ts 文件后广播
extern
const
string
kBroadcastRecordTs
;
#define BroadcastRecordTsArgs const RecordInfo &info
//收到http api请求广播
extern
const
string
kBroadcastHttpRequest
;
...
...
@@ -281,6 +285,8 @@ extern const string kSegmentRetain;
extern
const
string
kFileBufSize
;
//录制文件路径
extern
const
string
kFilePath
;
// 是否广播 ts 切片完成通知
extern
const
string
kBroadcastRecordTs
;
}
//namespace Hls
////////////Rtp代理相关配置///////////
...
...
src/Record/HlsMaker.cpp
查看文件 @
0fce108d
...
...
@@ -121,6 +121,11 @@ void HlsMaker::flushLastSegment(bool eof){
delOldSegment
();
makeIndexFile
(
eof
);
_last_file_name
.
clear
();
onFlushLastSegment
(
seg_dur
);
}
void
HlsMaker
::
onFlushLastSegment
(
uint32_t
)
{
}
bool
HlsMaker
::
isLive
()
{
...
...
src/Record/HlsMaker.h
查看文件 @
0fce108d
...
...
@@ -22,6 +22,20 @@ using namespace toolkit;
namespace
mediakit
{
class
TsInfo
{
public
:
time_t
ui64StartedTime
;
// GMT 标准时间,单位秒
time_t
ui64TimeLen
;
// 录像长度,单位毫秒
off_t
ui64FileSize
;
// 文件大小,单位 BYTE
string
strFilePath
;
// 文件路径
string
strFileName
;
// 文件名称
string
strFolder
;
// 文件夹路径
string
strUrl
;
// 播放路径
string
strAppName
;
// 应用名称
string
strStreamId
;
// 流 ID
string
strVhost
;
// vhost
};
class
HlsMaker
{
public
:
/**
...
...
@@ -84,6 +98,12 @@ protected:
*/
void
flushLastSegment
(
bool
eof
);
/**
* 上一个 ts 切片写入完成, 可在这里进行通知处理
* @param duration 上一个 ts 切片的时长, 单位为毫秒
*/
virtual
void
onFlushLastSegment
(
uint32_t
duration
);
private
:
/**
* 生成m3u8文件
...
...
src/Record/HlsMakerImp.cpp
查看文件 @
0fce108d
...
...
@@ -8,7 +8,10 @@
* may be found in the AUTHORS file in the root of the source tree.
*/
#include <ctime>
#include <sys/stat.h>
#include "HlsMakerImp.h"
#include "Thread/WorkThreadPool.h"
#include "Util/util.h"
#include "Util/uv_errno.h"
...
...
@@ -28,6 +31,8 @@ HlsMakerImp::HlsMakerImp(const string &m3u8_file,
_file_buf
.
reset
(
new
char
[
bufSize
],
[](
char
*
ptr
)
{
delete
[]
ptr
;
});
_info
.
strFolder
=
_path_prefix
;
}
HlsMakerImp
::~
HlsMakerImp
()
{
...
...
@@ -59,13 +64,19 @@ string HlsMakerImp::onOpenSegment(int index) {
}
}
_file
=
makeFile
(
segment_path
,
true
);
_info
.
ui64StartedTime
=
::
time
(
NULL
);
_info
.
strFileName
=
segment_name
;
_info
.
strFilePath
=
segment_path
;
_info
.
strUrl
=
_info
.
strAppName
+
"/"
+
_info
.
strStreamId
+
"/"
+
segment_name
;
if
(
!
_file
)
{
WarnL
<<
"create file failed,"
<<
segment_path
<<
" "
<<
get_uv_errmsg
();
}
if
(
_params
.
empty
())
{
return
s
td
::
move
(
segment_name
)
;
return
s
egment_name
;
}
return
s
td
::
move
(
segment_name
+
"?"
+
_params
)
;
return
s
egment_name
+
"?"
+
_params
;
}
void
HlsMakerImp
::
onDelSegment
(
int
index
)
{
...
...
@@ -97,6 +108,21 @@ void HlsMakerImp::onWriteHls(const char *data, int len) {
//DebugL << "\r\n" << string(data,len);
}
void
HlsMakerImp
::
onFlushLastSegment
(
uint32_t
duration
)
{
GET_CONFIG
(
bool
,
broadcastRecordTs
,
Hls
::
kBroadcastRecordTs
);
if
(
broadcastRecordTs
)
{
auto
info
=
_info
;
info
.
ui64TimeLen
=
duration
;
WorkThreadPool
::
Instance
().
getExecutor
()
->
async
([
info
]()
{
struct
stat
fileData
;
stat
(
info
.
strFilePath
.
data
(),
&
fileData
);
const_cast
<
RecordInfo
&>
(
info
).
ui64FileSize
=
fileData
.
st_size
;
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastRecordTs
,
info
);
});
}
}
std
::
shared_ptr
<
FILE
>
HlsMakerImp
::
makeFile
(
const
string
&
file
,
bool
setbuf
)
{
auto
file_buf
=
_file_buf
;
...
...
@@ -113,6 +139,9 @@ std::shared_ptr<FILE> HlsMakerImp::makeFile(const string &file, bool setbuf) {
void
HlsMakerImp
::
setMediaSource
(
const
string
&
vhost
,
const
string
&
app
,
const
string
&
stream_id
)
{
_media_src
=
std
::
make_shared
<
HlsMediaSource
>
(
vhost
,
app
,
stream_id
);
_info
.
strAppName
=
app
;
_info
.
strStreamId
=
stream_id
;
_info
.
strVhost
=
vhost
;
}
HlsMediaSource
::
Ptr
HlsMakerImp
::
getMediaSource
()
const
{
...
...
src/Record/HlsMakerImp.h
查看文件 @
0fce108d
...
...
@@ -16,6 +16,8 @@
#include <stdlib.h>
#include "HlsMaker.h"
#include "HlsMediaSource.h"
#include "RecordInfo.h"
using
namespace
std
;
namespace
mediakit
{
...
...
@@ -54,6 +56,7 @@ protected:
void
onDelSegment
(
int
index
)
override
;
void
onWriteSegment
(
const
char
*
data
,
int
len
)
override
;
void
onWriteHls
(
const
char
*
data
,
int
len
)
override
;
void
onFlushLastSegment
(
uint32_t
duration
)
override
;
private
:
std
::
shared_ptr
<
FILE
>
makeFile
(
const
string
&
file
,
bool
setbuf
=
false
);
...
...
@@ -66,6 +69,7 @@ private:
std
::
shared_ptr
<
FILE
>
_file
;
std
::
shared_ptr
<
char
>
_file_buf
;
HlsMediaSource
::
Ptr
_media_src
;
RecordInfo
_info
;
map
<
int
/*index*/
,
string
/*file_path*/
>
_segment_file_paths
;
};
...
...
src/Record/MP4Recorder.cpp
查看文件 @
0fce108d
...
...
@@ -73,7 +73,7 @@ void MP4Recorder::asyncClose() {
auto
info
=
_info
;
WorkThreadPool
::
Instance
().
getExecutor
()
->
async
([
muxer
,
strFileTmp
,
strFile
,
info
]()
{
//获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间
const_cast
<
MP4
Info
&>
(
info
).
ui64TimeLen
=
::
time
(
NULL
)
-
info
.
ui64StartedTime
;
const_cast
<
Record
Info
&>
(
info
).
ui64TimeLen
=
::
time
(
NULL
)
-
info
.
ui64StartedTime
;
//关闭mp4非常耗时,所以要放在后台线程执行
muxer
->
closeMP4
();
//临时文件名改成正式文件名,防止mp4未完成时被访问
...
...
@@ -81,7 +81,7 @@ void MP4Recorder::asyncClose() {
//获取文件大小
struct
stat
fileData
;
stat
(
strFile
.
data
(),
&
fileData
);
const_cast
<
MP4
Info
&>
(
info
).
ui64FileSize
=
fileData
.
st_size
;
const_cast
<
Record
Info
&>
(
info
).
ui64FileSize
=
fileData
.
st_size
;
/////record 业务逻辑//////
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastRecordMP4
,
info
);
});
...
...
src/Record/MP4Recorder.h
查看文件 @
0fce108d
...
...
@@ -20,24 +20,12 @@
#include "Util/TimeTicker.h"
#include "Common/MediaSink.h"
#include "MP4Muxer.h"
#include "RecordInfo.h"
using
namespace
toolkit
;
namespace
mediakit
{
class
MP4Info
{
public
:
time_t
ui64StartedTime
;
//GMT标准时间,单位秒
time_t
ui64TimeLen
;
//录像长度,单位秒
off_t
ui64FileSize
;
//文件大小,单位BYTE
string
strFilePath
;
//文件路径
string
strFileName
;
//文件名称
string
strFolder
;
//文件夹路径
string
strUrl
;
//播放路径
string
strAppName
;
//应用名称
string
strStreamId
;
//流ID
string
strVhost
;
//vhost
};
#ifdef ENABLE_MP4
class
MP4Recorder
:
public
MediaSinkInterface
{
public
:
...
...
@@ -72,7 +60,7 @@ private:
string
_strFile
;
string
_strFileTmp
;
Ticker
_createFileTicker
;
MP4
Info
_info
;
Record
Info
_info
;
bool
_haveVideo
=
false
;
MP4Muxer
::
Ptr
_muxer
;
list
<
Track
::
Ptr
>
_tracks
;
...
...
src/Record/RecordInfo.h
0 → 100644
查看文件 @
0fce108d
/*
* Copyright (c) 2020 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RECORDINFO_H_
#define RECORDINFO_H_
#include "Common/config.h"
namespace
mediakit
{
class
RecordInfo
{
public
:
time_t
ui64StartedTime
;
// GMT 标准时间,单位秒
time_t
ui64TimeLen
;
// 录像长度,需要注意 mp4 单位是秒,而 hls ts 单位是毫秒
off_t
ui64FileSize
;
// 文件大小,单位 BYTE
string
strFilePath
;
// 文件路径
string
strFileName
;
// 文件名称
string
strFolder
;
// 文件夹路径
string
strUrl
;
// 播放路径
string
strAppName
;
// 应用名称
string
strStreamId
;
// 流 ID
string
strVhost
;
// vhost
};
}
// namespace mediakit
#endif // RECORDINFO_H_
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论