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
1e1b3794
Commit
1e1b3794
authored
4 years ago
by
xiongziliang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
HLS切片间隔以数据时间戳为准:#463
parent
1b9550cf
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
65 行增加
和
61 行删除
+65
-61
src/Record/HlsMaker.cpp
+32
-33
src/Record/HlsMaker.h
+4
-4
src/Record/TsMuxer.cpp
+29
-24
没有找到文件。
src/Record/HlsMaker.cpp
查看文件 @
1e1b3794
...
@@ -32,27 +32,27 @@ void HlsMaker::makeIndexFile(bool eof) {
...
@@ -32,27 +32,27 @@ void HlsMaker::makeIndexFile(bool eof) {
}
}
}
}
auto
sequence
=
_seg_number
?
(
_file_index
>
_seg_number
?
_file_index
-
_seg_number
:
0LL
)
:
0LL
;
auto
sequence
=
_seg_number
?
(
_file_index
>
_seg_number
?
_file_index
-
_seg_number
:
0LL
)
:
0LL
;
string
m3u8
;
string
m3u8
;
snprintf
(
file_content
,
sizeof
(
file_content
),
snprintf
(
file_content
,
sizeof
(
file_content
),
"#EXTM3U
\n
"
"#EXTM3U
\n
"
"#EXT-X-VERSION:3
\n
"
"#EXT-X-VERSION:3
\n
"
"#EXT-X-ALLOW-CACHE:NO
\n
"
"#EXT-X-ALLOW-CACHE:NO
\n
"
"#EXT-X-TARGETDURATION:%u
\n
"
"#EXT-X-TARGETDURATION:%u
\n
"
"#EXT-X-MEDIA-SEQUENCE:%llu
\n
"
,
"#EXT-X-MEDIA-SEQUENCE:%llu
\n
"
,
(
maxSegmentDuration
+
999
)
/
1000
,
(
maxSegmentDuration
+
999
)
/
1000
,
sequence
);
sequence
);
m3u8
.
assign
(
file_content
);
m3u8
.
assign
(
file_content
);
for
(
auto
&
tp
:
_seg_dur_list
)
{
for
(
auto
&
tp
:
_seg_dur_list
)
{
snprintf
(
file_content
,
sizeof
(
file_content
),
"#EXTINF:%.3f,
\n
%s
\n
"
,
std
::
get
<
0
>
(
tp
)
/
1000.0
,
std
::
get
<
1
>
(
tp
).
data
());
snprintf
(
file_content
,
sizeof
(
file_content
),
"#EXTINF:%.3f,
\n
%s
\n
"
,
std
::
get
<
0
>
(
tp
)
/
1000.0
,
std
::
get
<
1
>
(
tp
).
data
());
m3u8
.
append
(
file_content
);
m3u8
.
append
(
file_content
);
}
}
if
(
eof
)
{
if
(
eof
)
{
snprintf
(
file_content
,
sizeof
(
file_content
),
"#EXT-X-ENDLIST
\n
"
);
snprintf
(
file_content
,
sizeof
(
file_content
),
"#EXT-X-ENDLIST
\n
"
);
m3u8
.
append
(
file_content
);
m3u8
.
append
(
file_content
);
}
}
onWriteHls
(
m3u8
.
data
(),
m3u8
.
size
());
onWriteHls
(
m3u8
.
data
(),
m3u8
.
size
());
...
@@ -61,20 +61,22 @@ void HlsMaker::makeIndexFile(bool eof) {
...
@@ -61,20 +61,22 @@ void HlsMaker::makeIndexFile(bool eof) {
void
HlsMaker
::
inputData
(
void
*
data
,
uint32_t
len
,
uint32_t
timestamp
,
bool
is_idr_fast_packet
)
{
void
HlsMaker
::
inputData
(
void
*
data
,
uint32_t
len
,
uint32_t
timestamp
,
bool
is_idr_fast_packet
)
{
if
(
data
&&
len
)
{
if
(
data
&&
len
)
{
if
(
is_idr_fast_packet
){
if
(
is_idr_fast_packet
)
{
//尝试切片ts
addNewSegment
(
timestamp
);
addNewSegment
(
timestamp
);
}
}
onWriteSegment
((
char
*
)
data
,
len
);
if
(
!
_last_file_name
.
empty
())
{
//记录上次写入数据时间
//存在切片才写入ts数据
_ticker_last_data
.
resetTime
();
onWriteSegment
((
char
*
)
data
,
len
);
}
}
else
{
}
else
{
//resetTracks时触发此逻辑
//resetTracks时触发此逻辑
flushLastSegment
(
true
);
flushLastSegment
(
t
imestamp
,
t
rue
);
}
}
}
}
void
HlsMaker
::
delOldSegment
()
{
void
HlsMaker
::
delOldSegment
()
{
if
(
_seg_number
==
0
)
{
if
(
_seg_number
==
0
)
{
//如果设置为保留0个切片,则认为是保存为点播
//如果设置为保留0个切片,则认为是保存为点播
return
;
return
;
}
}
...
@@ -83,35 +85,35 @@ void HlsMaker::delOldSegment() {
...
@@ -83,35 +85,35 @@ void HlsMaker::delOldSegment() {
_seg_dur_list
.
pop_front
();
_seg_dur_list
.
pop_front
();
}
}
GET_CONFIG
(
uint32_t
,
segRetain
,
Hls
::
kSegmentRetain
);
GET_CONFIG
(
uint32_t
,
segRetain
,
Hls
::
kSegmentRetain
);
//但是实际保存的切片个数比m3u8所述多若干个,这样做的目的是防止播放器在切片删除前能下载完毕
//但是实际保存的切片个数比m3u8所述多若干个,这样做的目的是防止播放器在切片删除前能下载完毕
if
(
_file_index
>
_seg_number
+
segRetain
)
{
if
(
_file_index
>
_seg_number
+
segRetain
)
{
onDelSegment
(
_file_index
-
_seg_number
-
segRetain
-
1
);
onDelSegment
(
_file_index
-
_seg_number
-
segRetain
-
1
);
}
}
}
}
void
HlsMaker
::
addNewSegment
(
uint32_t
)
{
void
HlsMaker
::
addNewSegment
(
uint32_t
stamp
)
{
if
(
!
_last_file_name
.
empty
()
&&
_ticker
.
elapsedTime
()
<
_seg_duration
*
1000
)
{
if
(
!
_last_file_name
.
empty
()
&&
stamp
-
_last_seg_timestamp
<
_seg_duration
*
1000
)
{
//存在上个切片,并且未到分片时间
//存在上个切片,并且未到分片时间
return
;
return
;
}
}
//关闭并保存上一个切片,如果_seg_number==0,那么是点播。
//关闭并保存上一个切片,如果_seg_number==0,那么是点播。
flushLastSegment
(
_seg_number
==
0
);
flushLastSegment
(
stamp
,
_seg_number
==
0
);
//新增切片
//新增切片
_last_file_name
=
onOpenSegment
(
_file_index
++
);
_last_file_name
=
onOpenSegment
(
_file_index
++
);
//
重置切片计时器
//
记录本次切片的起始时间戳
_
ticker
.
resetTime
()
;
_
last_seg_timestamp
=
stamp
;
}
}
void
HlsMaker
::
flushLastSegment
(
bool
eof
){
void
HlsMaker
::
flushLastSegment
(
uint32_t
timestamp
,
bool
eof
){
if
(
_last_file_name
.
empty
())
{
if
(
_last_file_name
.
empty
())
{
//不存在上个切片
//不存在上个切片
return
;
return
;
}
}
//文件创建到最后一次数据写入的时间即为切片长度
//文件创建到最后一次数据写入的时间即为切片长度
auto
seg_dur
=
_ticker
.
elapsedTime
()
-
_ticker_last_data
.
elapsedTime
()
;
auto
seg_dur
=
timestamp
-
_last_seg_timestamp
;
if
(
seg_dur
<=
0
)
{
if
(
seg_dur
<=
0
)
{
seg_dur
=
100
;
seg_dur
=
100
;
}
}
_seg_dur_list
.
push_back
(
std
::
make_tuple
(
seg_dur
,
_last_file_name
));
_seg_dur_list
.
push_back
(
std
::
make_tuple
(
seg_dur
,
_last_file_name
));
...
@@ -124,13 +126,11 @@ bool HlsMaker::isLive() {
...
@@ -124,13 +126,11 @@ bool HlsMaker::isLive() {
return
_seg_number
!=
0
;
return
_seg_number
!=
0
;
}
}
void
HlsMaker
::
clear
(){
void
HlsMaker
::
clear
()
{
_file_index
=
0
;
_last_seg_timestamp
=
0
;
_seg_dur_list
.
clear
();
_seg_dur_list
.
clear
();
_last_file_name
.
clear
();
_last_file_name
.
clear
();
_ticker_last_data
.
resetTime
();
_ticker
.
resetTime
();
_file_index
=
0
;
}
}
}
//
namespace
mediakit
}
//
namespace
mediakit
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/Record/HlsMaker.h
查看文件 @
1e1b3794
...
@@ -80,9 +80,10 @@ protected:
...
@@ -80,9 +80,10 @@ protected:
/**
/**
* 关闭上个ts切片并且写入m3u8索引
* 关闭上个ts切片并且写入m3u8索引
* @param timestamp 毫秒时间戳
* @param eof
* @param eof
*/
*/
void
flushLastSegment
(
bool
eof
=
false
);
void
flushLastSegment
(
uint32_t
timestamp
,
bool
eof
=
false
);
private
:
private
:
/**
/**
...
@@ -103,11 +104,10 @@ private:
...
@@ -103,11 +104,10 @@ private:
void
addNewSegment
(
uint32_t
timestamp
);
void
addNewSegment
(
uint32_t
timestamp
);
private
:
private
:
uint32_t
_seg_number
=
0
;
float
_seg_duration
=
0
;
float
_seg_duration
=
0
;
uint32_t
_seg_number
=
0
;
uint32_t
_last_seg_timestamp
=
0
;
uint64_t
_file_index
=
0
;
uint64_t
_file_index
=
0
;
Ticker
_ticker
;
Ticker
_ticker_last_data
;
string
_last_file_name
;
string
_last_file_name
;
std
::
deque
<
tuple
<
int
,
string
>
>
_seg_dur_list
;
std
::
deque
<
tuple
<
int
,
string
>
>
_seg_dur_list
;
};
};
...
...
This diff is collapsed.
Click to expand it.
src/Record/TsMuxer.cpp
查看文件 @
1e1b3794
...
@@ -25,20 +25,20 @@ TsMuxer::~TsMuxer() {
...
@@ -25,20 +25,20 @@ TsMuxer::~TsMuxer() {
}
}
void
TsMuxer
::
stampSync
(){
void
TsMuxer
::
stampSync
(){
if
(
_codec_to_trackid
.
size
()
<
2
)
{
if
(
_codec_to_trackid
.
size
()
<
2
)
{
return
;
return
;
}
}
Stamp
*
audio
=
nullptr
,
*
video
=
nullptr
;
Stamp
*
audio
=
nullptr
,
*
video
=
nullptr
;
for
(
auto
&
pr
:
_codec_to_trackid
)
{
for
(
auto
&
pr
:
_codec_to_trackid
)
{
switch
(
getTrackType
((
CodecId
)
pr
.
first
)){
switch
(
getTrackType
((
CodecId
)
pr
.
first
))
{
case
TrackAudio
:
audio
=
&
pr
.
second
.
stamp
;
break
;
case
TrackAudio
:
audio
=
&
pr
.
second
.
stamp
;
break
;
case
TrackVideo
:
video
=
&
pr
.
second
.
stamp
;
break
;
case
TrackVideo
:
video
=
&
pr
.
second
.
stamp
;
break
;
default
:
break
;
default
:
break
;
}
}
}
}
if
(
audio
&&
video
)
{
if
(
audio
&&
video
)
{
//音频时间戳同步于视频,因为音频时间戳被修改后不影响播放
//音频时间戳同步于视频,因为音频时间戳被修改后不影响播放
audio
->
syncTo
(
*
video
);
audio
->
syncTo
(
*
video
);
}
}
...
@@ -87,7 +87,7 @@ void TsMuxer::addTrack(const Track::Ptr &track) {
...
@@ -87,7 +87,7 @@ void TsMuxer::addTrack(const Track::Ptr &track) {
void
TsMuxer
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
void
TsMuxer
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
auto
it
=
_codec_to_trackid
.
find
(
frame
->
getCodecId
());
auto
it
=
_codec_to_trackid
.
find
(
frame
->
getCodecId
());
if
(
it
==
_codec_to_trackid
.
end
())
{
if
(
it
==
_codec_to_trackid
.
end
())
{
return
;
return
;
}
}
auto
&
track_info
=
it
->
second
;
auto
&
track_info
=
it
->
second
;
...
@@ -95,39 +95,41 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) {
...
@@ -95,39 +95,41 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) {
_is_idr_fast_packet
=
!
_have_video
;
_is_idr_fast_packet
=
!
_have_video
;
switch
(
frame
->
getCodecId
()){
switch
(
frame
->
getCodecId
()){
case
CodecH264
:
{
case
CodecH264
:
{
int
type
=
H264_TYPE
(
*
((
uint8_t
*
)
frame
->
data
()
+
frame
->
prefixSize
()));
int
type
=
H264_TYPE
(
*
((
uint8_t
*
)
frame
->
data
()
+
frame
->
prefixSize
()));
if
(
type
==
H264Frame
::
NAL_SEI
)
{
if
(
type
==
H264Frame
::
NAL_SEI
)
{
break
;
break
;
}
}
}
}
case
CodecH265
:
{
case
CodecH265
:
{
//这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理,
//这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理,
if
(
!
_frameCached
.
empty
()
&&
_frameCached
.
back
()
->
dts
()
!=
frame
->
dts
())
{
if
(
!
_frameCached
.
empty
()
&&
_frameCached
.
back
()
->
dts
()
!=
frame
->
dts
())
{
Frame
::
Ptr
back
=
_frameCached
.
back
();
Frame
::
Ptr
back
=
_frameCached
.
back
();
Buffer
::
Ptr
merged_frame
=
back
;
Buffer
::
Ptr
merged_frame
=
back
;
if
(
_frameCached
.
size
()
!=
1
)
{
if
(
_frameCached
.
size
()
!=
1
)
{
string
merged
;
string
merged
;
_frameCached
.
for_each
([
&
](
const
Frame
::
Ptr
&
frame
){
_frameCached
.
for_each
([
&
](
const
Frame
::
Ptr
&
frame
)
{
if
(
frame
->
prefixSize
())
{
if
(
frame
->
prefixSize
())
{
merged
.
append
(
frame
->
data
(),
frame
->
size
());
merged
.
append
(
frame
->
data
(),
frame
->
size
());
}
else
{
}
else
{
merged
.
append
(
"
\x00\x00\x00\x01
"
,
4
);
merged
.
append
(
"
\x00\x00\x00\x01
"
,
4
);
merged
.
append
(
frame
->
data
(),
frame
->
size
());
merged
.
append
(
frame
->
data
(),
frame
->
size
());
}
}
if
(
frame
->
keyFrame
())
{
if
(
frame
->
keyFrame
())
{
_is_idr_fast_packet
=
true
;
_is_idr_fast_packet
=
true
;
}
}
});
});
merged_frame
=
std
::
make_shared
<
BufferString
>
(
std
::
move
(
merged
));
merged_frame
=
std
::
make_shared
<
BufferString
>
(
std
::
move
(
merged
));
}
}
track_info
.
stamp
.
revise
(
back
->
dts
(),
back
->
pts
(),
dts_out
,
pts_out
);
track_info
.
stamp
.
revise
(
back
->
dts
(),
back
->
pts
(),
dts_out
,
pts_out
);
//取视频时间戳为TS的时间戳
_timestamp
=
dts_out
;
_timestamp
=
dts_out
;
mpeg_ts_write
(
_context
,
track_info
.
track_id
,
back
->
keyFrame
()
?
0x0001
:
0
,
pts_out
*
90LL
,
dts_out
*
90LL
,
merged_frame
->
data
(),
merged_frame
->
size
());
mpeg_ts_write
(
_context
,
track_info
.
track_id
,
back
->
keyFrame
()
?
0x0001
:
0
,
pts_out
*
90LL
,
dts_out
*
90LL
,
merged_frame
->
data
(),
merged_frame
->
size
());
_frameCached
.
clear
();
_frameCached
.
clear
();
}
}
_frameCached
.
emplace_back
(
Frame
::
getCacheAbleFrame
(
frame
));
_frameCached
.
emplace_back
(
Frame
::
getCacheAbleFrame
(
frame
));
}
break
;
break
;
}
case
CodecAAC
:
{
case
CodecAAC
:
{
if
(
frame
->
prefixSize
()
==
0
)
{
if
(
frame
->
prefixSize
()
==
0
)
{
...
@@ -137,18 +139,21 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) {
...
@@ -137,18 +139,21 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) {
}
}
default
:
{
default
:
{
track_info
.
stamp
.
revise
(
frame
->
dts
(),
frame
->
pts
(),
dts_out
,
pts_out
);
track_info
.
stamp
.
revise
(
frame
->
dts
(),
frame
->
pts
(),
dts_out
,
pts_out
);
_timestamp
=
dts_out
;
if
(
!
_have_video
){
//没有视频时,才以音频时间戳为TS的时间戳
_timestamp
=
dts_out
;
}
mpeg_ts_write
(
_context
,
track_info
.
track_id
,
frame
->
keyFrame
()
?
0x0001
:
0
,
pts_out
*
90LL
,
dts_out
*
90LL
,
frame
->
data
(),
frame
->
size
());
mpeg_ts_write
(
_context
,
track_info
.
track_id
,
frame
->
keyFrame
()
?
0x0001
:
0
,
pts_out
*
90LL
,
dts_out
*
90LL
,
frame
->
data
(),
frame
->
size
());
}
break
;
break
;
}
}
}
}
}
void
TsMuxer
::
resetTracks
()
{
void
TsMuxer
::
resetTracks
()
{
_have_video
=
false
;
_have_video
=
false
;
//通知片段中断
//通知片段中断
onTs
(
nullptr
,
0
,
0
,
0
);
onTs
(
nullptr
,
0
,
_timestamp
,
0
);
uninit
();
uninit
();
init
();
init
();
}
}
...
@@ -169,8 +174,8 @@ void TsMuxer::init() {
...
@@ -169,8 +174,8 @@ void TsMuxer::init() {
muxer
->
_is_idr_fast_packet
=
false
;
muxer
->
_is_idr_fast_packet
=
false
;
}
}
};
};
if
(
_context
==
nullptr
)
{
if
(
_context
==
nullptr
)
{
_context
=
mpeg_ts_create
(
&
s_func
,
this
);
_context
=
mpeg_ts_create
(
&
s_func
,
this
);
}
}
}
}
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论