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
46be8a38
Commit
46be8a38
authored
Apr 03, 2020
by
xiongziliang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
重写MP4点播
parent
f03365ef
显示空白字符变更
内嵌
并排
正在显示
17 个修改的文件
包含
185 行增加
和
510 行删除
+185
-510
3rdpart/media-server
+1
-1
Android/app/src/main/cpp/CMakeLists.txt
+5
-5
CMakeLists.txt
+4
-14
server/WebHook.cpp
+2
-2
src/Common/Device.cpp
+2
-2
src/Common/MediaSource.cpp
+1
-1
src/Extension/AAC.h
+1
-1
src/Extension/H265.h
+1
-1
src/Player/PlayerProxy.cpp
+1
-1
src/Record/MP4Muxer.cpp
+19
-102
src/Record/MP4Muxer.h
+12
-44
src/Record/MP4Reader.cpp
+95
-262
src/Record/MP4Reader.h
+32
-65
src/Record/MP4Recorder.cpp
+4
-4
src/Record/MP4Recorder.h
+3
-3
src/Record/Recorder.cpp
+1
-1
src/Rtp/RtpProcess.cpp
+1
-1
没有找到文件。
media-server
@
9f12aee3
Subproject commit
737b8d852eeb1a36bc77854f327fbbef7cfb81be
Subproject commit
9f12aee385993d14b18a1d773be5eedbbe4fa2c2
Android/app/src/main/cpp/CMakeLists.txt
查看文件 @
46be8a38
...
@@ -40,7 +40,7 @@ set(ENABLE_MYSQL false)
...
@@ -40,7 +40,7 @@ set(ENABLE_MYSQL false)
set
(
ENABLE_MP4V2 true
)
set
(
ENABLE_MP4V2 true
)
set
(
ENABLE_FAAC false
)
set
(
ENABLE_FAAC false
)
set
(
ENABLE_X264 false
)
set
(
ENABLE_X264 false
)
set
(
ENABLE_MP4
RECORD
true
)
set
(
ENABLE_MP4 true
)
#添加两个静态库
#添加两个静态库
if
(
ENABLE_HLS
)
if
(
ENABLE_HLS
)
...
@@ -52,9 +52,9 @@ else()
...
@@ -52,9 +52,9 @@ else()
endif
()
endif
()
if
(
ENABLE_MP4
RECORD
)
if
(
ENABLE_MP4
)
message
(
STATUS
"ENABLE_MP4
RECORD
defined"
)
message
(
STATUS
"ENABLE_MP4 defined"
)
add_definitions
(
-DENABLE_MP4
RECORD
)
add_definitions
(
-DENABLE_MP4
)
list
(
APPEND LINK_LIB_LIST mov flv
)
list
(
APPEND LINK_LIB_LIST mov flv
)
endif
()
endif
()
...
@@ -87,7 +87,7 @@ if(ENABLE_HLS)
...
@@ -87,7 +87,7 @@ if(ENABLE_HLS)
endif
(
WIN32
)
endif
(
WIN32
)
endif
()
endif
()
if
(
ENABLE_MP4
RECORD
)
if
(
ENABLE_MP4
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/include src_mov
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/include src_mov
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/source src_mov
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/source src_mov
)
include_directories
(
${
MediaServer_Root
}
/libmov/include
)
include_directories
(
${
MediaServer_Root
}
/libmov/include
)
...
...
CMakeLists.txt
查看文件 @
46be8a38
...
@@ -43,10 +43,9 @@ INCLUDE_DIRECTORIES(${MediaKit_Root})
...
@@ -43,10 +43,9 @@ INCLUDE_DIRECTORIES(${MediaKit_Root})
set
(
ENABLE_HLS true
)
set
(
ENABLE_HLS true
)
set
(
ENABLE_OPENSSL true
)
set
(
ENABLE_OPENSSL true
)
set
(
ENABLE_MYSQL false
)
set
(
ENABLE_MYSQL false
)
set
(
ENABLE_MP4V2 true
)
set
(
ENABLE_FAAC false
)
set
(
ENABLE_FAAC false
)
set
(
ENABLE_X264 false
)
set
(
ENABLE_X264 false
)
set
(
ENABLE_MP4
RECORD
true
)
set
(
ENABLE_MP4 true
)
set
(
ENABLE_RTPPROXY true
)
set
(
ENABLE_RTPPROXY true
)
set
(
LINK_LIB_LIST zlmediakit zltoolkit
)
set
(
LINK_LIB_LIST zlmediakit zltoolkit
)
...
@@ -70,15 +69,6 @@ if (MYSQL_FOUND AND ENABLE_MYSQL)
...
@@ -70,15 +69,6 @@ if (MYSQL_FOUND AND ENABLE_MYSQL)
list
(
APPEND LINK_LIB_LIST
${
MYSQL_LIBRARIES
}
)
list
(
APPEND LINK_LIB_LIST
${
MYSQL_LIBRARIES
}
)
endif
()
endif
()
#查找MP4V2是否安装
find_package
(
MP4V2 QUIET
)
if
(
MP4V2_FOUND AND ENABLE_MP4V2
)
include_directories
(
${
MP4V2_INCLUDE_DIR
}
)
list
(
APPEND LINK_LIB_LIST
${
MP4V2_LIBRARY
}
)
add_definitions
(
-DENABLE_MP4V2
)
message
(
STATUS
"found library:
${
MP4V2_LIBRARY
}
,ENABLE_MP4V2 defined"
)
endif
()
#查找x264是否安装
#查找x264是否安装
find_package
(
X264 QUIET
)
find_package
(
X264 QUIET
)
if
(
X264_FOUND AND ENABLE_X264
)
if
(
X264_FOUND AND ENABLE_X264
)
...
@@ -127,9 +117,9 @@ if(ENABLE_HLS)
...
@@ -127,9 +117,9 @@ if(ENABLE_HLS)
endif
()
endif
()
#添加mov、flv库用于MP4录制
#添加mov、flv库用于MP4录制
if
(
ENABLE_MP4
RECORD
)
if
(
ENABLE_MP4
)
message
(
STATUS
"ENABLE_MP4
RECORD
defined"
)
message
(
STATUS
"ENABLE_MP4 defined"
)
add_definitions
(
-DENABLE_MP4
RECORD
)
add_definitions
(
-DENABLE_MP4
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/include src_mov
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/include src_mov
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/source src_mov
)
aux_source_directory
(
${
MediaServer_Root
}
/libmov/source src_mov
)
...
...
server/WebHook.cpp
查看文件 @
46be8a38
...
@@ -362,7 +362,7 @@ void installWebHook(){
...
@@ -362,7 +362,7 @@ void installWebHook(){
do_http_hook
(
hook_stream_not_found
,
body
,
nullptr
);
do_http_hook
(
hook_stream_not_found
,
body
,
nullptr
);
});
});
#ifdef ENABLE_MP4
RECORD
#ifdef ENABLE_MP4
//录制mp4文件成功后广播
//录制mp4文件成功后广播
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastRecordMP4
,[](
BroadcastRecordMP4Args
){
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastRecordMP4
,[](
BroadcastRecordMP4Args
){
if
(
!
hook_enable
||
hook_record_mp4
.
empty
()){
if
(
!
hook_enable
||
hook_record_mp4
.
empty
()){
...
@@ -382,7 +382,7 @@ void installWebHook(){
...
@@ -382,7 +382,7 @@ void installWebHook(){
//执行hook
//执行hook
do_http_hook
(
hook_record_mp4
,
body
,
nullptr
);
do_http_hook
(
hook_record_mp4
,
body
,
nullptr
);
});
});
#endif //ENABLE_MP4
RECORD
#endif //ENABLE_MP4
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastShellLogin
,[](
BroadcastShellLoginArgs
){
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastShellLogin
,[](
BroadcastShellLoginArgs
){
if
(
!
hook_enable
||
hook_shell_login
.
empty
()
||
sender
.
get_peer_ip
()
==
"127.0.0.1"
){
if
(
!
hook_enable
||
hook_shell_login
.
empty
()
||
sender
.
get_peer_ip
()
==
"127.0.0.1"
){
...
...
src/Common/Device.cpp
查看文件 @
46be8a38
...
@@ -152,12 +152,12 @@ void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t u
...
@@ -152,12 +152,12 @@ void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t u
uiStamp
=
(
uint32_t
)
_aTicker
[
1
].
elapsedTime
();
uiStamp
=
(
uint32_t
)
_aTicker
[
1
].
elapsedTime
();
}
}
if
(
pcAdtsHeader
+
7
==
pcDataWithoutAdts
){
if
(
pcAdtsHeader
+
7
==
pcDataWithoutAdts
){
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
((
char
*
)
pcDataWithoutAdts
-
7
,
iDataLen
+
7
,
uiStamp
,
7
));
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
((
char
*
)
pcDataWithoutAdts
-
7
,
iDataLen
+
7
,
uiStamp
,
0
,
7
));
}
else
{
}
else
{
char
*
dataWithAdts
=
new
char
[
iDataLen
+
7
];
char
*
dataWithAdts
=
new
char
[
iDataLen
+
7
];
memcpy
(
dataWithAdts
,
pcAdtsHeader
,
7
);
memcpy
(
dataWithAdts
,
pcAdtsHeader
,
7
);
memcpy
(
dataWithAdts
+
7
,
pcDataWithoutAdts
,
iDataLen
);
memcpy
(
dataWithAdts
+
7
,
pcDataWithoutAdts
,
iDataLen
);
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
(
dataWithAdts
,
iDataLen
+
7
,
uiStamp
,
7
));
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
(
dataWithAdts
,
iDataLen
+
7
,
uiStamp
,
0
,
7
));
delete
[]
dataWithAdts
;
delete
[]
dataWithAdts
;
}
}
}
}
...
...
src/Common/MediaSource.cpp
查看文件 @
46be8a38
...
@@ -276,7 +276,7 @@ MediaSource::Ptr MediaSource::find(const string &schema, const string &vhost_tmp
...
@@ -276,7 +276,7 @@ MediaSource::Ptr MediaSource::find(const string &schema, const string &vhost_tmp
if
(
!
ret
&&
bMake
){
if
(
!
ret
&&
bMake
){
//未查找媒体源,则创建一个
//未查找媒体源,则创建一个
ret
=
MP4Reader
::
onMakeMediaSource
(
schema
,
vhost
,
app
,
id
);
ret
=
onMakeMediaSource
(
schema
,
vhost
,
app
,
id
);
}
}
return
ret
;
return
ret
;
}
}
...
...
src/Extension/AAC.h
查看文件 @
46be8a38
...
@@ -112,7 +112,7 @@ class AACFrameNoCacheAble : public FrameNoCacheAble {
...
@@ -112,7 +112,7 @@ class AACFrameNoCacheAble : public FrameNoCacheAble {
public
:
public
:
typedef
std
::
shared_ptr
<
AACFrameNoCacheAble
>
Ptr
;
typedef
std
::
shared_ptr
<
AACFrameNoCacheAble
>
Ptr
;
AACFrameNoCacheAble
(
char
*
ptr
,
uint32_t
size
,
uint32_t
dts
,
int
prefixeSize
=
7
){
AACFrameNoCacheAble
(
char
*
ptr
,
uint32_t
size
,
uint32_t
dts
,
uint32_t
pts
=
0
,
int
prefixeSize
=
7
){
_ptr
=
ptr
;
_ptr
=
ptr
;
_size
=
size
;
_size
=
size
;
_dts
=
dts
;
_dts
=
dts
;
...
...
src/Extension/H265.h
查看文件 @
46be8a38
...
@@ -268,7 +268,7 @@ public:
...
@@ -268,7 +268,7 @@ public:
*/
*/
void
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
{
void
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
{
int
type
=
H265_TYPE
(
*
((
uint8_t
*
)
frame
->
data
()
+
frame
->
prefixSize
()));
int
type
=
H265_TYPE
(
*
((
uint8_t
*
)
frame
->
data
()
+
frame
->
prefixSize
()));
if
(
type
==
H265Frame
::
NAL_VPS
){
if
(
frame
->
configFrame
()
){
bool
first_frame
=
true
;
bool
first_frame
=
true
;
splitH264
(
frame
->
data
()
+
frame
->
prefixSize
(),
splitH264
(
frame
->
data
()
+
frame
->
prefixSize
(),
frame
->
size
()
-
frame
->
prefixSize
(),
frame
->
size
()
-
frame
->
prefixSize
(),
...
...
src/Player/PlayerProxy.cpp
查看文件 @
46be8a38
...
@@ -215,7 +215,7 @@ public:
...
@@ -215,7 +215,7 @@ public:
auto
iAudioIndex
=
frame
->
dts
()
/
MUTE_ADTS_DATA_MS
;
auto
iAudioIndex
=
frame
->
dts
()
/
MUTE_ADTS_DATA_MS
;
if
(
_iAudioIndex
!=
iAudioIndex
){
if
(
_iAudioIndex
!=
iAudioIndex
){
_iAudioIndex
=
iAudioIndex
;
_iAudioIndex
=
iAudioIndex
;
auto
aacFrame
=
std
::
make_shared
<
AACFrameCacheAble
>
((
char
*
)
MUTE_ADTS_DATA
,
MUTE_ADTS_DATA_LEN
,
_iAudioIndex
*
MUTE_ADTS_DATA_MS
);
auto
aacFrame
=
std
::
make_shared
<
AACFrameCacheAble
>
((
char
*
)
MUTE_ADTS_DATA
,
MUTE_ADTS_DATA_LEN
,
_iAudioIndex
*
MUTE_ADTS_DATA_MS
,
0
);
FrameDispatcher
::
inputFrame
(
aacFrame
);
FrameDispatcher
::
inputFrame
(
aacFrame
);
}
}
}
}
...
...
src/Record/MP4Muxer.cpp
查看文件 @
46be8a38
...
@@ -24,53 +24,35 @@
...
@@ -24,53 +24,35 @@
* SOFTWARE.
* SOFTWARE.
*/
*/
#ifdef ENABLE_MP4RECORD
#ifdef ENABLE_MP4
#include "MP4Muxer.h"
#include "MP4Muxer.h"
#include "Util/File.h"
#include "Util/File.h"
#include "Common/config.h"
namespace
mediakit
{
namespace
mediakit
{
#if defined(_WIN32) || defined(_WIN64)
MP4Muxer
::
MP4Muxer
(
const
char
*
file
)
{
#define fseek64 _fseeki64
_file_name
=
file
;
#define ftell64 _ftelli64
openMP4
();
#else
}
#define fseek64 fseek
#define ftell64 ftell
#endif
void
MP4MuxerBase
::
init
(
int
flags
)
{
MP4Muxer
::~
MP4Muxer
()
{
static
struct
mov_buffer_t
s_io
=
{
closeMP4
();
[](
void
*
ctx
,
void
*
data
,
uint64_t
bytes
)
{
}
MP4MuxerBase
*
thiz
=
(
MP4MuxerBase
*
)
ctx
;
return
thiz
->
onRead
(
data
,
bytes
);
void
MP4Muxer
::
openMP4
(){
},
closeMP4
();
[](
void
*
ctx
,
const
void
*
data
,
uint64_t
bytes
){
openFile
(
_file_name
.
data
(),
"wb+"
);
MP4MuxerBase
*
thiz
=
(
MP4MuxerBase
*
)
ctx
;
_mov_writter
=
createWriter
();
return
thiz
->
onWrite
(
data
,
bytes
);
}
},
void
MP4Muxer
::
closeMP4
(){
[](
void
*
ctx
,
uint64_t
offset
)
{
_mov_writter
=
nullptr
;
MP4MuxerBase
*
thiz
=
(
MP4MuxerBase
*
)
ctx
;
closeFile
();
return
thiz
->
onSeek
(
offset
);
},
[](
void
*
ctx
){
MP4MuxerBase
*
thiz
=
(
MP4MuxerBase
*
)
ctx
;
return
thiz
->
onTell
();
}
};
_mov_writter
.
reset
(
mov_writer_create
(
&
s_io
,
this
,
flags
),[](
mov_writer_t
*
ptr
){
if
(
ptr
){
mov_writer_destroy
(
ptr
);
}
});
}
}
///////////////////////////////////
void
MP4Muxer
::
resetTracks
()
{
void
MP4Muxer
::
resetTracks
()
{
_codec_to_trackid
.
clear
();
_codec_to_trackid
.
clear
();
_started
=
false
;
_started
=
false
;
_have_video
=
false
;
_have_video
=
false
;
openMP4
();
}
}
void
MP4Muxer
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
void
MP4Muxer
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
...
@@ -263,70 +245,5 @@ void MP4Muxer::addTrack(const Track::Ptr &track) {
...
@@ -263,70 +245,5 @@ void MP4Muxer::addTrack(const Track::Ptr &track) {
}
}
}
}
MP4MuxerFile
::
MP4MuxerFile
(
const
char
*
file
){
_file_name
=
file
;
openFile
(
file
);
}
void
MP4MuxerFile
::
openFile
(
const
char
*
file
)
{
//创建文件
auto
fp
=
File
::
createfile_file
(
file
,
"wb+"
);
if
(
!
fp
){
throw
std
::
runtime_error
(
string
(
"打开文件失败:"
)
+
file
);
}
GET_CONFIG
(
uint32_t
,
mp4BufSize
,
Record
::
kFileBufSize
);
//新建文件io缓存
std
::
shared_ptr
<
char
>
file_buf
(
new
char
[
mp4BufSize
],[](
char
*
ptr
){
if
(
ptr
){
delete
[]
ptr
;
}
});
if
(
file_buf
){
//设置文件io缓存
setvbuf
(
fp
,
file_buf
.
get
(),
_IOFBF
,
mp4BufSize
);
}
//创建智能指针
_file
.
reset
(
fp
,[
file_buf
](
FILE
*
fp
)
{
fclose
(
fp
);
});
GET_CONFIG
(
bool
,
mp4FastStart
,
Record
::
kFastStart
);
init
(
mp4FastStart
?
MOV_FLAG_FASTSTART
:
0
);
}
MP4MuxerFile
::~
MP4MuxerFile
()
{
_mov_writter
=
nullptr
;
}
int
MP4MuxerFile
::
onRead
(
void
*
data
,
uint64_t
bytes
)
{
if
(
bytes
==
fread
(
data
,
1
,
bytes
,
_file
.
get
())){
return
0
;
}
return
0
!=
ferror
(
_file
.
get
())
?
ferror
(
_file
.
get
())
:
-
1
/*EOF*/
;
}
int
MP4MuxerFile
::
onWrite
(
const
void
*
data
,
uint64_t
bytes
)
{
return
bytes
==
fwrite
(
data
,
1
,
bytes
,
_file
.
get
())
?
0
:
ferror
(
_file
.
get
());
}
int
MP4MuxerFile
::
onSeek
(
uint64_t
offset
)
{
return
fseek64
(
_file
.
get
(),
offset
,
SEEK_SET
);
}
uint64_t
MP4MuxerFile
::
onTell
()
{
return
ftell64
(
_file
.
get
());
}
void
MP4MuxerFile
::
resetTracks
(){
MP4Muxer
::
resetTracks
();
openFile
(
_file_name
.
data
());
}
}
//namespace mediakit
}
//namespace mediakit
#endif//#ifdef ENABLE_MP4
#endif//#ifdef ENABLE_MP4RECORD
src/Record/MP4Muxer.h
查看文件 @
46be8a38
...
@@ -27,40 +27,21 @@
...
@@ -27,40 +27,21 @@
#ifndef ZLMEDIAKIT_MP4MUXER_H
#ifndef ZLMEDIAKIT_MP4MUXER_H
#define ZLMEDIAKIT_MP4MUXER_H
#define ZLMEDIAKIT_MP4MUXER_H
#ifdef ENABLE_MP4
RECORD
#ifdef ENABLE_MP4
#include "Common/MediaSink.h"
#include "Common/MediaSink.h"
#include "mov-writer.h"
#include "mpeg4-hevc.h"
#include "mpeg4-avc.h"
#include "mpeg4-aac.h"
#include "mov-buffer.h"
#include "mov-format.h"
#include "Extension/AAC.h"
#include "Extension/AAC.h"
#include "Extension/H264.h"
#include "Extension/H264.h"
#include "Extension/H265.h"
#include "Extension/H265.h"
#include "Common/Stamp.h"
#include "Common/Stamp.h"
#include "MP4.h"
namespace
mediakit
{
namespace
mediakit
{
class
MP4Muxer
Bas
e
{
class
MP4Muxer
:
public
MediaSinkInterface
,
public
MP4Fil
e
{
public
:
public
:
MP4MuxerBase
()
=
default
;
MP4Muxer
(
const
char
*
file
);
virtual
~
MP4MuxerBase
()
=
default
;
~
MP4Muxer
()
override
;
protected
:
virtual
int
onRead
(
void
*
data
,
uint64_t
bytes
)
=
0
;
virtual
int
onWrite
(
const
void
*
data
,
uint64_t
bytes
)
=
0
;
virtual
int
onSeek
(
uint64_t
offset
)
=
0
;
virtual
uint64_t
onTell
()
=
0
;
void
init
(
int
flags
);
protected
:
std
::
shared_ptr
<
mov_writer_t
>
_mov_writter
;
};
class
MP4Muxer
:
public
MediaSinkInterface
,
public
MP4MuxerBase
{
public
:
MP4Muxer
()
=
default
;
~
MP4Muxer
()
override
=
default
;
/**
/**
* 添加已经ready状态的track
* 添加已经ready状态的track
...
@@ -75,6 +56,11 @@ public:
...
@@ -75,6 +56,11 @@ public:
* 重置所有track
* 重置所有track
*/
*/
void
resetTracks
()
override
;
void
resetTracks
()
override
;
private
:
void
openMP4
();
void
closeMP4
();
private
:
private
:
struct
track_info
{
struct
track_info
{
int
track_id
=
-
1
;
int
track_id
=
-
1
;
...
@@ -84,28 +70,10 @@ private:
...
@@ -84,28 +70,10 @@ private:
List
<
Frame
::
Ptr
>
_frameCached
;
List
<
Frame
::
Ptr
>
_frameCached
;
bool
_started
=
false
;
bool
_started
=
false
;
bool
_have_video
=
false
;
bool
_have_video
=
false
;
};
MP4File
::
Writer
_mov_writter
;
class
MP4MuxerFile
:
public
MP4Muxer
{
public
:
typedef
std
::
shared_ptr
<
MP4MuxerFile
>
Ptr
;
MP4MuxerFile
(
const
char
*
file
);
~
MP4MuxerFile
();
void
resetTracks
()
override
;
protected
:
int
onRead
(
void
*
data
,
uint64_t
bytes
)
override
;
int
onWrite
(
const
void
*
data
,
uint64_t
bytes
)
override
;
int
onSeek
(
uint64_t
offset
)
override
;
uint64_t
onTell
()
override
;
void
openFile
(
const
char
*
file
);
private
:
std
::
shared_ptr
<
FILE
>
_file
;
string
_file_name
;
string
_file_name
;
};
};
}
//namespace mediakit
}
//namespace mediakit
#endif//#ifdef ENABLE_MP4
#endif//#ifdef ENABLE_MP4RECORD
#endif //ZLMEDIAKIT_MP4MUXER_H
#endif //ZLMEDIAKIT_MP4MUXER_H
src/Record/MP4Reader.cpp
查看文件 @
46be8a38
...
@@ -24,20 +24,13 @@
...
@@ -24,20 +24,13 @@
* SOFTWARE.
* SOFTWARE.
*/
*/
#ifdef ENABLE_MP4
#include "MP4Reader.h"
#include "MP4Reader.h"
#include "Common/config.h"
#include "Common/config.h"
#include "Util/mini.h"
#include "Util/File.h"
#include "Http/HttpSession.h"
#include "Extension/AAC.h"
#include "Extension/H264.h"
#include "Thread/WorkThreadPool.h"
#include "Thread/WorkThreadPool.h"
using
namespace
toolkit
;
using
namespace
toolkit
;
namespace
mediakit
{
namespace
mediakit
{
#ifdef ENABLE_MP4V2
MP4Reader
::
MP4Reader
(
const
string
&
strVhost
,
const
string
&
strApp
,
const
string
&
strId
,
const
string
&
filePath
)
{
MP4Reader
::
MP4Reader
(
const
string
&
strVhost
,
const
string
&
strApp
,
const
string
&
strId
,
const
string
&
filePath
)
{
_poller
=
WorkThreadPool
::
Instance
().
getPoller
();
_poller
=
WorkThreadPool
::
Instance
().
getPoller
();
auto
strFileName
=
filePath
;
auto
strFileName
=
filePath
;
...
@@ -52,314 +45,154 @@ MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &
...
@@ -52,314 +45,154 @@ MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &
strFileName
=
File
::
absolutePath
(
strFileName
,
recordPath
);
strFileName
=
File
::
absolutePath
(
strFileName
,
recordPath
);
}
}
_hMP4File
=
MP4Read
(
strFileName
.
data
());
_demuxer
=
std
::
make_shared
<
MP4Demuxer
>
(
strFileName
.
data
());
if
(
_hMP4File
==
MP4_INVALID_FILE_HANDLE
){
_mediaMuxer
.
reset
(
new
MultiMediaSourceMuxer
(
strVhost
,
strApp
,
strId
,
_demuxer
->
getDurationMS
()
/
1000.0
,
true
,
true
,
false
,
false
));
throw
runtime_error
(
StrPrinter
<<
"打开MP4文件失败:"
<<
strFileName
<<
endl
);
for
(
auto
&
track
:
_demuxer
->
getTracks
(
false
)){
}
_mediaMuxer
->
addTrack
(
track
);
_video_trId
=
MP4FindTrackId
(
_hMP4File
,
0
,
MP4_VIDEO_TRACK_TYPE
,
0
);
if
(
track
->
getTrackType
()
==
TrackVideo
){
if
(
_video_trId
!=
MP4_INVALID_TRACK_ID
){
_have_video
=
true
;
if
(
strcmp
(
MP4GetTrackMediaDataName
(
_hMP4File
,
_video_trId
),
"avc1"
)
==
0
){
auto
_video_timescale
=
MP4GetTrackTimeScale
(
_hMP4File
,
_video_trId
);
auto
_video_duration
=
MP4GetTrackDuration
(
_hMP4File
,
_video_trId
);
_video_num_samples
=
MP4GetTrackNumberOfSamples
(
_hMP4File
,
_video_trId
);
_video_sample_max_size
=
MP4GetTrackMaxSampleSize
(
_hMP4File
,
_video_trId
);
_video_width
=
MP4GetTrackVideoWidth
(
_hMP4File
,
_video_trId
);
_video_height
=
MP4GetTrackVideoHeight
(
_hMP4File
,
_video_trId
);
_video_framerate
=
MP4GetTrackVideoFrameRate
(
_hMP4File
,
_video_trId
);
_pcVideoSample
=
std
::
shared_ptr
<
uint8_t
>
(
new
uint8_t
[
_video_sample_max_size
],[](
uint8_t
*
ptr
){
delete
[]
ptr
;
});
uint8_t
**
seqheader
;
uint8_t
**
pictheader
;
uint32_t
*
pictheadersize
;
uint32_t
*
seqheadersize
;
uint32_t
ix
;
if
(
MP4GetTrackH264SeqPictHeaders
(
_hMP4File
,
_video_trId
,
&
seqheader
,
&
seqheadersize
,
&
pictheader
,
&
pictheadersize
)){
for
(
ix
=
0
;
seqheadersize
[
ix
]
!=
0
;
ix
++
)
{
_strSps
.
assign
((
char
*
)(
seqheader
[
ix
]),
seqheadersize
[
ix
]);
float
framerate
;
getAVCInfo
(
_strSps
,
(
int
&
)
_video_width
,
(
int
&
)
_video_height
,
framerate
);
_video_framerate
=
framerate
;
_strSps
=
string
(
"\x0\x0\x0\x1"
,
4
)
+
_strSps
;
MP4Free
(
seqheader
[
ix
]);
}
MP4Free
(
seqheader
);
MP4Free
(
seqheadersize
);
for
(
ix
=
0
;
pictheadersize
[
ix
]
!=
0
;
ix
++
)
{
_strPps
.
assign
(
"\x0\x0\x0\x1"
,
4
);
_strPps
.
append
((
char
*
)(
pictheader
[
ix
]),
pictheadersize
[
ix
]);
MP4Free
(
pictheader
[
ix
]);
}
MP4Free
(
pictheader
);
MP4Free
(
pictheadersize
);
}
_video_ms
=
1000.0
*
_video_duration
/
_video_timescale
;
/*InfoL << "\r\n"
<< _video_ms << "\r\n"
<< _video_num_samples << "\r\n"
<< _video_framerate << "\r\n"
<< _video_width << "\r\n"
<< _video_height << "\r\n";*/
}
else
{
//如果不是h264,则忽略
_video_trId
=
MP4_INVALID_TRACK_ID
;
}
}
}
}
//添加完毕所有track,防止单track情况下最大等待3秒
_mediaMuxer
->
addTrackCompleted
();
}
bool
MP4Reader
::
readSample
()
{
_audio_trId
=
MP4FindTrackId
(
_hMP4File
,
0
,
MP4_AUDIO_TRACK_TYPE
,
0
);
bool
eof
=
false
;
if
(
_audio_trId
!=
MP4_INVALID_TRACK_ID
)
{
while
(
!
eof
)
{
if
(
strcmp
(
MP4GetTrackMediaDataName
(
_hMP4File
,
_audio_trId
),
"mp4a"
)
==
0
)
{
auto
frame
=
_demuxer
->
readFrame
(
false
,
&
eof
);
_audio_sample_rate
=
MP4GetTrackTimeScale
(
_hMP4File
,
_audio_trId
);
if
(
!
frame
)
{
auto
_audio_duration
=
MP4GetTrackDuration
(
_hMP4File
,
_audio_trId
);
break
;
_audio_num_samples
=
MP4GetTrackNumberOfSamples
(
_hMP4File
,
_audio_trId
);
_audio_num_channels
=
MP4GetTrackAudioChannels
(
_hMP4File
,
_audio_trId
);
_audio_sample_max_size
=
MP4GetTrackMaxSampleSize
(
_hMP4File
,
_audio_trId
);
uint8_t
*
ppConfig
;
uint32_t
pConfigSize
;
if
(
MP4GetTrackESConfiguration
(
_hMP4File
,
_audio_trId
,
&
ppConfig
,
&
pConfigSize
)){
_strAacCfg
.
assign
((
char
*
)
ppConfig
,
pConfigSize
);
makeAdtsHeader
(
_strAacCfg
,
_adts
);
writeAdtsHeader
(
_adts
,
_adts
.
buffer
);
getAACInfo
(
_adts
,
(
int
&
)
_audio_sample_rate
,
(
int
&
)
_audio_num_channels
);
MP4Free
(
ppConfig
);
}
_audio_ms
=
1000.0
*
_audio_duration
/
_audio_sample_rate
;
/*InfoL << "\r\n"
<< _audio_ms << "\r\n"
<< _audio_num_samples << "\r\n"
<< _audio_num_channels << "\r\n"
<< _audio_sample_rate << "\r\n";*/
}
else
{
_audio_trId
=
MP4_INVALID_TRACK_ID
;
}
}
}
if
(
_audio_trId
==
MP4_INVALID_TRACK_ID
&&
_video_trId
==
MP4_INVALID_TRACK_ID
){
_mediaMuxer
->
inputFrame
(
frame
);
MP4Close
(
_hMP4File
);
if
(
frame
->
dts
()
>
nextStampForStop
())
{
_hMP4File
=
MP4_INVALID_FILE_HANDLE
;
break
;
throw
runtime_error
(
StrPrinter
<<
"该MP4文件音视频格式不支持:"
<<
strFileName
<<
endl
);
}
}
_iDuration
=
MAX
(
_video_ms
,
_audio_ms
);
_mediaMuxer
.
reset
(
new
MultiMediaSourceMuxer
(
strVhost
,
strApp
,
strId
,
_iDuration
/
1000.0
,
true
,
true
,
false
,
false
));
if
(
_audio_trId
!=
MP4_INVALID_TRACK_ID
)
{
AACTrack
::
Ptr
track
=
std
::
make_shared
<
AACTrack
>
(
_strAacCfg
);
_mediaMuxer
->
addTrack
(
track
);
}
}
if
(
_video_trId
!=
MP4_INVALID_TRACK_ID
)
{
if
(
!
eof
&&
_mediaMuxer
->
totalReaderCount
()
>
0
)
{
H264Track
::
Ptr
track
=
std
::
make_shared
<
H264Track
>
(
_strSps
,
_strPps
);
//文件未看完且观看者大于0个
_
mediaMuxer
->
addTrack
(
track
);
_
alive
.
resetTime
(
);
}
}
//添加完毕所有track,防止单track情况下最大等待3秒
//重头开始循环读取
_mediaMuxer
->
addTrackCompleted
();
GET_CONFIG
(
bool
,
fileRepeat
,
Record
::
kFileRepeat
);
}
if
(
eof
&&
fileRepeat
){
//文件看完了,且需要从头开始看
seekTo
(
0
);
MP4Reader
::~
MP4Reader
()
{
if
(
_hMP4File
!=
MP4_INVALID_FILE_HANDLE
)
{
MP4Close
(
_hMP4File
);
_hMP4File
=
MP4_INVALID_FILE_HANDLE
;
}
}
//读取mp4完毕后10秒才销毁对象
return
_alive
.
elapsedTime
()
<
10
*
1000
;
}
}
void
MP4Reader
::
startReadMP4
()
{
void
MP4Reader
::
startReadMP4
()
{
GET_CONFIG
(
uint32_t
,
sampleMS
,
Record
::
kSampleMS
);
auto
strongSelf
=
shared_from_this
();
auto
strongSelf
=
shared_from_this
();
GET_CONFIG
(
uint32_t
,
sampleMS
,
Record
::
kSampleMS
);
_mediaMuxer
->
setListener
(
strongSelf
);
_timer
=
std
::
make_shared
<
Timer
>
(
sampleMS
/
1000.0
f
,[
strongSelf
](){
//先获取关键帧
return
strongSelf
->
readSample
(
0
,
false
);
seekTo
(
0
);
//设置下次读取停止事件
setNextStampForStop
(
_seek_to
+
sampleMS
);
//读sampleMS毫秒的数据用于产生MediaSource
readSample
();
//启动定时器
_timer
=
std
::
make_shared
<
Timer
>
(
sampleMS
/
1000.0
f
,
[
strongSelf
]()
{
lock_guard
<
recursive_mutex
>
lck
(
strongSelf
->
_mtx
);
return
strongSelf
->
readSample
();
},
_poller
);
},
_poller
);
//先读sampleMS毫秒的数据用于产生MediaSouce
readSample
(
sampleMS
,
false
);
_mediaMuxer
->
setListener
(
strongSelf
);
}
}
bool
MP4Reader
::
seekTo
(
MediaSource
&
sender
,
uint32_t
ui32Stamp
){
seek
(
ui32Stamp
);
uint32_t
MP4Reader
::
nextStampForStop
()
{
return
true
;
return
_seek_to
+
_seek_ticker
.
elapsedTime
()
;
}
}
bool
MP4Reader
::
close
(
MediaSource
&
sender
,
bool
force
){
if
(
!
_mediaMuxer
||
(
!
force
&&
_mediaMuxer
->
totalReaderCount
())){
void
MP4Reader
::
setNextStampForStop
(
uint32_t
ui32Stamp
){
return
false
;
_seek_to
=
ui32Stamp
;
}
_seek_ticker
.
resetTime
();
_timer
.
reset
();
_alive
.
resetTime
();
WarnL
<<
sender
.
getSchema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
return
true
;
}
}
int
MP4Reader
::
totalReaderCount
(
MediaSource
&
sender
)
{
bool
MP4Reader
::
seekTo
(
MediaSource
&
sender
,
uint32_t
ui32Stamp
)
{
return
_mediaMuxer
?
_mediaMuxer
->
totalReaderCount
()
:
sender
.
readerCount
(
);
return
seekTo
(
ui32Stamp
);
}
}
bool
MP4Reader
::
readSample
(
int
iTimeInc
,
bool
justSeekSyncFrame
)
{
bool
MP4Reader
::
seekTo
(
uint32_t
ui32Stamp
){
TimeTicker
();
lock_guard
<
recursive_mutex
>
lck
(
_mtx
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx
);
auto
bFlag0
=
readVideoSample
(
iTimeInc
,
justSeekSyncFrame
);
//数据没读完
if
(
ui32Stamp
>
_demuxer
->
getDurationMS
())
{
auto
bFlag1
=
readAudioSample
(
iTimeInc
,
justSeekSyncFrame
);
//数据没读完
//超过文件长度
auto
bFlag2
=
_mediaMuxer
->
totalReaderCount
()
>
0
;
//读取者大于0
return
false
;
if
((
bFlag0
||
bFlag1
)
&&
bFlag2
){
_alive
.
resetTime
();
}
//重头开始循环读取
GET_CONFIG
(
bool
,
fileRepeat
,
Record
::
kFileRepeat
);
if
(
fileRepeat
&&
!
bFlag0
&&
!
bFlag1
)
{
seek
(
0
);
}
}
//DebugL << "alive ...";
auto
stamp
=
_demuxer
->
seekTo
(
ui32Stamp
);
//3秒延时关闭
if
(
stamp
==
-
1
){
return
_alive
.
elapsedTime
()
<
3
*
1000
;
//seek失败
}
return
false
;
inline
bool
MP4Reader
::
readVideoSample
(
int
iTimeInc
,
bool
justSeekSyncFrame
)
{
if
(
_video_trId
!=
MP4_INVALID_TRACK_ID
)
{
auto
iNextSample
=
getVideoSampleId
(
iTimeInc
);
MP4SampleId
iIdx
=
_video_current
;
for
(;
iIdx
<
iNextSample
;
iIdx
++
)
{
uint8_t
*
pBytes
=
_pcVideoSample
.
get
();
uint32_t
numBytes
=
_video_sample_max_size
;
MP4Duration
pRenderingOffset
;
if
(
MP4ReadSample
(
_hMP4File
,
_video_trId
,
iIdx
+
1
,
&
pBytes
,
&
numBytes
,
NULL
,
NULL
,
&
pRenderingOffset
,
&
_bSyncSample
)){
if
(
!
justSeekSyncFrame
)
{
uint32_t
dts
=
(
double
)
_video_ms
*
iIdx
/
_video_num_samples
;
uint32_t
pts
=
dts
+
pRenderingOffset
/
90
;
uint32_t
iOffset
=
0
;
while
(
iOffset
<
numBytes
)
{
uint32_t
iFrameLen
;
memcpy
(
&
iFrameLen
,
pBytes
+
iOffset
,
4
);
iFrameLen
=
ntohl
(
iFrameLen
);
if
(
iFrameLen
+
iOffset
+
4
>
numBytes
){
break
;
}
}
memcpy
(
pBytes
+
iOffset
,
"\x0\x0\x0\x1"
,
4
);
InfoL
<<
stamp
;
writeH264
(
pBytes
+
iOffset
,
iFrameLen
+
4
,
dts
,
pts
);
//设置当前时间戳
iOffset
+=
(
iFrameLen
+
4
);
setNextStampForStop
(
stamp
);
if
(
!
_have_video
){
//没有视频,不需要搜索关键帧
return
true
;
}
}
}
else
if
(
_bSyncSample
){
//搜索到下一帧关键帧
bool
eof
=
false
;
while
(
!
eof
)
{
auto
frame
=
_demuxer
->
readFrame
(
false
,
&
eof
);
if
(
!
frame
){
break
;
break
;
}
}
}
else
{
if
(
frame
->
keyFrame
()
||
frame
->
configFrame
()){
ErrorL
<<
"读取视频失败:"
<<
iIdx
+
1
;
//定位到key帧
}
_mediaMuxer
->
inputFrame
(
frame
);
setNextStampForStop
(
frame
->
dts
());
return
true
;
}
}
_video_current
=
iIdx
;
return
_video_current
<
_video_num_samples
;
}
}
return
false
;
return
false
;
}
}
inline
bool
MP4Reader
::
readAudioSample
(
int
iTimeInc
,
bool
justSeekSyncFrame
)
{
bool
MP4Reader
::
close
(
MediaSource
&
sender
,
bool
force
){
if
(
_audio_trId
!=
MP4_INVALID_TRACK_ID
)
{
if
(
!
_mediaMuxer
||
(
!
force
&&
_mediaMuxer
->
totalReaderCount
())){
auto
iNextSample
=
getAudioSampleId
(
iTimeInc
);
for
(
auto
i
=
_audio_current
;
i
<
iNextSample
;
i
++
)
{
uint32_t
numBytes
=
_audio_sample_max_size
;
uint8_t
*
pBytes
=
_adts
.
buffer
+
7
;
if
(
MP4ReadSample
(
_hMP4File
,
_audio_trId
,
i
+
1
,
&
pBytes
,
&
numBytes
)){
if
(
!
justSeekSyncFrame
)
{
uint32_t
dts
=
(
double
)
_audio_ms
*
i
/
_audio_num_samples
;
_adts
.
aac_frame_length
=
7
+
numBytes
;
writeAdtsHeader
(
_adts
,
_adts
.
buffer
);
writeAAC
(
_adts
.
buffer
,
_adts
.
aac_frame_length
,
dts
);
}
}
else
{
ErrorL
<<
"读取音频失败:"
<<
i
+
1
;
}
}
_audio_current
=
iNextSample
;
return
_audio_current
<
_audio_num_samples
;
}
return
false
;
return
false
;
}
inline
void
MP4Reader
::
writeH264
(
uint8_t
*
pucData
,
int
iLen
,
uint32_t
dts
,
uint32_t
pts
)
{
_mediaMuxer
->
inputFrame
(
std
::
make_shared
<
H264FrameNoCacheAble
>
((
char
*
)
pucData
,
iLen
,
dts
,
pts
));
}
inline
void
MP4Reader
::
writeAAC
(
uint8_t
*
pucData
,
int
iLen
,
uint32_t
uiStamp
)
{
_mediaMuxer
->
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
((
char
*
)
pucData
,
iLen
,
uiStamp
));
}
inline
MP4SampleId
MP4Reader
::
getVideoSampleId
(
int
iTimeInc
)
{
MP4SampleId
video_current
=
(
double
)
_video_num_samples
*
(
_iSeekTime
+
_ticker
.
elapsedTime
()
+
iTimeInc
)
/
_video_ms
;
video_current
=
MAX
(
0
,
MIN
(
_video_num_samples
,
video_current
));
return
video_current
;
}
inline
MP4SampleId
MP4Reader
::
getAudioSampleId
(
int
iTimeInc
)
{
MP4SampleId
audio_current
=
(
double
)
_audio_num_samples
*
(
_iSeekTime
+
_ticker
.
elapsedTime
()
+
iTimeInc
)
/
_audio_ms
;
audio_current
=
MAX
(
0
,
MIN
(
_audio_num_samples
,
audio_current
));
return
audio_current
;
}
inline
void
MP4Reader
::
setSeekTime
(
uint32_t
iSeekTime
){
_iSeekTime
=
MAX
(
0
,
MIN
(
iSeekTime
,
_iDuration
));
_ticker
.
resetTime
();
if
(
_audio_trId
!=
MP4_INVALID_TRACK_ID
)
{
_audio_current
=
getAudioSampleId
();
}
if
(
_video_trId
!=
MP4_INVALID_TRACK_ID
)
{
_video_current
=
getVideoSampleId
();
}
}
inline
uint32_t
MP4Reader
::
getVideoCurrentTime
(){
return
(
double
)
_video_current
*
_video_ms
/
_video_num_samples
;
}
void
MP4Reader
::
seek
(
uint32_t
iSeekTime
,
bool
bReStart
){
lock_guard
<
recursive_mutex
>
lck
(
_mtx
);
if
(
iSeekTime
==
0
||
_video_trId
==
MP4_INVALID_TRACK_ID
){
setSeekTime
(
iSeekTime
);
}
else
{
setSeekTime
(
iSeekTime
-
5000
);
//在之后的10秒查找关键帧
readVideoSample
(
10000
,
true
);
if
(
_bSyncSample
)
{
//找到关键帧
auto
iIdr
=
_video_current
;
setSeekTime
(
getVideoCurrentTime
());
_video_current
=
iIdr
;
}
else
{
//未找到关键帧
setSeekTime
(
iSeekTime
);
}
}
}
_mediaMuxer
->
setTimeStamp
(
_iSeekTime
);
if
(
bReStart
){
_timer
.
reset
();
_timer
.
reset
();
startReadMP4
()
;
WarnL
<<
sender
.
getSchema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
}
return
true
;
}
}
#endif //ENABLE_MP4V2
int
MP4Reader
::
totalReaderCount
(
MediaSource
&
sender
)
{
return
_mediaMuxer
?
_mediaMuxer
->
totalReaderCount
()
:
sender
.
readerCount
();
}
}
/* namespace mediakit */
#endif //ENABLE_MP4
MediaSource
::
Ptr
MP4Reader
::
onMakeMediaSource
(
const
string
&
strSchema
,
namespace
mediakit
{
MediaSource
::
Ptr
onMakeMediaSource
(
const
string
&
strSchema
,
const
string
&
strVhost
,
const
string
&
strVhost
,
const
string
&
strApp
,
const
string
&
strApp
,
const
string
&
strId
,
const
string
&
strId
,
const
string
&
filePath
,
const
string
&
filePath
,
bool
checkApp
)
{
bool
checkApp
)
{
#ifdef ENABLE_MP4
V2
#ifdef ENABLE_MP4
GET_CONFIG
(
string
,
appName
,
Record
::
kAppName
);
GET_CONFIG
(
string
,
appName
,
Record
::
kAppName
);
if
(
checkApp
&&
strApp
!=
appName
)
{
if
(
checkApp
&&
strApp
!=
appName
)
{
return
nullptr
;
return
nullptr
;
}
}
try
{
try
{
MP4Reader
::
Ptr
pReader
(
new
MP4Reader
(
strVhost
,
strApp
,
strId
,
filePath
));
MP4Reader
::
Ptr
pReader
(
new
MP4Reader
(
strVhost
,
strApp
,
strId
,
filePath
));
pReader
->
startReadMP4
();
pReader
->
startReadMP4
();
return
MediaSource
::
find
(
strSchema
,
strVhost
,
strApp
,
strId
,
false
);
return
MediaSource
::
find
(
strSchema
,
strVhost
,
strApp
,
strId
,
false
);
}
catch
(
std
::
exception
&
ex
)
{
}
catch
(
std
::
exception
&
ex
)
{
WarnL
<<
ex
.
what
();
WarnL
<<
ex
.
what
();
return
nullptr
;
return
nullptr
;
}
}
#else
#else
return
nullptr
;
return
nullptr
;
#endif //ENABLE_MP4
V2
#endif //ENABLE_MP4
}
}
}
//namespace mediakit
}
/* namespace mediakit */
src/Record/MP4Reader.h
查看文件 @
46be8a38
...
@@ -26,21 +26,16 @@
...
@@ -26,21 +26,16 @@
#ifndef SRC_MEDIAFILE_MEDIAREADER_H_
#ifndef SRC_MEDIAFILE_MEDIAREADER_H_
#define SRC_MEDIAFILE_MEDIAREADER_H_
#define SRC_MEDIAFILE_MEDIAREADER_H_
#ifdef ENABLE_MP4
#include "MP4Demuxer.h"
#include "Common/MultiMediaSourceMuxer.h"
#include "Common/MultiMediaSourceMuxer.h"
#include "Extension/AAC.h"
#ifdef ENABLE_MP4V2
#include <mp4v2/mp4v2.h>
#endif //ENABLE_MP4V2
using
namespace
toolkit
;
using
namespace
toolkit
;
namespace
mediakit
{
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
:
public
:
typedef
std
::
shared_ptr
<
MP4Reader
>
Ptr
;
typedef
std
::
shared_ptr
<
MP4Reader
>
Ptr
;
virtual
~
MP4Reader
();
virtual
~
MP4Reader
()
=
default
;
/**
/**
* 流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource
* 流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource
...
@@ -50,13 +45,40 @@ public:
...
@@ -50,13 +45,40 @@ public:
* @param filePath 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件
* @param filePath 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件
*/
*/
MP4Reader
(
const
string
&
strVhost
,
const
string
&
strApp
,
const
string
&
strId
,
const
string
&
filePath
=
""
);
MP4Reader
(
const
string
&
strVhost
,
const
string
&
strApp
,
const
string
&
strId
,
const
string
&
filePath
=
""
);
/**
/**
* 开始流化MP4文件,需要指出的是,MP4Reader对象一经过调用startReadMP4方法,它的强引用会自持有,
* 开始流化MP4文件,需要指出的是,MP4Reader对象一经过调用startReadMP4方法,它的强引用会自持有,
* 意思是在文件流化结束之前或中断之前,MP4Reader对象是不会被销毁的(不管有没有被外部对象持有)
* 意思是在文件流化结束之前或中断之前,MP4Reader对象是不会被销毁的(不管有没有被外部对象持有)
*/
*/
void
startReadMP4
();
void
startReadMP4
();
private
:
//MediaSourceEvent override
bool
seekTo
(
MediaSource
&
sender
,
uint32_t
ui32Stamp
)
override
;
bool
close
(
MediaSource
&
sender
,
bool
force
)
override
;
int
totalReaderCount
(
MediaSource
&
sender
)
override
;
/**
bool
readSample
();
uint32_t
nextStampForStop
();
void
setNextStampForStop
(
uint32_t
ui32Stamp
);
bool
seekTo
(
uint32_t
ui32Stamp
);
private
:
recursive_mutex
_mtx
;
MultiMediaSourceMuxer
::
Ptr
_mediaMuxer
;
uint32_t
_seek_to
;
Ticker
_seek_ticker
;
Ticker
_alive
;
Timer
::
Ptr
_timer
;
EventPoller
::
Ptr
_poller
;
MP4Demuxer
::
Ptr
_demuxer
;
bool
_have_video
=
false
;
};
}
/* namespace mediakit */
#endif //ENABLE_MP4
namespace
mediakit
{
/**
* 自动生成MP4Reader对象然后查找相关的MediaSource对象
* 自动生成MP4Reader对象然后查找相关的MediaSource对象
* @param strSchema 协议名
* @param strSchema 协议名
* @param strVhost 虚拟主机
* @param strVhost 虚拟主机
...
@@ -66,66 +88,11 @@ public:
...
@@ -66,66 +88,11 @@ public:
* @param checkApp 是否检查app,防止服务器上文件被乱访问
* @param checkApp 是否检查app,防止服务器上文件被乱访问
* @return MediaSource
* @return MediaSource
*/
*/
static
MediaSource
::
Ptr
onMakeMediaSource
(
const
string
&
strSchema
,
MediaSource
::
Ptr
onMakeMediaSource
(
const
string
&
strSchema
,
const
string
&
strVhost
,
const
string
&
strVhost
,
const
string
&
strApp
,
const
string
&
strApp
,
const
string
&
strId
,
const
string
&
strId
,
const
string
&
filePath
=
""
,
const
string
&
filePath
=
""
,
bool
checkApp
=
true
);
bool
checkApp
=
true
);
private
:
//MediaSourceEvent override
bool
seekTo
(
MediaSource
&
sender
,
uint32_t
ui32Stamp
)
override
;
bool
close
(
MediaSource
&
sender
,
bool
force
)
override
;
int
totalReaderCount
(
MediaSource
&
sender
)
override
;
#ifdef ENABLE_MP4V2
void
seek
(
uint32_t
iSeekTime
,
bool
bReStart
=
true
);
inline
void
setSeekTime
(
uint32_t
iSeekTime
);
inline
uint32_t
getVideoCurrentTime
();
inline
MP4SampleId
getVideoSampleId
(
int
iTimeInc
=
0
);
inline
MP4SampleId
getAudioSampleId
(
int
iTimeInc
=
0
);
bool
readSample
(
int
iTimeInc
,
bool
justSeekSyncFrame
);
inline
bool
readVideoSample
(
int
iTimeInc
,
bool
justSeekSyncFrame
);
inline
bool
readAudioSample
(
int
iTimeInc
,
bool
justSeekSyncFrame
);
inline
void
writeH264
(
uint8_t
*
pucData
,
int
iLen
,
uint32_t
dts
,
uint32_t
pts
);
inline
void
writeAAC
(
uint8_t
*
pucData
,
int
iLen
,
uint32_t
uiStamp
);
private
:
MP4FileHandle
_hMP4File
=
MP4_INVALID_FILE_HANDLE
;
MP4TrackId
_video_trId
=
MP4_INVALID_TRACK_ID
;
uint32_t
_video_ms
=
0
;
uint32_t
_video_num_samples
=
0
;
uint32_t
_video_sample_max_size
=
0
;
uint32_t
_video_width
=
0
;
uint32_t
_video_height
=
0
;
uint32_t
_video_framerate
=
0
;
string
_strPps
;
string
_strSps
;
bool
_bSyncSample
=
false
;
MP4TrackId
_audio_trId
=
MP4_INVALID_TRACK_ID
;
uint32_t
_audio_ms
=
0
;
uint32_t
_audio_num_samples
=
0
;
uint32_t
_audio_sample_max_size
=
0
;
uint32_t
_audio_sample_rate
=
0
;
uint32_t
_audio_num_channels
=
0
;
string
_strAacCfg
;
AACFrame
_adts
;
int
_iDuration
=
0
;
MultiMediaSourceMuxer
::
Ptr
_mediaMuxer
;
MP4SampleId
_video_current
=
0
;
MP4SampleId
_audio_current
=
0
;
std
::
shared_ptr
<
uint8_t
>
_pcVideoSample
;
int
_iSeekTime
=
0
;
Ticker
_ticker
;
Ticker
_alive
;
recursive_mutex
_mtx
;
Timer
::
Ptr
_timer
;
EventPoller
::
Ptr
_poller
;
#endif //ENABLE_MP4V2
};
}
/* namespace mediakit */
}
/* namespace mediakit */
#endif
/* SRC_MEDIAFILE_MEDIAREADER_H_ */
#endif
/* SRC_MEDIAFILE_MEDIAREADER_H_ */
src/Record/MP4Recorder.cpp
查看文件 @
46be8a38
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
* SOFTWARE.
* SOFTWARE.
*/
*/
#ifdef ENABLE_MP4
RECORD
#ifdef ENABLE_MP4
#include <ctime>
#include <ctime>
#include <sys/stat.h>
#include <sys/stat.h>
#include "Common/config.h"
#include "Common/config.h"
...
@@ -69,7 +69,7 @@ void MP4Recorder::createFile() {
...
@@ -69,7 +69,7 @@ void MP4Recorder::createFile() {
+
strTime
+
".mp4"
;
+
strTime
+
".mp4"
;
try
{
try
{
_muxer
=
std
::
make_shared
<
MP4Muxer
File
>
(
strFileTmp
.
data
());
_muxer
=
std
::
make_shared
<
MP4Muxer
>
(
strFileTmp
.
data
());
for
(
auto
&
track
:
_tracks
){
for
(
auto
&
track
:
_tracks
){
//添加track
//添加track
_muxer
->
addTrack
(
track
);
_muxer
->
addTrack
(
track
);
...
@@ -91,7 +91,7 @@ void MP4Recorder::asyncClose() {
...
@@ -91,7 +91,7 @@ void MP4Recorder::asyncClose() {
//获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间
//获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间
const_cast
<
MP4Info
&>
(
info
).
ui64TimeLen
=
::
time
(
NULL
)
-
info
.
ui64StartedTime
;
const_cast
<
MP4Info
&>
(
info
).
ui64TimeLen
=
::
time
(
NULL
)
-
info
.
ui64StartedTime
;
//关闭mp4非常耗时,所以要放在后台线程执行
//关闭mp4非常耗时,所以要放在后台线程执行
const_cast
<
MP4Muxer
File
::
Ptr
&>
(
muxer
).
reset
();
const_cast
<
MP4Muxer
::
Ptr
&>
(
muxer
).
reset
();
//临时文件名改成正式文件名,防止mp4未完成时被访问
//临时文件名改成正式文件名,防止mp4未完成时被访问
rename
(
strFileTmp
.
data
(),
strFile
.
data
());
rename
(
strFileTmp
.
data
(),
strFile
.
data
());
//获取文件大小
//获取文件大小
...
@@ -145,4 +145,4 @@ void MP4Recorder::resetTracks() {
...
@@ -145,4 +145,4 @@ void MP4Recorder::resetTracks() {
}
/* namespace mediakit */
}
/* namespace mediakit */
#endif //ENABLE_MP4
RECORD
#endif //ENABLE_MP4
src/Record/MP4Recorder.h
查看文件 @
46be8a38
...
@@ -54,7 +54,7 @@ public:
...
@@ -54,7 +54,7 @@ public:
string
strVhost
;
//vhost
string
strVhost
;
//vhost
};
};
#ifdef ENABLE_MP4
RECORD
#ifdef ENABLE_MP4
class
MP4Recorder
:
public
MediaSinkInterface
{
class
MP4Recorder
:
public
MediaSinkInterface
{
public
:
public
:
typedef
std
::
shared_ptr
<
MP4Recorder
>
Ptr
;
typedef
std
::
shared_ptr
<
MP4Recorder
>
Ptr
;
...
@@ -90,11 +90,11 @@ private:
...
@@ -90,11 +90,11 @@ private:
Ticker
_createFileTicker
;
Ticker
_createFileTicker
;
MP4Info
_info
;
MP4Info
_info
;
bool
_haveVideo
=
false
;
bool
_haveVideo
=
false
;
MP4Muxer
File
::
Ptr
_muxer
;
MP4Muxer
::
Ptr
_muxer
;
list
<
Track
::
Ptr
>
_tracks
;
list
<
Track
::
Ptr
>
_tracks
;
};
};
#endif ///ENABLE_MP4
RECORD
#endif ///ENABLE_MP4
}
/* namespace mediakit */
}
/* namespace mediakit */
...
...
src/Record/Recorder.cpp
查看文件 @
46be8a38
...
@@ -364,7 +364,7 @@ std::shared_ptr<MediaSinkInterface> Recorder::createRecorder(type type, const st
...
@@ -364,7 +364,7 @@ std::shared_ptr<MediaSinkInterface> Recorder::createRecorder(type type, const st
}
}
case
Recorder
:
:
type_mp4
:
{
case
Recorder
:
:
type_mp4
:
{
#if defined(ENABLE_MP4
RECORD
)
#if defined(ENABLE_MP4)
return
std
::
make_shared
<
MP4Recorder
>
(
path
,
vhost
,
app
,
stream_id
);
return
std
::
make_shared
<
MP4Recorder
>
(
path
,
vhost
,
app
,
stream_id
);
#endif
#endif
return
nullptr
;
return
nullptr
;
...
...
src/Rtp/RtpProcess.cpp
查看文件 @
46be8a38
...
@@ -282,7 +282,7 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
...
@@ -282,7 +282,7 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
WarnL
<<
"audio track change to AAC from codecid:"
<<
getCodecName
(
_codecid_audio
);
WarnL
<<
"audio track change to AAC from codecid:"
<<
getCodecName
(
_codecid_audio
);
return
;
return
;
}
}
_muxer
->
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
((
char
*
)
data
,
bytes
,
dts
,
7
));
_muxer
->
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
((
char
*
)
data
,
bytes
,
dts
,
0
,
7
));
break
;
break
;
}
}
default
:
default
:
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论