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
7fcd88d0
Unverified
Commit
7fcd88d0
authored
Apr 05, 2023
by
alexliyu7352
Committed by
GitHub
Apr 05, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
避免hls拉流时m3u8文件出现问题或直播结束后,无限重试 (#2357)
Co-authored-by: xiongziliang <771730766@qq.com>
parent
21691e34
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
42 行增加
和
25 行删除
+42
-25
src/Http/HlsParser.cpp
+2
-5
src/Http/HlsParser.h
+12
-5
src/Http/HlsPlayer.cpp
+23
-11
src/Http/HlsPlayer.h
+5
-4
没有找到文件。
src/Http/HlsParser.cpp
查看文件 @
7fcd88d0
...
...
@@ -98,17 +98,14 @@ bool HlsParser::parse(const string &http_url, const string &m3u8) {
continue
;
}
if
(
_is_m3u8
)
{
onParsed
(
_is_m3u8_inner
,
_sequence
,
ts_map
);
}
return
_is_m3u8
;
return
_is_m3u8
&&
onParsed
(
_is_m3u8_inner
,
_sequence
,
ts_map
);
}
bool
HlsParser
::
isM3u8
()
const
{
return
_is_m3u8
;
}
bool
HlsParser
::
isLive
()
const
{
bool
HlsParser
::
isLive
()
const
{
return
_is_live
;
}
...
...
src/Http/HlsParser.h
查看文件 @
7fcd88d0
...
...
@@ -36,8 +36,9 @@ typedef struct{
class
HlsParser
{
public
:
HlsParser
(){}
~
HlsParser
(){}
HlsParser
()
=
default
;
~
HlsParser
()
=
default
;
bool
parse
(
const
std
::
string
&
http_url
,
const
std
::
string
&
m3u8
);
/**
...
...
@@ -79,10 +80,16 @@ public:
* 得到总时间
*/
float
getTotalDuration
()
const
;
protected
:
//解析出ts文件地址回调
virtual
void
onParsed
(
bool
is_m3u8_inner
,
int64_t
sequence
,
const
std
::
map
<
int
,
ts_segment
>
&
ts_list
)
{};
/**
* 解析m3u8文件回调
* @param is_m3u8_inner 该m3u8文件中是否包含多个hls地址
* @param sequence ts序号
* @param ts_list ts地址列表
* @return 是否解析成功,返回false时,将导致HlsParser::parse返回false
*/
virtual
bool
onParsed
(
bool
is_m3u8_inner
,
int64_t
sequence
,
const
std
::
map
<
int
,
ts_segment
>
&
ts_list
)
=
0
;
private
:
bool
_is_m3u8
=
false
;
...
...
src/Http/HlsPlayer.cpp
查看文件 @
7fcd88d0
...
...
@@ -51,7 +51,7 @@ void HlsPlayer::teardown_l(const SockException &ex) {
}
else
{
_try_fetch_index_times
+=
1
;
shutdown
(
ex
);
WarnL
<<
"
重新尝试拉取索引文件
["
<<
_try_fetch_index_times
<<
"]:"
<<
_play_url
;
WarnL
<<
"
Attempt to pull the m3u8 file again
["
<<
_try_fetch_index_times
<<
"]:"
<<
_play_url
;
fetchIndexFile
();
return
;
}
...
...
@@ -118,7 +118,7 @@ void HlsPlayer::fetchSegment() {
return
;
}
if
(
err
)
{
WarnL
<<
"
d
ownload ts segment "
<<
url
<<
" failed:"
<<
err
.
what
();
WarnL
<<
"
D
ownload ts segment "
<<
url
<<
" failed:"
<<
err
.
what
();
if
(
err
.
getErrCode
()
==
Err_timeout
)
{
strong_self
->
_timeout_multiple
=
MAX
(
strong_self
->
_timeout_multiple
+
1
,
MAX_TIMEOUT_MULTIPLE
);
}
else
{
...
...
@@ -147,30 +147,41 @@ void HlsPlayer::fetchSegment() {
_http_ts_player
->
sendRequest
(
url
);
}
void
HlsPlayer
::
onParsed
(
bool
is_m3u8_inner
,
int64_t
sequence
,
const
map
<
int
,
ts_segment
>
&
ts_map
)
{
bool
HlsPlayer
::
onParsed
(
bool
is_m3u8_inner
,
int64_t
sequence
,
const
map
<
int
,
ts_segment
>
&
ts_map
)
{
if
(
!
is_m3u8_inner
)
{
//这是ts播放列表
//
这是ts播放列表
if
(
_last_sequence
==
sequence
)
{
return
;
// 如果是重复的ts列表,那么忽略
// 但是需要注意, 如果当前ts列表为空了, 那么表明直播结束了或者m3u8文件有问题,需要重新拉流
// 这里的5倍是为了防止m3u8文件有问题导致的无限重试
if
(
_last_sequence
>
0
&&
_ts_list
.
empty
()
&&
HlsParser
::
isLive
()
&&
_wait_index_update_ticker
.
elapsedTime
()
>
(
uint64_t
)
HlsParser
::
getTargetDur
()
*
1000
*
5
)
{
_wait_index_update_ticker
.
resetTime
();
WarnL
<<
"Fetch new ts list from m3u8 timeout"
;
return
false
;
}
return
true
;
}
_last_sequence
=
sequence
;
_wait_index_update_ticker
.
resetTime
();
for
(
auto
&
pr
:
ts_map
)
{
auto
&
ts
=
pr
.
second
;
if
(
_ts_url_cache
.
emplace
(
ts
.
url
).
second
)
{
//该ts未重复
//
该ts未重复
_ts_list
.
emplace_back
(
ts
);
//按时间排序
//
按时间排序
_ts_url_sort
.
emplace_back
(
ts
.
url
);
}
}
if
(
_ts_url_sort
.
size
()
>
2
*
ts_map
.
size
())
{
//去除防重列表中过多的数据
//
去除防重列表中过多的数据
_ts_url_cache
.
erase
(
_ts_url_sort
.
front
());
_ts_url_sort
.
pop_front
();
}
fetchSegment
();
}
else
{
//这是m3u8列表,我们播放最高清的子hls
//
这是m3u8列表,我们播放最高清的子hls
if
(
ts_map
.
empty
())
{
throw
invalid_argument
(
"empty sub hls list:"
+
getUrl
());
}
...
...
@@ -184,6 +195,7 @@ void HlsPlayer::onParsed(bool is_m3u8_inner, int64_t sequence, const map<int, ts
}
},
false
);
}
return
true
;
}
void
HlsPlayer
::
onResponseHeader
(
const
string
&
status
,
const
HttpClient
::
HttpHeader
&
headers
)
{
...
...
@@ -193,7 +205,7 @@ void HlsPlayer::onResponseHeader(const string &status, const HttpClient::HttpHea
}
auto
content_type
=
strToLower
(
const_cast
<
HttpClient
::
HttpHeader
&>
(
headers
)[
"Content-Type"
]);
if
(
content_type
.
find
(
"application/vnd.apple.mpegurl"
)
!=
0
&&
content_type
.
find
(
"/x-mpegurl"
)
==
_StrPrinter
::
npos
)
{
WarnL
<<
"
m
ay not a hls video: "
<<
content_type
<<
", url: "
<<
getUrl
();
WarnL
<<
"
M
ay not a hls video: "
<<
content_type
<<
", url: "
<<
getUrl
();
}
_m3u8
.
clear
();
}
...
...
@@ -208,7 +220,7 @@ void HlsPlayer::onResponseCompleted(const SockException &ex) {
return
;
}
if
(
!
HlsParser
::
parse
(
getUrl
(),
_m3u8
))
{
teardown_l
(
SockException
(
Err_other
,
"parse m3u8 failed:"
+
_
m3u8
));
teardown_l
(
SockException
(
Err_other
,
"parse m3u8 failed:"
+
_
play_url
));
return
;
}
if
(
!
_play_result
)
{
...
...
src/Http/HlsPlayer.h
查看文件 @
7fcd88d0
...
...
@@ -73,11 +73,11 @@ protected:
virtual
void
onPacket
(
const
char
*
data
,
size_t
len
)
=
0
;
private
:
void
onParsed
(
bool
is_m3u8_inner
,
int64_t
sequence
,
const
map
<
int
,
ts_segment
>
&
ts_map
)
override
;
void
onResponseHeader
(
const
std
::
string
&
status
,
const
HttpHeader
&
headers
)
override
;
void
onResponseBody
(
const
char
*
buf
,
size_t
size
)
override
;
bool
onParsed
(
bool
is_m3u8_inner
,
int64_t
sequence
,
const
map
<
int
,
ts_segment
>
&
ts_map
)
override
;
void
onResponseHeader
(
const
std
::
string
&
status
,
const
HttpHeader
&
headers
)
override
;
void
onResponseBody
(
const
char
*
buf
,
size_t
size
)
override
;
void
onResponseCompleted
(
const
toolkit
::
SockException
&
e
)
override
;
bool
onRedirectUrl
(
const
std
::
string
&
url
,
bool
temporary
)
override
;
bool
onRedirectUrl
(
const
std
::
string
&
url
,
bool
temporary
)
override
;
private
:
void
playDelay
();
...
...
@@ -101,6 +101,7 @@ private:
std
::
string
_play_url
;
toolkit
::
Timer
::
Ptr
_timer
;
toolkit
::
Timer
::
Ptr
_timer_ts
;
toolkit
::
Ticker
_wait_index_update_ticker
;
std
::
list
<
ts_segment
>
_ts_list
;
std
::
list
<
std
::
string
>
_ts_url_sort
;
std
::
set
<
std
::
string
,
UrlComp
>
_ts_url_cache
;
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论