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
11a39c68
Unverified
Commit
11a39c68
authored
May 31, 2023
by
xiongguangjie
Committed by
GitHub
May 31, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修复海康rtsp点播拉流seek相关bug(#2501 #2511)
parent
0232caf0
隐藏空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
170 行增加
和
177 行删除
+170
-177
src/Rtsp/RtspPlayer.cpp
+170
-177
没有找到文件。
src/Rtsp/RtspPlayer.cpp
查看文件 @
11a39c68
...
...
@@ -8,40 +8,35 @@
* may be found in the AUTHORS file in the root of the source tree.
*/
#include <set>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include "Common/config.h"
#include "RtspPlayer.h"
#include "Util/MD5.h"
#include "Util/base64.h"
#include "Common/config.h"
#include "Rtcp/Rtcp.h"
#include "Rtcp/RtcpContext.h"
#include "RtspMediaSource.h"
#include "RtspDemuxer.h"
#include "RtspMediaSource.h"
#include "RtspPlayerImp.h"
#include "Util/MD5.h"
#include "Util/base64.h"
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <set>
using
namespace
toolkit
;
using
namespace
std
;
namespace
mediakit
{
enum
PlayType
{
type_play
=
0
,
type_pause
,
type_seek
,
type_speed
};
enum
PlayType
{
type_play
=
0
,
type_pause
,
type_seek
,
type_speed
};
RtspPlayer
::
RtspPlayer
(
const
EventPoller
::
Ptr
&
poller
)
:
TcpClient
(
poller
){
}
RtspPlayer
::
RtspPlayer
(
const
EventPoller
::
Ptr
&
poller
)
:
TcpClient
(
poller
)
{
}
RtspPlayer
::~
RtspPlayer
(
void
)
{
DebugL
<<
endl
;
}
void
RtspPlayer
::
sendTeardown
(){
void
RtspPlayer
::
sendTeardown
()
{
if
(
alive
())
{
if
(
!
_content_base
.
empty
())
{
sendRtspRequest
(
"TEARDOWN"
,
_content_base
);
...
...
@@ -50,7 +45,7 @@ void RtspPlayer::sendTeardown(){
}
}
void
RtspPlayer
::
teardown
(){
void
RtspPlayer
::
teardown
()
{
sendTeardown
();
_md5_nonce
.
clear
();
_realm
.
clear
();
...
...
@@ -69,7 +64,7 @@ void RtspPlayer::teardown(){
_on_response
=
nullptr
;
}
void
RtspPlayer
::
play
(
const
string
&
strUrl
){
void
RtspPlayer
::
play
(
const
string
&
strUrl
)
{
RtspUrl
url
;
try
{
url
.
parse
(
strUrl
);
...
...
@@ -94,32 +89,35 @@ void RtspPlayer::play(const string &strUrl){
weak_ptr
<
RtspPlayer
>
weakSelf
=
static_pointer_cast
<
RtspPlayer
>
(
shared_from_this
());
float
playTimeOutSec
=
(
*
this
)[
Client
::
kTimeoutMS
].
as
<
int
>
()
/
1000.0
f
;
_play_check_timer
.
reset
(
new
Timer
(
playTimeOutSec
,
[
weakSelf
]()
{
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
)
{
_play_check_timer
.
reset
(
new
Timer
(
playTimeOutSec
,
[
weakSelf
]()
{
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
)
{
return
false
;
}
strongSelf
->
onPlayResult_l
(
SockException
(
Err_timeout
,
"play rtsp timeout"
),
false
);
return
false
;
}
strongSelf
->
onPlayResult_l
(
SockException
(
Err_timeout
,
"play rtsp timeout"
),
false
);
return
false
;
},
getPoller
()));
},
getPoller
()));
if
(
!
(
*
this
)[
Client
::
kNetAdapter
].
empty
())
{
if
(
!
(
*
this
)[
Client
::
kNetAdapter
].
empty
())
{
setNetAdapter
((
*
this
)[
Client
::
kNetAdapter
]);
}
startConnect
(
url
.
_host
,
url
.
_port
,
playTimeOutSec
);
}
void
RtspPlayer
::
onConnect
(
const
SockException
&
err
){
if
(
err
.
getErrCode
()
!=
Err_success
)
{
onPlayResult_l
(
err
,
false
);
void
RtspPlayer
::
onConnect
(
const
SockException
&
err
)
{
if
(
err
.
getErrCode
()
!=
Err_success
)
{
onPlayResult_l
(
err
,
false
);
return
;
}
sendOptions
();
}
void
RtspPlayer
::
onRecv
(
const
Buffer
::
Ptr
&
buf
)
{
if
(
_benchmark_mode
&&
!
_play_check_timer
)
{
//在性能测试模式下,如果rtsp握手完毕后,不再解析rtp包
void
RtspPlayer
::
onRecv
(
const
Buffer
::
Ptr
&
buf
)
{
if
(
_benchmark_mode
&&
!
_play_check_timer
)
{
//
在性能测试模式下,如果rtsp握手完毕后,不再解析rtp包
_rtp_recv_ticker
.
resetTime
();
return
;
}
...
...
@@ -132,21 +130,21 @@ void RtspPlayer::onRecv(const Buffer::Ptr& buf) {
}
void
RtspPlayer
::
onError
(
const
SockException
&
ex
)
{
//定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l
(
ex
,
!
_play_check_timer
);
//
定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l
(
ex
,
!
_play_check_timer
);
}
// from live555
bool
RtspPlayer
::
handleAuthenticationFailure
(
const
string
&
paramsStr
)
{
if
(
!
_realm
.
empty
())
{
//已经认证过了
if
(
!
_realm
.
empty
())
{
//
已经认证过了
return
false
;
}
char
*
realm
=
new
char
[
paramsStr
.
size
()];
char
*
nonce
=
new
char
[
paramsStr
.
size
()];
char
*
stale
=
new
char
[
paramsStr
.
size
()];
onceToken
token
(
nullptr
,
[
&
]()
{
onceToken
token
(
nullptr
,
[
&
]()
{
delete
[]
realm
;
delete
[]
nonce
;
delete
[]
stale
;
...
...
@@ -169,16 +167,16 @@ bool RtspPlayer::handleAuthenticationFailure(const string ¶msStr) {
return
false
;
}
bool
RtspPlayer
::
handleResponse
(
const
string
&
cmd
,
const
Parser
&
parser
){
bool
RtspPlayer
::
handleResponse
(
const
string
&
cmd
,
const
Parser
&
parser
)
{
string
authInfo
=
parser
[
"WWW-Authenticate"
];
//发送DESCRIBE命令后的回复
//
发送DESCRIBE命令后的回复
if
((
parser
.
Url
()
==
"401"
)
&&
handleAuthenticationFailure
(
authInfo
))
{
sendOptions
();
return
false
;
}
if
(
parser
.
Url
()
==
"302"
||
parser
.
Url
()
==
"301"
)
{
if
(
parser
.
Url
()
==
"302"
||
parser
.
Url
()
==
"301"
)
{
auto
newUrl
=
parser
[
"Location"
];
if
(
newUrl
.
empty
())
{
if
(
newUrl
.
empty
())
{
throw
std
::
runtime_error
(
"未找到Location字段(跳转url)"
);
}
play
(
newUrl
);
...
...
@@ -190,19 +188,19 @@ bool RtspPlayer::handleResponse(const string &cmd, const Parser &parser){
return
true
;
}
void
RtspPlayer
::
handleResDESCRIBE
(
const
Parser
&
parser
)
{
void
RtspPlayer
::
handleResDESCRIBE
(
const
Parser
&
parser
)
{
if
(
!
handleResponse
(
"DESCRIBE"
,
parser
))
{
return
;
}
_content_base
=
parser
[
"Content-Base"
];
if
(
_content_base
.
empty
())
{
if
(
_content_base
.
empty
())
{
_content_base
=
_play_url
;
}
if
(
_content_base
.
back
()
==
'/'
)
{
_content_base
.
pop_back
();
}
//解析sdp
//
解析sdp
SdpParser
sdpParser
(
parser
.
Content
());
string
sdp
;
...
...
@@ -224,16 +222,16 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) {
}
_rtcp_context
.
clear
();
for
(
auto
&
track
:
_sdp_track
)
{
if
(
track
->
_pt
!=
0xff
)
{
setPayloadType
(
_rtcp_context
.
size
(),
track
->
_pt
);
if
(
track
->
_pt
!=
0xff
)
{
setPayloadType
(
_rtcp_context
.
size
(),
track
->
_pt
);
}
_rtcp_context
.
emplace_back
(
std
::
make_shared
<
RtcpContextForRecv
>
());
}
sendSetup
(
0
);
}
//有必要的情况下创建udp端口
void
RtspPlayer
::
createUdpSockIfNecessary
(
int
track_idx
){
//
有必要的情况下创建udp端口
void
RtspPlayer
::
createUdpSockIfNecessary
(
int
track_idx
)
{
auto
&
rtpSockRef
=
_rtp_sock
[
track_idx
];
auto
&
rtcpSockRef
=
_rtcp_sock
[
track_idx
];
if
(
!
rtpSockRef
||
!
rtcpSockRef
)
{
...
...
@@ -244,30 +242,27 @@ void RtspPlayer::createUdpSockIfNecessary(int track_idx){
}
}
//发送SETUP命令
//
发送SETUP命令
void
RtspPlayer
::
sendSetup
(
unsigned
int
track_idx
)
{
_on_response
=
std
::
bind
(
&
RtspPlayer
::
handleResSETUP
,
this
,
placeholders
::
_1
,
track_idx
);
auto
&
track
=
_sdp_track
[
track_idx
];
auto
control_url
=
track
->
getControlUrl
(
_content_base
);
switch
(
_rtp_type
)
{
case
Rtsp
:
:
RTP_TCP
:
{
sendRtspRequest
(
"SETUP"
,
control_url
,
{
"Transport"
,
StrPrinter
<<
"RTP/AVP/TCP;unicast;interleaved="
<<
track
->
_type
*
2
<<
"-"
<<
track
->
_type
*
2
+
1
});
}
break
;
sendRtspRequest
(
"SETUP"
,
control_url
,
{
"Transport"
,
StrPrinter
<<
"RTP/AVP/TCP;unicast;interleaved="
<<
track
->
_type
*
2
<<
"-"
<<
track
->
_type
*
2
+
1
});
}
break
;
case
Rtsp
:
:
RTP_MULTICAST
:
{
sendRtspRequest
(
"SETUP"
,
control_url
,
{
"Transport"
,
"RTP/AVP;multicast"
});
}
break
;
sendRtspRequest
(
"SETUP"
,
control_url
,
{
"Transport"
,
"RTP/AVP;multicast"
});
}
break
;
case
Rtsp
:
:
RTP_UDP
:
{
createUdpSockIfNecessary
(
track_idx
);
sendRtspRequest
(
"SETUP"
,
control_url
,
{
"Transport"
,
StrPrinter
<<
"RTP/AVP;unicast;client_port="
<<
_rtp_sock
[
track_idx
]
->
get_local_port
()
<<
"-"
<<
_rtcp_sock
[
track_idx
]
->
get_local_port
()});
}
break
;
default
:
break
;
sendRtspRequest
(
"SETUP"
,
control_url
,
{
"Transport"
,
StrPrinter
<<
"RTP/AVP;unicast;client_port="
<<
_rtp_sock
[
track_idx
]
->
get_local_port
()
<<
"-"
<<
_rtcp_sock
[
track_idx
]
->
get_local_port
()
});
}
break
;
default
:
break
;
}
}
...
...
@@ -292,9 +287,9 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
auto
transport_map
=
Parser
::
parseArgs
(
strTransport
,
";"
,
"="
);
RtspSplitter
::
enableRecvRtp
(
_rtp_type
==
Rtsp
::
RTP_TCP
);
string
ssrc
=
transport_map
[
"ssrc"
];
if
(
!
ssrc
.
empty
())
{
if
(
!
ssrc
.
empty
())
{
sscanf
(
ssrc
.
data
(),
"%x"
,
&
_sdp_track
[
track_idx
]
->
_ssrc
);
}
else
{
}
else
{
_sdp_track
[
track_idx
]
->
_ssrc
=
0
;
}
...
...
@@ -310,47 +305,47 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
auto
&
pRtcpSockRef
=
_rtcp_sock
[
track_idx
];
if
(
_rtp_type
==
Rtsp
::
RTP_MULTICAST
)
{
//udp组播
auto
multiAddr
=
transport_map
[
"destination"
];
//
udp组播
auto
multiAddr
=
transport_map
[
"destination"
];
pRtpSockRef
=
createSocket
();
//目前组播仅支持ipv4
//
目前组播仅支持ipv4
if
(
!
pRtpSockRef
->
bindUdpSock
(
rtp_port
,
"0.0.0.0"
))
{
pRtpSockRef
.
reset
();
throw
std
::
runtime_error
(
"open udp sock err"
);
}
auto
fd
=
pRtpSockRef
->
rawFD
();
if
(
-
1
==
SockUtil
::
joinMultiAddrFilter
(
fd
,
multiAddr
.
data
(),
get_peer_ip
().
data
(),
get_local_ip
().
data
()))
{
SockUtil
::
joinMultiAddr
(
fd
,
multiAddr
.
data
(),
get_local_ip
().
data
());
if
(
-
1
==
SockUtil
::
joinMultiAddrFilter
(
fd
,
multiAddr
.
data
(),
get_peer_ip
().
data
(),
get_local_ip
().
data
()))
{
SockUtil
::
joinMultiAddr
(
fd
,
multiAddr
.
data
(),
get_local_ip
().
data
());
}
//设置rtcp发送端口
//
设置rtcp发送端口
pRtcpSockRef
=
createSocket
();
//目前组播仅支持ipv4
//
目前组播仅支持ipv4
if
(
!
pRtcpSockRef
->
bindUdpSock
(
0
,
"0.0.0.0"
))
{
//分配端口失败
//
分配端口失败
throw
runtime_error
(
"open udp socket failed"
);
}
//设置发送地址和发送端口
//
设置发送地址和发送端口
auto
dst
=
SockUtil
::
make_sockaddr
(
get_peer_ip
().
data
(),
rtcp_port
);
pRtcpSockRef
->
bindPeerAddr
((
struct
sockaddr
*
)
&
(
dst
));
}
else
{
createUdpSockIfNecessary
(
track_idx
);
//udp单播
//
udp单播
auto
dst
=
SockUtil
::
make_sockaddr
(
get_peer_ip
().
data
(),
rtp_port
);
pRtpSockRef
->
bindPeerAddr
((
struct
sockaddr
*
)
&
(
dst
));
//发送rtp打洞包
//
发送rtp打洞包
pRtpSockRef
->
send
(
"
\xce\xfa\xed\xfe
"
,
4
);
dst
=
SockUtil
::
make_sockaddr
(
get_peer_ip
().
data
(),
rtcp_port
);
//设置rtcp发送目标,为后续发送rtcp做准备
//
设置rtcp发送目标,为后续发送rtcp做准备
pRtcpSockRef
->
bindPeerAddr
((
struct
sockaddr
*
)
&
(
dst
));
}
auto
peer_ip
=
get_peer_ip
();
weak_ptr
<
RtspPlayer
>
weakSelf
=
static_pointer_cast
<
RtspPlayer
>
(
shared_from_this
());
//设置rtp over udp接收回调处理函数
pRtpSockRef
->
setOnRead
([
peer_ip
,
track_idx
,
weakSelf
](
const
Buffer
::
Ptr
&
buf
,
struct
sockaddr
*
addr
,
int
addr_len
)
{
//
设置rtp over udp接收回调处理函数
pRtpSockRef
->
setOnRead
([
peer_ip
,
track_idx
,
weakSelf
](
const
Buffer
::
Ptr
&
buf
,
struct
sockaddr
*
addr
,
int
addr_len
)
{
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
)
{
return
;
...
...
@@ -359,13 +354,13 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
WarnL
<<
"收到其他地址的rtp数据:"
<<
SockUtil
::
inet_ntoa
(
addr
);
return
;
}
strongSelf
->
handleOneRtp
(
track_idx
,
strongSelf
->
_sdp_track
[
track_idx
]
->
_type
,
strongSelf
->
_sdp_track
[
track_idx
]
->
_samplerate
,
(
uint8_t
*
)
buf
->
data
(),
buf
->
size
());
strongSelf
->
handleOneRtp
(
track_idx
,
strongSelf
->
_sdp_track
[
track_idx
]
->
_type
,
strongSelf
->
_sdp_track
[
track_idx
]
->
_samplerate
,
(
uint8_t
*
)
buf
->
data
(),
buf
->
size
());
});
if
(
pRtcpSockRef
)
{
//设置rtcp over udp接收回调处理函数
pRtcpSockRef
->
setOnRead
([
peer_ip
,
track_idx
,
weakSelf
](
const
Buffer
::
Ptr
&
buf
,
struct
sockaddr
*
addr
,
int
addr_len
)
{
if
(
pRtcpSockRef
)
{
//
设置rtcp over udp接收回调处理函数
pRtcpSockRef
->
setOnRead
([
peer_ip
,
track_idx
,
weakSelf
](
const
Buffer
::
Ptr
&
buf
,
struct
sockaddr
*
addr
,
int
addr_len
)
{
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
)
{
return
;
...
...
@@ -374,68 +369,66 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
WarnL
<<
"收到其他地址的rtcp数据:"
<<
SockUtil
::
inet_ntoa
(
addr
);
return
;
}
strongSelf
->
onRtcpPacket
(
track_idx
,
strongSelf
->
_sdp_track
[
track_idx
],
(
uint8_t
*
)
buf
->
data
(),
buf
->
size
());
strongSelf
->
onRtcpPacket
(
track_idx
,
strongSelf
->
_sdp_track
[
track_idx
],
(
uint8_t
*
)
buf
->
data
(),
buf
->
size
());
});
}
}
if
(
track_idx
<
_sdp_track
.
size
()
-
1
)
{
//需要继续发送SETUP命令
//
需要继续发送SETUP命令
sendSetup
(
track_idx
+
1
);
return
;
}
//所有setup命令发送完毕
//发送play命令
//
所有setup命令发送完毕
//
发送play命令
sendPause
(
type_play
,
0
);
}
void
RtspPlayer
::
sendDescribe
()
{
//发送DESCRIBE命令后处理函数:handleResDESCRIBE
//
发送DESCRIBE命令后处理函数:handleResDESCRIBE
_on_response
=
std
::
bind
(
&
RtspPlayer
::
handleResDESCRIBE
,
this
,
placeholders
::
_1
);
sendRtspRequest
(
"DESCRIBE"
,
_play_url
,
{
"Accept"
,
"application/sdp"
});
sendRtspRequest
(
"DESCRIBE"
,
_play_url
,
{
"Accept"
,
"application/sdp"
});
}
void
RtspPlayer
::
sendOptions
(){
_on_response
=
[
this
](
const
Parser
&
parser
)
{
void
RtspPlayer
::
sendOptions
()
{
_on_response
=
[
this
](
const
Parser
&
parser
)
{
if
(
!
handleResponse
(
"OPTIONS"
,
parser
))
{
return
;
}
//获取服务器支持的命令
//
获取服务器支持的命令
_supported_cmd
.
clear
();
auto
public_val
=
split
(
parser
[
"Public"
],
","
);
for
(
auto
&
cmd
:
public_val
)
{
auto
public_val
=
split
(
parser
[
"Public"
],
","
);
for
(
auto
&
cmd
:
public_val
)
{
trim
(
cmd
);
_supported_cmd
.
emplace
(
cmd
);
}
//发送Describe请求,获取sdp
//
发送Describe请求,获取sdp
sendDescribe
();
};
sendRtspRequest
(
"OPTIONS"
,
_play_url
);
}
void
RtspPlayer
::
sendKeepAlive
(){
void
RtspPlayer
::
sendKeepAlive
()
{
_on_response
=
[](
const
Parser
&
parser
)
{};
if
(
_supported_cmd
.
find
(
"GET_PARAMETER"
)
!=
_supported_cmd
.
end
())
{
//支持GET_PARAMETER,用此命令保活
if
(
_supported_cmd
.
find
(
"GET_PARAMETER"
)
!=
_supported_cmd
.
end
())
{
//
支持GET_PARAMETER,用此命令保活
sendRtspRequest
(
"GET_PARAMETER"
,
_content_base
);
}
else
{
//不支持GET_PARAMETER,用OPTIONS命令保活
}
else
{
//
不支持GET_PARAMETER,用OPTIONS命令保活
sendRtspRequest
(
"OPTIONS"
,
_play_url
);
}
}
void
RtspPlayer
::
sendPause
(
int
type
,
uint32_t
seekMS
)
{
void
RtspPlayer
::
sendPause
(
int
type
,
uint32_t
seekMS
)
{
_on_response
=
std
::
bind
(
&
RtspPlayer
::
handleResPAUSE
,
this
,
placeholders
::
_1
,
type
);
//开启或暂停rtsp
switch
(
type
){
case
type_pause
:
sendRtspRequest
(
"PAUSE"
,
_content_base
);
break
;
// 开启或暂停rtsp
switch
(
type
)
{
case
type_pause
:
sendRtspRequest
(
"PAUSE"
,
_content_base
);
break
;
case
type_play
:
sendRtspRequest
(
"PLAY"
,
_content_base
);
break
;
//
sendRtspRequest("PLAY", _content_base);
//
break;
case
type_seek
:
sendRtspRequest
(
"PLAY"
,
_content_base
,
{
"Range"
,
StrPrinter
<<
"npt="
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
2
)
<<
seekMS
/
1000.0
<<
"-"
});
sendRtspRequest
(
"PLAY"
,
_content_base
,
{
"Range"
,
StrPrinter
<<
"npt="
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
2
)
<<
seekMS
/
1000.0
<<
"-"
});
break
;
default
:
WarnL
<<
"unknown type : "
<<
type
;
...
...
@@ -449,35 +442,31 @@ void RtspPlayer::pause(bool bPause) {
}
void
RtspPlayer
::
speed
(
float
speed
)
{
sendRtspRequest
(
"PLAY"
,
_content_base
,
{
"Scale"
,
StrPrinter
<<
speed
});
sendRtspRequest
(
"PLAY"
,
_content_base
,
{
"Scale"
,
StrPrinter
<<
speed
});
}
void
RtspPlayer
::
handleResPAUSE
(
const
Parser
&
parser
,
int
type
)
{
void
RtspPlayer
::
handleResPAUSE
(
const
Parser
&
parser
,
int
type
)
{
if
(
parser
.
Url
()
!=
"200"
)
{
switch
(
type
)
{
case
type_pause
:
WarnL
<<
"Pause failed:"
<<
parser
.
Url
()
<<
" "
<<
parser
.
Tail
()
<<
endl
;
break
;
case
type_pause
:
WarnL
<<
"Pause failed:"
<<
parser
.
Url
()
<<
" "
<<
parser
.
Tail
()
<<
endl
;
break
;
case
type_play
:
WarnL
<<
"Play failed:"
<<
parser
.
Url
()
<<
" "
<<
parser
.
Tail
()
<<
endl
;
onPlayResult_l
(
SockException
(
Err_shutdown
,
StrPrinter
<<
"rtsp play failed:"
<<
parser
.
Url
()
<<
" "
<<
parser
.
Tail
()
),
!
_play_check_timer
);
break
;
case
type_seek
:
WarnL
<<
"Seek failed:"
<<
parser
.
Url
()
<<
" "
<<
parser
.
Tail
()
<<
endl
;
onPlayResult_l
(
SockException
(
Err_shutdown
,
StrPrinter
<<
"rtsp play failed:"
<<
parser
.
Url
()
<<
" "
<<
parser
.
Tail
()),
!
_play_check_timer
);
break
;
case
type_seek
:
WarnL
<<
"Seek failed:"
<<
parser
.
Url
()
<<
" "
<<
parser
.
Tail
()
<<
endl
;
break
;
}
return
;
}
if
(
type
==
type_pause
)
{
//暂停成功!
//
暂停成功!
_rtp_check_timer
.
reset
();
return
;
}
//play或seek成功
//
play或seek成功
uint32_t
iSeekTo
=
0
;
//修正时间轴
//
修正时间轴
auto
strRange
=
parser
[
"Range"
];
if
(
strRange
.
size
())
{
auto
strStart
=
FindField
(
strRange
.
data
(),
"npt="
,
"-"
);
...
...
@@ -495,54 +484,56 @@ void RtspPlayer::onWholeRtspPacket(Parser &parser) {
try
{
decltype
(
_on_response
)
func
;
_on_response
.
swap
(
func
);
if
(
func
)
{
if
(
func
)
{
func
(
parser
);
}
parser
.
Clear
();
}
catch
(
std
::
exception
&
err
)
{
//定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l
(
SockException
(
Err_other
,
err
.
what
()),
!
_play_check_timer
);
//
定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l
(
SockException
(
Err_other
,
err
.
what
()),
!
_play_check_timer
);
}
}
void
RtspPlayer
::
onRtpPacket
(
const
char
*
data
,
size_t
len
)
{
int
trackIdx
=
-
1
;
uint8_t
interleaved
=
data
[
1
];
if
(
interleaved
%
2
==
0
)
{
if
(
interleaved
%
2
==
0
)
{
trackIdx
=
getTrackIndexByInterleaved
(
interleaved
);
if
(
trackIdx
==
-
1
)
{
return
;
}
handleOneRtp
(
trackIdx
,
_sdp_track
[
trackIdx
]
->
_type
,
_sdp_track
[
trackIdx
]
->
_samplerate
,
(
uint8_t
*
)
data
+
RtpPacket
::
kRtpTcpHeaderSize
,
len
-
RtpPacket
::
kRtpTcpHeaderSize
);
}
else
{
handleOneRtp
(
trackIdx
,
_sdp_track
[
trackIdx
]
->
_type
,
_sdp_track
[
trackIdx
]
->
_samplerate
,
(
uint8_t
*
)
data
+
RtpPacket
::
kRtpTcpHeaderSize
,
len
-
RtpPacket
::
kRtpTcpHeaderSize
);
}
else
{
trackIdx
=
getTrackIndexByInterleaved
(
interleaved
-
1
);
if
(
trackIdx
==
-
1
)
{
return
;
}
onRtcpPacket
(
trackIdx
,
_sdp_track
[
trackIdx
],
(
uint8_t
*
)
data
+
RtpPacket
::
kRtpTcpHeaderSize
,
len
-
RtpPacket
::
kRtpTcpHeaderSize
);
onRtcpPacket
(
trackIdx
,
_sdp_track
[
trackIdx
],
(
uint8_t
*
)
data
+
RtpPacket
::
kRtpTcpHeaderSize
,
len
-
RtpPacket
::
kRtpTcpHeaderSize
);
}
}
//此处预留rtcp处理函数
void
RtspPlayer
::
onRtcpPacket
(
int
track_idx
,
SdpTrack
::
Ptr
&
track
,
uint8_t
*
data
,
size_t
len
){
auto
rtcp_arr
=
RtcpHeader
::
loadFromBytes
((
char
*
)
data
,
len
);
//
此处预留rtcp处理函数
void
RtspPlayer
::
onRtcpPacket
(
int
track_idx
,
SdpTrack
::
Ptr
&
track
,
uint8_t
*
data
,
size_t
len
)
{
auto
rtcp_arr
=
RtcpHeader
::
loadFromBytes
((
char
*
)
data
,
len
);
for
(
auto
&
rtcp
:
rtcp_arr
)
{
_rtcp_context
[
track_idx
]
->
onRtcp
(
rtcp
);
if
((
RtcpType
)
rtcp
->
pt
==
RtcpType
::
RTCP_SR
)
{
auto
sr
=
(
RtcpSR
*
)
(
rtcp
);
//设置rtp时间戳与ntp时间戳的对应关系
if
((
RtcpType
)
rtcp
->
pt
==
RtcpType
::
RTCP_SR
)
{
auto
sr
=
(
RtcpSR
*
)(
rtcp
);
//
设置rtp时间戳与ntp时间戳的对应关系
setNtpStamp
(
track_idx
,
sr
->
rtpts
,
sr
->
getNtpUnixStampMS
());
}
}
}
void
RtspPlayer
::
onRtpSorted
(
RtpPacket
::
Ptr
rtppt
,
int
trackidx
){
void
RtspPlayer
::
onRtpSorted
(
RtpPacket
::
Ptr
rtppt
,
int
trackidx
)
{
_stamp
[
trackidx
]
=
rtppt
->
getStampMS
();
_rtp_recv_ticker
.
resetTime
();
onRecvRTP
(
std
::
move
(
rtppt
),
_sdp_track
[
trackidx
]);
}
float
RtspPlayer
::
getPacketLossRate
(
TrackType
type
)
const
{
float
RtspPlayer
::
getPacketLossRate
(
TrackType
type
)
const
{
size_t
lost
=
0
,
expected
=
0
;
try
{
auto
track_idx
=
getTrackIndexByTrackType
(
type
);
...
...
@@ -558,32 +549,32 @@ float RtspPlayer::getPacketLossRate(TrackType type) const{
if
(
!
expected
)
{
return
0
;
}
return
(
float
)
(
double
(
lost
)
/
double
(
expected
));
return
(
float
)(
double
(
lost
)
/
double
(
expected
));
}
uint32_t
RtspPlayer
::
getProgressMilliSecond
()
const
{
return
MAX
(
_stamp
[
0
],
_stamp
[
1
]);
uint32_t
RtspPlayer
::
getProgressMilliSecond
()
const
{
return
MAX
(
_stamp
[
0
],
_stamp
[
1
]);
}
void
RtspPlayer
::
seekToMilliSecond
(
uint32_t
ms
)
{
sendPause
(
type_seek
,
ms
);
sendPause
(
type_seek
,
ms
);
}
void
RtspPlayer
::
sendRtspRequest
(
const
string
&
cmd
,
const
string
&
url
,
const
std
::
initializer_list
<
string
>
&
header
)
{
string
key
;
StrCaseMap
header_map
;
int
i
=
0
;
for
(
auto
&
val
:
header
)
{
if
(
++
i
%
2
==
0
)
{
header_map
.
emplace
(
key
,
val
);
}
else
{
for
(
auto
&
val
:
header
)
{
if
(
++
i
%
2
==
0
)
{
header_map
.
emplace
(
key
,
val
);
}
else
{
key
=
val
;
}
}
sendRtspRequest
(
cmd
,
url
,
header_map
);
sendRtspRequest
(
cmd
,
url
,
header_map
);
}
void
RtspPlayer
::
sendRtspRequest
(
const
string
&
cmd
,
const
string
&
url
,
const
StrCaseMap
&
header_const
)
{
void
RtspPlayer
::
sendRtspRequest
(
const
string
&
cmd
,
const
string
&
url
,
const
StrCaseMap
&
header_const
)
{
auto
header
=
header_const
;
header
.
emplace
(
"CSeq"
,
StrPrinter
<<
_cseq_send
++
);
header
.
emplace
(
"User-Agent"
,
kServerName
);
...
...
@@ -624,44 +615,49 @@ void RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrC
}
_StrPrinter
printer
;
printer
<<
cmd
<<
" "
<<
url
<<
" RTSP/1.0
\r\n
"
;
for
(
auto
&
pr
:
header
){
if
(
cmd
==
"PLAY"
)
{
printer
<<
cmd
<<
" "
<<
_play_url
<<
" RTSP/1.0
\r\n
"
;
}
else
{
printer
<<
cmd
<<
" "
<<
url
<<
" RTSP/1.0
\r\n
"
;
}
for
(
auto
&
pr
:
header
)
{
printer
<<
pr
.
first
<<
": "
<<
pr
.
second
<<
"
\r\n
"
;
}
printer
<<
"
\r\n
"
;
SockSender
::
send
(
std
::
move
(
printer
));
}
void
RtspPlayer
::
onBeforeRtpSorted
(
const
RtpPacket
::
Ptr
&
rtp
,
int
track_idx
){
void
RtspPlayer
::
onBeforeRtpSorted
(
const
RtpPacket
::
Ptr
&
rtp
,
int
track_idx
)
{
auto
&
rtcp_ctx
=
_rtcp_context
[
track_idx
];
rtcp_ctx
->
onRtp
(
rtp
->
getSeq
(),
rtp
->
getStamp
(),
rtp
->
ntp_stamp
,
rtp
->
sample_rate
,
rtp
->
size
()
-
RtpPacket
::
kRtpTcpHeaderSize
);
auto
&
ticker
=
_rtcp_send_ticker
[
track_idx
];
if
(
ticker
.
elapsedTime
()
<
3
*
1000
)
{
//时间未到
//
时间未到
return
;
}
auto
&
rtcp_flag
=
_send_rtcp
[
track_idx
];
//每3秒发送一次心跳,rtcp与rtsp信令轮流心跳,该特性用于兼容issue:642
//有些rtsp服务器需要rtcp保活,有些需要发送信令保活
//
每3秒发送一次心跳,rtcp与rtsp信令轮流心跳,该特性用于兼容issue:642
//
有些rtsp服务器需要rtcp保活,有些需要发送信令保活
//发送信令保活
//
发送信令保活
if
(
!
rtcp_flag
)
{
if
(
track_idx
==
0
)
{
sendKeepAlive
();
}
ticker
.
resetTime
();
//下次发送rtcp保活
//
下次发送rtcp保活
rtcp_flag
=
true
;
return
;
}
//发送rtcp
//
发送rtcp
static
auto
send_rtcp
=
[](
RtspPlayer
*
thiz
,
int
index
,
Buffer
::
Ptr
ptr
)
{
if
(
thiz
->
_rtp_type
==
Rtsp
::
RTP_TCP
)
{
auto
&
track
=
thiz
->
_sdp_track
[
index
];
thiz
->
send
(
makeRtpOverTcpPrefix
((
uint16_t
)
(
ptr
->
size
()),
track
->
_interleaved
+
1
));
thiz
->
send
(
makeRtpOverTcpPrefix
((
uint16_t
)(
ptr
->
size
()),
track
->
_interleaved
+
1
));
thiz
->
send
(
std
::
move
(
ptr
));
}
else
{
thiz
->
_rtcp_sock
[
index
]
->
send
(
std
::
move
(
ptr
));
...
...
@@ -670,39 +666,39 @@ void RtspPlayer::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_idx){
auto
ssrc
=
rtp
->
getSSRC
();
auto
rtcp
=
rtcp_ctx
->
createRtcpRR
(
ssrc
+
1
,
ssrc
);
auto
rtcp_sdes
=
RtcpSdes
::
create
({
kServerName
});
rtcp_sdes
->
chunks
.
type
=
(
uint8_t
)
SdesType
::
RTCP_SDES_CNAME
;
auto
rtcp_sdes
=
RtcpSdes
::
create
({
kServerName
});
rtcp_sdes
->
chunks
.
type
=
(
uint8_t
)
SdesType
::
RTCP_SDES_CNAME
;
rtcp_sdes
->
chunks
.
ssrc
=
htonl
(
ssrc
);
send_rtcp
(
this
,
track_idx
,
std
::
move
(
rtcp
));
send_rtcp
(
this
,
track_idx
,
RtcpHeader
::
toBuffer
(
rtcp_sdes
));
ticker
.
resetTime
();
//下次发送信令保活
//
下次发送信令保活
rtcp_flag
=
false
;
}
void
RtspPlayer
::
onPlayResult_l
(
const
SockException
&
ex
,
bool
handshake_done
)
{
void
RtspPlayer
::
onPlayResult_l
(
const
SockException
&
ex
,
bool
handshake_done
)
{
if
(
ex
.
getErrCode
()
==
Err_shutdown
)
{
//主动shutdown的,不触发回调
//
主动shutdown的,不触发回调
return
;
}
WarnL
<<
ex
.
getErrCode
()
<<
" "
<<
ex
.
what
();
if
(
!
handshake_done
)
{
//开始播放阶段
//
开始播放阶段
_play_check_timer
.
reset
();
onPlayResult
(
ex
);
//是否为性能测试模式
//
是否为性能测试模式
_benchmark_mode
=
(
*
this
)[
Client
::
kBenchmarkMode
].
as
<
int
>
();
}
else
if
(
ex
)
{
//播放成功后异常断开回调
//
播放成功后异常断开回调
onShutdown
(
ex
);
}
else
{
//恢复播放
//
恢复播放
onResume
();
}
if
(
!
ex
)
{
//播放成功,恢复rtp接收超时定时器
//
播放成功,恢复rtp接收超时定时器
_rtp_recv_ticker
.
resetTime
();
auto
timeoutMS
=
(
*
this
)[
Client
::
kMediaTimeoutMS
].
as
<
uint64_t
>
();
weak_ptr
<
RtspPlayer
>
weakSelf
=
static_pointer_cast
<
RtspPlayer
>
(
shared_from_this
());
...
...
@@ -712,13 +708,13 @@ void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshake_done) {
return
false
;
}
if
(
strongSelf
->
_rtp_recv_ticker
.
elapsedTime
()
>
timeoutMS
)
{
//接收rtp媒体数据包超时
//
接收rtp媒体数据包超时
strongSelf
->
onPlayResult_l
(
SockException
(
Err_timeout
,
"receive rtp timeout"
),
true
);
return
false
;
}
return
true
;
};
//创建rtp数据接收超时检测定时器
//
创建rtp数据接收超时检测定时器
_rtp_check_timer
=
std
::
make_shared
<
Timer
>
(
timeoutMS
/
2000.0
f
,
lam
,
getPoller
());
}
else
{
sendTeardown
();
...
...
@@ -752,8 +748,7 @@ int RtspPlayer::getTrackIndexByTrackType(TrackType track_type) const {
///////////////////////////////////////////////////
// RtspPlayerImp
float
RtspPlayerImp
::
getDuration
()
const
{
float
RtspPlayerImp
::
getDuration
()
const
{
return
_demuxer
?
_demuxer
->
getDuration
()
:
0
;
}
...
...
@@ -770,13 +765,11 @@ void RtspPlayerImp::addTrackCompleted() {
}
}
std
::
vector
<
Track
::
Ptr
>
RtspPlayerImp
::
getTracks
(
bool
ready
/*= true*/
)
const
{
std
::
vector
<
Track
::
Ptr
>
RtspPlayerImp
::
getTracks
(
bool
ready
/*= true*/
)
const
{
return
_demuxer
?
_demuxer
->
getTracks
(
ready
)
:
Super
::
getTracks
(
ready
);
}
bool
RtspPlayerImp
::
onCheckSDP
(
const
std
::
string
&
sdp
)
{
bool
RtspPlayerImp
::
onCheckSDP
(
const
std
::
string
&
sdp
)
{
_rtsp_media_src
=
std
::
dynamic_pointer_cast
<
RtspMediaSource
>
(
_media_src
);
if
(
_rtsp_media_src
)
{
_rtsp_media_src
->
setSdp
(
sdp
);
...
...
@@ -788,7 +781,7 @@ bool RtspPlayerImp::onCheckSDP(const std::string &sdp)
}
void
RtspPlayerImp
::
onRecvRTP
(
RtpPacket
::
Ptr
rtp
,
const
SdpTrack
::
Ptr
&
track
)
{
//rtp解复用时可以判断是否为关键帧起始位置
//
rtp解复用时可以判断是否为关键帧起始位置
auto
key_pos
=
_demuxer
->
inputRtp
(
rtp
);
if
(
_rtsp_media_src
)
{
_rtsp_media_src
->
onWrite
(
std
::
move
(
rtp
),
key_pos
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论