Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
2014-03-18 11:32:58 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
c85dde7f3ffa1c49105cce83507613cdd0ecdec9
c85dde7f
1 parent
e5770b10
substitute all TAB with 4spaces.
隐藏空白字符变更
内嵌
并排对比
正在显示
5 个修改的文件
包含
1498 行增加
和
1498 行删除
trunk/src/app/srs_app_bandwidth.cpp
trunk/src/app/srs_app_client.cpp
trunk/src/app/srs_app_client.hpp
trunk/src/app/srs_app_codec.cpp
trunk/src/app/srs_app_codec.hpp
要显示太多修改。
重新载入完整差异
差异文件
邮件补丁
为保证性能只显示
5 of 5+
个文件。
trunk/src/app/srs_app_bandwidth.cpp
查看文件 @
c85dde7
...
...
@@ -45,28 +45,28 @@ SrsBandwidth::~SrsBandwidth()
int
SrsBandwidth
::
bandwidth_test
(
SrsRequest
*
_req
,
st_netfd_t
stfd
,
SrsRtmpServer
*
_rtmp
)
{
int
ret
=
ERROR_SUCCESS
;
rtmp
=
_rtmp
;
req
=
_req
;
if
(
!
_srs_config
->
get_bw_check_enabled
(
req
->
vhost
))
{
return
ret
;
}
// validate the bandwidth check key
std
::
string
key
=
"key="
+
_srs_config
->
get_bw_check_key
(
req
->
vhost
);
if
(
req
->
tcUrl
.
find
(
key
)
==
std
::
string
::
npos
)
{
ret
=
ERROR_SYSTEM_BANDWIDTH_KEY
;
srs_error
(
"check the vhost=%s %s failed, tcUrl=%s, ret=%d"
,
req
->
vhost
.
c_str
(),
key
.
c_str
(),
req
->
tcUrl
.
c_str
(),
ret
);
return
ret
;
}
// shared global last check time,
// to avoid attach by bandwidth check,
// if client request check in the window(specifeid by interval),
// directly reject the request.
int
ret
=
ERROR_SUCCESS
;
rtmp
=
_rtmp
;
req
=
_req
;
if
(
!
_srs_config
->
get_bw_check_enabled
(
req
->
vhost
))
{
return
ret
;
}
// validate the bandwidth check key
std
::
string
key
=
"key="
+
_srs_config
->
get_bw_check_key
(
req
->
vhost
);
if
(
req
->
tcUrl
.
find
(
key
)
==
std
::
string
::
npos
)
{
ret
=
ERROR_SYSTEM_BANDWIDTH_KEY
;
srs_error
(
"check the vhost=%s %s failed, tcUrl=%s, ret=%d"
,
req
->
vhost
.
c_str
(),
key
.
c_str
(),
req
->
tcUrl
.
c_str
(),
ret
);
return
ret
;
}
// shared global last check time,
// to avoid attach by bandwidth check,
// if client request check in the window(specifeid by interval),
// directly reject the request.
static
int64_t
last_check_time
=
0
;
int
interval_ms
=
_srs_config
->
get_bw_check_interval_ms
(
req
->
vhost
);
...
...
@@ -75,16 +75,16 @@ int SrsBandwidth::bandwidth_test(SrsRequest* _req, st_netfd_t stfd, SrsRtmpServe
if
(
last_check_time
>
0
&&
time_now
-
last_check_time
<
interval_ms
)
{
ret
=
ERROR_SYSTEM_BANDWIDTH_DENIED
;
srs_trace
(
"bandcheck denied, "
"last_check=%"
PRId64
", now=%"
PRId64
", interval=%d"
,
last_check_time
,
time_now
,
interval_ms
);
"last_check=%"
PRId64
", now=%"
PRId64
", interval=%d"
,
last_check_time
,
time_now
,
interval_ms
);
rtmp
->
response_connect_reject
(
req
,
"bandcheck rejected"
);
return
ret
;
}
// accept and do bandwidth check.
last_check_time
=
time_now
;
last_check_time
=
time_now
;
char
*
local_ip
=
0
;
if
((
ret
=
get_local_ip
(
stfd
,
local_ip
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"get local ip failed. ret = %d"
,
ret
);
...
...
@@ -137,7 +137,7 @@ int SrsBandwidth::do_bandwidth_check()
{
int
ret
=
ERROR_SUCCESS
;
SrsProtocol
*
protocol
=
rtmp
->
get_protocol
();
SrsProtocol
*
protocol
=
rtmp
->
get_protocol
();
int
play_duration_ms
=
3000
;
int
play_interval_ms
=
0
;
...
...
@@ -154,14 +154,14 @@ int SrsBandwidth::do_bandwidth_check()
int64_t
start_time
=
srs_get_system_time_ms
();
ret
=
check_play
(
play_duration_ms
,
play_interval_ms
,
play_actual_duration_ms
,
play_bytes
,
limit_kbps
);
play_interval_ms
,
play_actual_duration_ms
,
play_bytes
,
limit_kbps
);
if
(
ret
!=
ERROR_SUCCESS
)
{
srs_error
(
"band width play check failed. ret=%d"
,
ret
);
return
ret
;
}
ret
=
check_publish
(
publish_duration_ms
,
publish_interval_ms
,
publish_actual_duration_ms
,
publish_bytes
,
limit_kbps
);
publish_interval_ms
,
publish_actual_duration_ms
,
publish_bytes
,
limit_kbps
);
if
(
ret
!=
ERROR_SUCCESS
)
{
srs_error
(
"band width publish check failed. ret=%d"
,
ret
);
return
ret
;
...
...
@@ -188,29 +188,29 @@ int SrsBandwidth::do_bandwidth_check()
pkt
->
data
->
set
(
"publish_bytes"
,
SrsAmf0Any
::
number
(
publish_bytes
));
pkt
->
data
->
set
(
"publish_time"
,
SrsAmf0Any
::
number
(
publish_actual_duration_ms
));
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check finish message failed. ret=%d"
,
ret
);
return
ret
;
}
// if flash, we notice the result, and expect a final packet.
while
(
true
)
{
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
// info level to ignore and return success.
srs_info
(
"expect final message failed. ret=%d"
,
ret
);
return
ERROR_SUCCESS
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get final message success."
);
if
(
pkt
->
is_flash_final
())
{
srs_info
(
"BW check recv flash final response."
);
break
;
}
}
while
(
true
)
{
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
// info level to ignore and return success.
srs_info
(
"expect final message failed. ret=%d"
,
ret
);
return
ERROR_SUCCESS
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get final message success."
);
if
(
pkt
->
is_flash_final
())
{
srs_info
(
"BW check recv flash final response."
);
break
;
}
}
srs_info
(
"BW check finished."
);
...
...
@@ -218,44 +218,44 @@ int SrsBandwidth::do_bandwidth_check()
}
int
SrsBandwidth
::
check_play
(
int
duration_ms
,
int
interval_ms
,
int
&
actual_duration_ms
,
int
&
play_bytes
,
int
max_play_kbps
)
int
duration_ms
,
int
interval_ms
,
int
&
actual_duration_ms
,
int
&
play_bytes
,
int
max_play_kbps
)
{
int
ret
=
ERROR_SUCCESS
;
SrsProtocol
*
protocol
=
rtmp
->
get_protocol
();
if
(
true
)
{
// send start play command to client
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_start_play
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check start play message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check begin."
);
}
while
(
true
)
{
// recv client's starting play response
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_starting_play
())
{
srs_info
(
"BW check recv play begin response."
);
break
;
}
}
SrsProtocol
*
protocol
=
rtmp
->
get_protocol
();
if
(
true
)
{
// send start play command to client
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_start_play
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check start play message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check begin."
);
}
while
(
true
)
{
// recv client's starting play response
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_starting_play
())
{
srs_info
(
"BW check recv play begin response."
);
break
;
}
}
// send play data to client
int64_t
current_time
=
srs_get_system_time_ms
();
...
...
@@ -280,10 +280,10 @@ int SrsBandwidth::check_play(
}
data_count
+=
2
;
// TODO: FIXME: get length from the rtmp protocol stack.
// TODO: FIXME: get length from the rtmp protocol stack.
play_bytes
+=
pkt
->
get_payload_length
();
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check play messages failed. ret=%d"
,
ret
);
return
ret
;
...
...
@@ -305,81 +305,81 @@ int SrsBandwidth::check_play(
actual_duration_ms
=
srs_get_system_time_ms
()
-
current_time
;
srs_info
(
"BW check send play bytes over."
);
if
(
true
)
{
// notify client to stop play
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_stop_play
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
pkt
->
data
->
set
(
"duration_delta"
,
SrsAmf0Any
::
number
(
actual_duration_ms
));
pkt
->
data
->
set
(
"bytes_delta"
,
SrsAmf0Any
::
number
(
play_bytes
));
if
(
true
)
{
// notify client to stop play
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_stop_play
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
pkt
->
data
->
set
(
"duration_delta"
,
SrsAmf0Any
::
number
(
actual_duration_ms
));
pkt
->
data
->
set
(
"bytes_delta"
,
SrsAmf0Any
::
number
(
play_bytes
));
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check stop play message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check stop play bytes."
);
}
while
(
true
)
{
// recv client's stop play response.
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_stopped_play
())
{
srs_info
(
"BW check recv stop play response."
);
break
;
}
}
srs_error
(
"send bandwidth check stop play message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check stop play bytes."
);
}
while
(
true
)
{
// recv client's stop play response.
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_stopped_play
())
{
srs_info
(
"BW check recv stop play response."
);
break
;
}
}
return
ret
;
}
int
SrsBandwidth
::
check_publish
(
int
duration_ms
,
int
interval_ms
,
int
&
actual_duration_ms
,
int
&
publish_bytes
,
int
max_pub_kbps
)
int
duration_ms
,
int
interval_ms
,
int
&
actual_duration_ms
,
int
&
publish_bytes
,
int
max_pub_kbps
)
{
int
ret
=
ERROR_SUCCESS
;
SrsProtocol
*
protocol
=
rtmp
->
get_protocol
();
if
(
true
)
{
// notify client to start publish
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_start_publish
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check start publish message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check publish begin."
);
}
while
(
true
)
{
// read client's notification of starting publish
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_starting_publish
())
{
srs_info
(
"BW check recv publish begin response."
);
break
;
}
}
SrsProtocol
*
protocol
=
rtmp
->
get_protocol
();
if
(
true
)
{
// notify client to start publish
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_start_publish
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check start publish message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check publish begin."
);
}
while
(
true
)
{
// read client's notification of starting publish
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_starting_publish
())
{
srs_info
(
"BW check recv publish begin response."
);
break
;
}
}
// recv publish msgs until @duration_ms ms
int64_t
current_time
=
srs_get_system_time_ms
();
...
...
@@ -393,7 +393,7 @@ int SrsBandwidth::check_publish(
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
// TODO: FIXME.
// TODO: FIXME.
publish_bytes
+=
msg
->
header
.
payload_length
;
int
kbps
=
0
;
...
...
@@ -411,21 +411,21 @@ int SrsBandwidth::check_publish(
actual_duration_ms
=
srs_get_system_time_ms
()
-
current_time
;
srs_info
(
"BW check recv publish data over."
);
if
(
true
)
{
// notify client to stop publish
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_stop_publish
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
pkt
->
data
->
set
(
"duration_delta"
,
SrsAmf0Any
::
number
(
actual_duration_ms
));
pkt
->
data
->
set
(
"bytes_delta"
,
SrsAmf0Any
::
number
(
publish_bytes
));
if
(
true
)
{
// notify client to stop publish
SrsBandwidthPacket
*
pkt
=
SrsBandwidthPacket
::
create_stop_publish
();
pkt
->
data
->
set
(
"duration_ms"
,
SrsAmf0Any
::
number
(
duration_ms
));
pkt
->
data
->
set
(
"interval_ms"
,
SrsAmf0Any
::
number
(
interval_ms
));
pkt
->
data
->
set
(
"duration_delta"
,
SrsAmf0Any
::
number
(
actual_duration_ms
));
pkt
->
data
->
set
(
"bytes_delta"
,
SrsAmf0Any
::
number
(
publish_bytes
));
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
SrsCommonMessage
*
msg
=
(
new
SrsCommonMessage
())
->
set_packet
(
pkt
,
0
);
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send bandwidth check stop publish message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check stop publish bytes."
);
}
srs_error
(
"send bandwidth check stop publish message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"BW check stop publish bytes."
);
}
// expect client to stop publish
// if flash client, we never expect the client stop publish bytes,
...
...
@@ -433,22 +433,22 @@ int SrsBandwidth::check_publish(
// there are many many packets in the queue.
// we just ignore the packet and send the bandwidth test data.
// TODO: FIXME: check whether flash client.
while
(
false
)
{
// recv client's stop publish response.
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_stopped_publish
())
{
srs_info
(
"BW check recv stop publish response."
);
break
;
}
}
while
(
false
)
{
// recv client's stop publish response.
SrsCommonMessage
*
msg
=
NULL
;
SrsBandwidthPacket
*
pkt
=
NULL
;
if
((
ret
=
srs_rtmp_expect_message
<
SrsBandwidthPacket
>
(
protocol
,
&
msg
,
&
pkt
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"expect bandwidth message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
srs_info
(
"get bandwidth message succes."
);
if
(
pkt
->
is_stopped_publish
())
{
srs_info
(
"BW check recv stop publish response."
);
break
;
}
}
return
ret
;
}
...
...
trunk/src/app/srs_app_client.cpp
查看文件 @
c85dde7
...
...
@@ -44,603 +44,603 @@ using namespace std;
#include <srs_app_socket.hpp>
SrsClient
::
SrsClient
(
SrsServer
*
srs_server
,
st_netfd_t
client_stfd
)
:
SrsConnection
(
srs_server
,
client_stfd
)
:
SrsConnection
(
srs_server
,
client_stfd
)
{
ip
=
NULL
;
req
=
new
SrsRequest
();
res
=
new
SrsResponse
();
skt
=
new
SrsSocket
(
client_stfd
);
rtmp
=
new
SrsRtmpServer
(
skt
);
refer
=
new
SrsRefer
();
#ifdef SRS_HTTP_CALLBACK
http_hooks
=
new
SrsHttpHooks
();
ip
=
NULL
;
req
=
new
SrsRequest
();
res
=
new
SrsResponse
();
skt
=
new
SrsSocket
(
client_stfd
);
rtmp
=
new
SrsRtmpServer
(
skt
);
refer
=
new
SrsRefer
();
#ifdef SRS_HTTP_CALLBACK
http_hooks
=
new
SrsHttpHooks
();
#endif
bandwidth
=
new
SrsBandwidth
();
_srs_config
->
subscribe
(
this
);
bandwidth
=
new
SrsBandwidth
();
_srs_config
->
subscribe
(
this
);
}
SrsClient
::~
SrsClient
()
{
_srs_config
->
unsubscribe
(
this
);
srs_freepa
(
ip
);
srs_freep
(
req
);
srs_freep
(
res
);
srs_freep
(
rtmp
);
srs_freep
(
skt
);
srs_freep
(
refer
);
#ifdef SRS_HTTP_CALLBACK
srs_freep
(
http_hooks
);
_srs_config
->
unsubscribe
(
this
);
srs_freepa
(
ip
);
srs_freep
(
req
);
srs_freep
(
res
);
srs_freep
(
rtmp
);
srs_freep
(
skt
);
srs_freep
(
refer
);
#ifdef SRS_HTTP_CALLBACK
srs_freep
(
http_hooks
);
#endif
srs_freep
(
bandwidth
);
srs_freep
(
bandwidth
);
}
// TODO: return detail message when error for client.
int
SrsClient
::
do_cycle
()
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
get_peer_ip
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"get peer ip failed. ret=%d"
,
ret
);
return
ret
;
}
srs_trace
(
"get peer ip success. ip=%s, send_to=%"
PRId64
", recv_to=%"
PRId64
""
,
ip
,
SRS_SEND_TIMEOUT_US
,
SRS_RECV_TIMEOUT_US
);
rtmp
->
set_recv_timeout
(
SRS_RECV_TIMEOUT_US
);
rtmp
->
set_send_timeout
(
SRS_SEND_TIMEOUT_US
);
if
((
ret
=
rtmp
->
handshake
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtmp handshake failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"rtmp handshake success"
);
if
((
ret
=
rtmp
->
connect_app
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtmp connect vhost/app failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"rtmp connect app success"
);
// discovery vhost, resolve the vhost from config
SrsConfDirective
*
parsed_vhost
=
_srs_config
->
get_vhost
(
req
->
vhost
);
if
(
parsed_vhost
)
{
req
->
vhost
=
parsed_vhost
->
arg0
();
}
srs_info
(
"discovery app success. schema=%s, vhost=%s, port=%s, app=%s"
,
req
->
schema
.
c_str
(),
req
->
vhost
.
c_str
(),
req
->
port
.
c_str
(),
req
->
app
.
c_str
());
if
(
req
->
schema
.
empty
()
||
req
->
vhost
.
empty
()
||
req
->
port
.
empty
()
||
req
->
app
.
empty
())
{
ret
=
ERROR_RTMP_REQ_TCURL
;
srs_error
(
"discovery tcUrl failed. "
"tcUrl=%s, schema=%s, vhost=%s, port=%s, app=%s, ret=%d"
,
req
->
tcUrl
.
c_str
(),
req
->
schema
.
c_str
(),
req
->
vhost
.
c_str
(),
req
->
port
.
c_str
(),
req
->
app
.
c_str
(),
ret
);
return
ret
;
}
// check vhost
if
((
ret
=
check_vhost
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"check vhost failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"check vhost success."
);
srs_trace
(
"rtmp connect app success. "
"tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s"
,
req
->
tcUrl
.
c_str
(),
req
->
pageUrl
.
c_str
(),
req
->
swfUrl
.
c_str
(),
req
->
schema
.
c_str
(),
req
->
vhost
.
c_str
(),
req
->
port
.
c_str
(),
req
->
app
.
c_str
());
ret
=
service_cycle
();
on_close
();
return
ret
;
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
get_peer_ip
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"get peer ip failed. ret=%d"
,
ret
);
return
ret
;
}
srs_trace
(
"get peer ip success. ip=%s, send_to=%"
PRId64
", recv_to=%"
PRId64
""
,
ip
,
SRS_SEND_TIMEOUT_US
,
SRS_RECV_TIMEOUT_US
);
rtmp
->
set_recv_timeout
(
SRS_RECV_TIMEOUT_US
);
rtmp
->
set_send_timeout
(
SRS_SEND_TIMEOUT_US
);
if
((
ret
=
rtmp
->
handshake
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtmp handshake failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"rtmp handshake success"
);
if
((
ret
=
rtmp
->
connect_app
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtmp connect vhost/app failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"rtmp connect app success"
);
// discovery vhost, resolve the vhost from config
SrsConfDirective
*
parsed_vhost
=
_srs_config
->
get_vhost
(
req
->
vhost
);
if
(
parsed_vhost
)
{
req
->
vhost
=
parsed_vhost
->
arg0
();
}
srs_info
(
"discovery app success. schema=%s, vhost=%s, port=%s, app=%s"
,
req
->
schema
.
c_str
(),
req
->
vhost
.
c_str
(),
req
->
port
.
c_str
(),
req
->
app
.
c_str
());
if
(
req
->
schema
.
empty
()
||
req
->
vhost
.
empty
()
||
req
->
port
.
empty
()
||
req
->
app
.
empty
())
{
ret
=
ERROR_RTMP_REQ_TCURL
;
srs_error
(
"discovery tcUrl failed. "
"tcUrl=%s, schema=%s, vhost=%s, port=%s, app=%s, ret=%d"
,
req
->
tcUrl
.
c_str
(),
req
->
schema
.
c_str
(),
req
->
vhost
.
c_str
(),
req
->
port
.
c_str
(),
req
->
app
.
c_str
(),
ret
);
return
ret
;
}
// check vhost
if
((
ret
=
check_vhost
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"check vhost failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"check vhost success."
);
srs_trace
(
"rtmp connect app success. "
"tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s"
,
req
->
tcUrl
.
c_str
(),
req
->
pageUrl
.
c_str
(),
req
->
swfUrl
.
c_str
(),
req
->
schema
.
c_str
(),
req
->
vhost
.
c_str
(),
req
->
port
.
c_str
(),
req
->
app
.
c_str
());
ret
=
service_cycle
();
on_close
();
return
ret
;
}
int
SrsClient
::
on_reload_vhost_removed
(
string
vhost
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
req
->
vhost
!=
vhost
)
{
return
ret
;
}
// if the vhost connected is removed, disconnect the client.
srs_trace
(
"vhost %s removed/disabled, close client url=%s"
,
vhost
.
c_str
(),
req
->
get_stream_url
().
c_str
());
srs_close_stfd
(
stfd
);
return
ret
;
int
ret
=
ERROR_SUCCESS
;
if
(
req
->
vhost
!=
vhost
)
{
return
ret
;
}
// if the vhost connected is removed, disconnect the client.
srs_trace
(
"vhost %s removed/disabled, close client url=%s"
,
vhost
.
c_str
(),
req
->
get_stream_url
().
c_str
());
srs_close_stfd
(
stfd
);
return
ret
;
}
int
SrsClient
::
service_cycle
()
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
rtmp
->
set_window_ack_size
(
2.5
*
1000
*
1000
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"set window acknowledgement size failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"set window acknowledgement size success"
);
if
((
ret
=
rtmp
->
set_peer_bandwidth
(
2.5
*
1000
*
1000
,
2
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"set peer bandwidth failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"set peer bandwidth success"
);
// do bandwidth test if connect to the vhost which is for bandwidth check.
if
(
_srs_config
->
get_bw_check_enabled
(
req
->
vhost
))
{
return
bandwidth
->
bandwidth_test
(
req
,
stfd
,
rtmp
);
}
if
((
ret
=
rtmp
->
response_connect_app
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"response connect app failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"response connect app success"
);
if
((
ret
=
rtmp
->
on_bw_done
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"on_bw_done failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"on_bw_done success"
);
while
(
true
)
{
ret
=
stream_service_cycle
();
// stream service must terminated with error, never success.
srs_assert
(
ret
!=
ERROR_SUCCESS
);
// when not system control error, fatal error, return.
if
(
!
srs_is_system_control_error
(
ret
))
{
if
(
ret
!=
ERROR_SOCKET_TIMEOUT
&&
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"stream service cycle failed. ret=%d"
,
ret
);
}
return
ret
;
}
// for republish, continue service
if
(
ret
==
ERROR_CONTROL_REPUBLISH
)
{
// set timeout to a larger value, wait for encoder to republish.
rtmp
->
set_send_timeout
(
SRS_REPUBLISH_RECV_TIMEOUT_US
);
rtmp
->
set_recv_timeout
(
SRS_REPUBLISH_SEND_TIMEOUT_US
);
srs_trace
(
"control message(unpublish) accept, retry stream service."
);
continue
;
}
// for "some" system control error,
// logical accept and retry stream service.
if
(
ret
==
ERROR_CONTROL_RTMP_CLOSE
)
{
// set timeout to a larger value, for user paused.
rtmp
->
set_recv_timeout
(
SRS_PAUSED_RECV_TIMEOUT_US
);
rtmp
->
set_send_timeout
(
SRS_PAUSED_SEND_TIMEOUT_US
);
srs_trace
(
"control message(close) accept, retry stream service."
);
continue
;
}
// for other system control message, fatal error.
srs_error
(
"control message(%d) reject as error. ret=%d"
,
ret
,
ret
);
return
ret
;
}
return
ret
;
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
rtmp
->
set_window_ack_size
(
2.5
*
1000
*
1000
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"set window acknowledgement size failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"set window acknowledgement size success"
);
if
((
ret
=
rtmp
->
set_peer_bandwidth
(
2.5
*
1000
*
1000
,
2
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"set peer bandwidth failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"set peer bandwidth success"
);
// do bandwidth test if connect to the vhost which is for bandwidth check.
if
(
_srs_config
->
get_bw_check_enabled
(
req
->
vhost
))
{
return
bandwidth
->
bandwidth_test
(
req
,
stfd
,
rtmp
);
}
if
((
ret
=
rtmp
->
response_connect_app
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"response connect app failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"response connect app success"
);
if
((
ret
=
rtmp
->
on_bw_done
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"on_bw_done failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"on_bw_done success"
);
while
(
true
)
{
ret
=
stream_service_cycle
();
// stream service must terminated with error, never success.
srs_assert
(
ret
!=
ERROR_SUCCESS
);
// when not system control error, fatal error, return.
if
(
!
srs_is_system_control_error
(
ret
))
{
if
(
ret
!=
ERROR_SOCKET_TIMEOUT
&&
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"stream service cycle failed. ret=%d"
,
ret
);
}
return
ret
;
}
// for republish, continue service
if
(
ret
==
ERROR_CONTROL_REPUBLISH
)
{
// set timeout to a larger value, wait for encoder to republish.
rtmp
->
set_send_timeout
(
SRS_REPUBLISH_RECV_TIMEOUT_US
);
rtmp
->
set_recv_timeout
(
SRS_REPUBLISH_SEND_TIMEOUT_US
);
srs_trace
(
"control message(unpublish) accept, retry stream service."
);
continue
;
}
// for "some" system control error,
// logical accept and retry stream service.
if
(
ret
==
ERROR_CONTROL_RTMP_CLOSE
)
{
// set timeout to a larger value, for user paused.
rtmp
->
set_recv_timeout
(
SRS_PAUSED_RECV_TIMEOUT_US
);
rtmp
->
set_send_timeout
(
SRS_PAUSED_SEND_TIMEOUT_US
);
srs_trace
(
"control message(close) accept, retry stream service."
);
continue
;
}
// for other system control message, fatal error.
srs_error
(
"control message(%d) reject as error. ret=%d"
,
ret
,
ret
);
return
ret
;
}
return
ret
;
}
int
SrsClient
::
stream_service_cycle
()
{
int
ret
=
ERROR_SUCCESS
;
SrsClientType
type
;
if
((
ret
=
rtmp
->
identify_client
(
res
->
stream_id
,
type
,
req
->
stream
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"identify client failed. ret=%d"
,
ret
);
return
ret
;
}
req
->
strip
();
srs_trace
(
"identify client success. type=%s, stream_name=%s"
,
srs_client_type_string
(
type
).
c_str
(),
req
->
stream
.
c_str
());
// client is identified, set the timeout to service timeout.
rtmp
->
set_recv_timeout
(
SRS_RECV_TIMEOUT_US
);
rtmp
->
set_send_timeout
(
SRS_SEND_TIMEOUT_US
);
// set chunk size to larger.
int
ret
=
ERROR_SUCCESS
;
SrsClientType
type
;
if
((
ret
=
rtmp
->
identify_client
(
res
->
stream_id
,
type
,
req
->
stream
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"identify client failed. ret=%d"
,
ret
);
return
ret
;
}
req
->
strip
();
srs_trace
(
"identify client success. type=%s, stream_name=%s"
,
srs_client_type_string
(
type
).
c_str
(),
req
->
stream
.
c_str
());
// client is identified, set the timeout to service timeout.
rtmp
->
set_recv_timeout
(
SRS_RECV_TIMEOUT_US
);
rtmp
->
set_send_timeout
(
SRS_SEND_TIMEOUT_US
);
// set chunk size to larger.
int
chunk_size
=
_srs_config
->
get_chunk_size
(
req
->
vhost
);
if
((
ret
=
rtmp
->
set_chunk_size
(
chunk_size
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"set chunk_size=%d failed. ret=%d"
,
chunk_size
,
ret
);
return
ret
;
}
srs_trace
(
"set chunk_size=%d success"
,
chunk_size
);
// find a source to serve.
SrsSource
*
source
=
SrsSource
::
find
(
req
);
srs_assert
(
source
!=
NULL
);
// check publish available.
if
(
type
!=
SrsClientPlay
&&
!
source
->
can_publish
())
{
ret
=
ERROR_SYSTEM_STREAM_BUSY
;
srs_warn
(
"stream %s is already publishing. ret=%d"
,
req
->
get_stream_url
().
c_str
(),
ret
);
// to delay request
st_usleep
(
SRS_STREAM_BUSY_SLEEP_US
);
return
ret
;
}
bool
enabled_cache
=
_srs_config
->
get_gop_cache
(
req
->
vhost
);
srs_info
(
"source found, url=%s, enabled_cache=%d"
,
req
->
get_stream_url
().
c_str
(),
enabled_cache
);
source
->
set_cache
(
enabled_cache
);
switch
(
type
)
{
case
SrsClientPlay
:
{
srs_verbose
(
"start to play stream %s."
,
req
->
stream
.
c_str
());
if
((
ret
=
rtmp
->
start_play
(
res
->
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"start to play stream failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
on_play
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"http hook on_play failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"start to play stream %s success"
,
req
->
stream
.
c_str
());
ret
=
playing
(
source
);
on_stop
();
return
ret
;
}
case
SrsClientFMLEPublish
:
{
srs_verbose
(
"FMLE start to publish stream %s."
,
req
->
stream
.
c_str
());
if
((
ret
=
rtmp
->
start_fmle_publish
(
res
->
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"start to publish stream failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
on_publish
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"http hook on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"start to publish stream %s success"
,
req
->
stream
.
c_str
());
ret
=
fmle_publish
(
source
);
source
->
on_unpublish
();
on_unpublish
();
return
ret
;
}
case
SrsClientFlashPublish
:
{
srs_verbose
(
"flash start to publish stream %s."
,
req
->
stream
.
c_str
());
if
((
ret
=
rtmp
->
start_flash_publish
(
res
->
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash start to publish stream failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
on_publish
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"http hook on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"flash start to publish stream %s success"
,
req
->
stream
.
c_str
());
ret
=
flash_publish
(
source
);
source
->
on_unpublish
();
on_unpublish
();
return
ret
;
}
default
:
{
ret
=
ERROR_SYSTEM_CLIENT_INVALID
;
srs_info
(
"invalid client type=%d. ret=%d"
,
type
,
ret
);
return
ret
;
}
}
return
ret
;
if
((
ret
=
rtmp
->
set_chunk_size
(
chunk_size
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"set chunk_size=%d failed. ret=%d"
,
chunk_size
,
ret
);
return
ret
;
}
srs_trace
(
"set chunk_size=%d success"
,
chunk_size
);
// find a source to serve.
SrsSource
*
source
=
SrsSource
::
find
(
req
);
srs_assert
(
source
!=
NULL
);
// check publish available.
if
(
type
!=
SrsClientPlay
&&
!
source
->
can_publish
())
{
ret
=
ERROR_SYSTEM_STREAM_BUSY
;
srs_warn
(
"stream %s is already publishing. ret=%d"
,
req
->
get_stream_url
().
c_str
(),
ret
);
// to delay request
st_usleep
(
SRS_STREAM_BUSY_SLEEP_US
);
return
ret
;
}
bool
enabled_cache
=
_srs_config
->
get_gop_cache
(
req
->
vhost
);
srs_info
(
"source found, url=%s, enabled_cache=%d"
,
req
->
get_stream_url
().
c_str
(),
enabled_cache
);
source
->
set_cache
(
enabled_cache
);
switch
(
type
)
{
case
SrsClientPlay
:
{
srs_verbose
(
"start to play stream %s."
,
req
->
stream
.
c_str
());
if
((
ret
=
rtmp
->
start_play
(
res
->
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"start to play stream failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
on_play
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"http hook on_play failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"start to play stream %s success"
,
req
->
stream
.
c_str
());
ret
=
playing
(
source
);
on_stop
();
return
ret
;
}
case
SrsClientFMLEPublish
:
{
srs_verbose
(
"FMLE start to publish stream %s."
,
req
->
stream
.
c_str
());
if
((
ret
=
rtmp
->
start_fmle_publish
(
res
->
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"start to publish stream failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
on_publish
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"http hook on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"start to publish stream %s success"
,
req
->
stream
.
c_str
());
ret
=
fmle_publish
(
source
);
source
->
on_unpublish
();
on_unpublish
();
return
ret
;
}
case
SrsClientFlashPublish
:
{
srs_verbose
(
"flash start to publish stream %s."
,
req
->
stream
.
c_str
());
if
((
ret
=
rtmp
->
start_flash_publish
(
res
->
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash start to publish stream failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
on_publish
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"http hook on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"flash start to publish stream %s success"
,
req
->
stream
.
c_str
());
ret
=
flash_publish
(
source
);
source
->
on_unpublish
();
on_unpublish
();
return
ret
;
}
default
:
{
ret
=
ERROR_SYSTEM_CLIENT_INVALID
;
srs_info
(
"invalid client type=%d. ret=%d"
,
type
,
ret
);
return
ret
;
}
}
return
ret
;
}
int
SrsClient
::
check_vhost
()
{
int
ret
=
ERROR_SUCCESS
;
srs_assert
(
req
!=
NULL
);
SrsConfDirective
*
vhost
=
_srs_config
->
get_vhost
(
req
->
vhost
);
if
(
vhost
==
NULL
)
{
ret
=
ERROR_RTMP_VHOST_NOT_FOUND
;
srs_error
(
"vhost %s not found. ret=%d"
,
req
->
vhost
.
c_str
(),
ret
);
return
ret
;
}
if
(
!
_srs_config
->
get_vhost_enabled
(
req
->
vhost
))
{
ret
=
ERROR_RTMP_VHOST_NOT_FOUND
;
srs_error
(
"vhost %s disabled. ret=%d"
,
req
->
vhost
.
c_str
(),
ret
);
return
ret
;
}
if
(
req
->
vhost
!=
vhost
->
arg0
())
{
srs_trace
(
"vhost change from %s to %s"
,
req
->
vhost
.
c_str
(),
vhost
->
arg0
().
c_str
());
req
->
vhost
=
vhost
->
arg0
();
}
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"check refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"check refer success."
);
if
((
ret
=
on_connect
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
int
ret
=
ERROR_SUCCESS
;
srs_assert
(
req
!=
NULL
);
SrsConfDirective
*
vhost
=
_srs_config
->
get_vhost
(
req
->
vhost
);
if
(
vhost
==
NULL
)
{
ret
=
ERROR_RTMP_VHOST_NOT_FOUND
;
srs_error
(
"vhost %s not found. ret=%d"
,
req
->
vhost
.
c_str
(),
ret
);
return
ret
;
}
if
(
!
_srs_config
->
get_vhost_enabled
(
req
->
vhost
))
{
ret
=
ERROR_RTMP_VHOST_NOT_FOUND
;
srs_error
(
"vhost %s disabled. ret=%d"
,
req
->
vhost
.
c_str
(),
ret
);
return
ret
;
}
if
(
req
->
vhost
!=
vhost
->
arg0
())
{
srs_trace
(
"vhost change from %s to %s"
,
req
->
vhost
.
c_str
(),
vhost
->
arg0
().
c_str
());
req
->
vhost
=
vhost
->
arg0
();
}
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"check refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"check refer success."
);
if
((
ret
=
on_connect
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
int
SrsClient
::
playing
(
SrsSource
*
source
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer_play
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"check play_refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"check play_refer success."
);
SrsConsumer
*
consumer
=
NULL
;
if
((
ret
=
source
->
create_consumer
(
consumer
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"create consumer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_assert
(
consumer
!=
NULL
);
SrsAutoFree
(
SrsConsumer
,
consumer
,
false
);
srs_verbose
(
"consumer created success."
);
rtmp
->
set_recv_timeout
(
SRS_PULSE_TIMEOUT_US
);
SrsPithyPrint
pithy_print
(
SRS_STAGE_PLAY_USER
);
while
(
true
)
{
pithy_print
.
elapse
(
SRS_PULSE_TIMEOUT_US
/
1000
);
// switch to other st-threads.
st_usleep
(
0
);
// read from client.
int
ctl_msg_ret
=
ERROR_SUCCESS
;
if
(
true
)
{
SrsCommonMessage
*
msg
=
NULL
;
ctl_msg_ret
=
ret
=
rtmp
->
recv_message
(
&
msg
);
srs_verbose
(
"play loop recv message. ret=%d"
,
ret
);
if
(
ret
!=
ERROR_SUCCESS
&&
ret
!=
ERROR_SOCKET_TIMEOUT
)
{
if
(
ret
!=
ERROR_SOCKET_TIMEOUT
&&
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"recv client control message failed. ret=%d"
,
ret
);
}
return
ret
;
}
if
((
ret
=
process_play_control_msg
(
consumer
,
msg
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_system_control_error
(
ret
))
{
srs_error
(
"process play control message failed. ret=%d"
,
ret
);
}
return
ret
;
}
}
// get messages from consumer.
SrsSharedPtrMessage
**
msgs
=
NULL
;
int
count
=
0
;
if
((
ret
=
consumer
->
get_packets
(
0
,
msgs
,
count
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"get messages from consumer failed. ret=%d"
,
ret
);
return
ret
;
}
// reportable
if
(
pithy_print
.
can_print
())
{
srs_trace
(
"-> time=%"
PRId64
", cmr=%d, msgs=%d, obytes=%"
PRId64
", ibytes=%"
PRId64
", okbps=%d, ikbps=%d"
,
pithy_print
.
get_age
(),
ctl_msg_ret
,
count
,
rtmp
->
get_send_bytes
(),
rtmp
->
get_recv_bytes
(),
rtmp
->
get_send_kbps
(),
rtmp
->
get_recv_kbps
());
}
if
(
count
<=
0
)
{
srs_verbose
(
"no packets in queue."
);
continue
;
}
SrsAutoFree
(
SrsSharedPtrMessage
*
,
msgs
,
true
);
// sendout messages
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
SrsSharedPtrMessage
*
msg
=
msgs
[
i
];
// the send_message will free the msg,
// so set the msgs[i] to NULL.
msgs
[
i
]
=
NULL
;
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send message to client failed. ret=%d"
,
ret
);
return
ret
;
}
}
}
return
ret
;
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer_play
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"check play_refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"check play_refer success."
);
SrsConsumer
*
consumer
=
NULL
;
if
((
ret
=
source
->
create_consumer
(
consumer
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"create consumer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_assert
(
consumer
!=
NULL
);
SrsAutoFree
(
SrsConsumer
,
consumer
,
false
);
srs_verbose
(
"consumer created success."
);
rtmp
->
set_recv_timeout
(
SRS_PULSE_TIMEOUT_US
);
SrsPithyPrint
pithy_print
(
SRS_STAGE_PLAY_USER
);
while
(
true
)
{
pithy_print
.
elapse
(
SRS_PULSE_TIMEOUT_US
/
1000
);
// switch to other st-threads.
st_usleep
(
0
);
// read from client.
int
ctl_msg_ret
=
ERROR_SUCCESS
;
if
(
true
)
{
SrsCommonMessage
*
msg
=
NULL
;
ctl_msg_ret
=
ret
=
rtmp
->
recv_message
(
&
msg
);
srs_verbose
(
"play loop recv message. ret=%d"
,
ret
);
if
(
ret
!=
ERROR_SUCCESS
&&
ret
!=
ERROR_SOCKET_TIMEOUT
)
{
if
(
ret
!=
ERROR_SOCKET_TIMEOUT
&&
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"recv client control message failed. ret=%d"
,
ret
);
}
return
ret
;
}
if
((
ret
=
process_play_control_msg
(
consumer
,
msg
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_system_control_error
(
ret
))
{
srs_error
(
"process play control message failed. ret=%d"
,
ret
);
}
return
ret
;
}
}
// get messages from consumer.
SrsSharedPtrMessage
**
msgs
=
NULL
;
int
count
=
0
;
if
((
ret
=
consumer
->
get_packets
(
0
,
msgs
,
count
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"get messages from consumer failed. ret=%d"
,
ret
);
return
ret
;
}
// reportable
if
(
pithy_print
.
can_print
())
{
srs_trace
(
"-> time=%"
PRId64
", cmr=%d, msgs=%d, obytes=%"
PRId64
", ibytes=%"
PRId64
", okbps=%d, ikbps=%d"
,
pithy_print
.
get_age
(),
ctl_msg_ret
,
count
,
rtmp
->
get_send_bytes
(),
rtmp
->
get_recv_bytes
(),
rtmp
->
get_send_kbps
(),
rtmp
->
get_recv_kbps
());
}
if
(
count
<=
0
)
{
srs_verbose
(
"no packets in queue."
);
continue
;
}
SrsAutoFree
(
SrsSharedPtrMessage
*
,
msgs
,
true
);
// sendout messages
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
SrsSharedPtrMessage
*
msg
=
msgs
[
i
];
// the send_message will free the msg,
// so set the msgs[i] to NULL.
msgs
[
i
]
=
NULL
;
if
((
ret
=
rtmp
->
send_message
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"send message to client failed. ret=%d"
,
ret
);
return
ret
;
}
}
}
return
ret
;
}
int
SrsClient
::
fmle_publish
(
SrsSource
*
source
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer_publish
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle check publish_refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"fmle check publish_refer success."
);
SrsPithyPrint
pithy_print
(
SRS_STAGE_PUBLISH_USER
);
// notify the hls to prepare when publish start.
if
((
ret
=
source
->
on_publish
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle hls on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"fmle hls on_publish success."
);
while
(
true
)
{
// switch to other st-threads.
st_usleep
(
0
);
SrsCommonMessage
*
msg
=
NULL
;
if
((
ret
=
rtmp
->
recv_message
(
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle recv identify client message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
pithy_print
.
set_age
(
msg
->
header
.
timestamp
);
// reportable
if
(
pithy_print
.
can_print
())
{
srs_trace
(
"<- time=%"
PRId64
", obytes=%"
PRId64
", ibytes=%"
PRId64
", okbps=%d, ikbps=%d"
,
pithy_print
.
get_age
(),
rtmp
->
get_send_bytes
(),
rtmp
->
get_recv_bytes
(),
rtmp
->
get_send_kbps
(),
rtmp
->
get_recv_kbps
());
}
// process UnPublish event.
if
(
msg
->
header
.
is_amf0_command
()
||
msg
->
header
.
is_amf3_command
())
{
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle decode unpublish message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsPacket
*
pkt
=
msg
->
get_packet
();
if
(
dynamic_cast
<
SrsFMLEStartPacket
*>
(
pkt
))
{
SrsFMLEStartPacket
*
unpublish
=
dynamic_cast
<
SrsFMLEStartPacket
*>
(
pkt
);
if
((
ret
=
rtmp
->
fmle_unpublish
(
res
->
stream_id
,
unpublish
->
transaction_id
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ERROR_CONTROL_REPUBLISH
;
}
srs_trace
(
"fmle ignore AMF0/AMF3 command message."
);
continue
;
}
// video, audio, data message
if
((
ret
=
process_publish_message
(
source
,
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle process publish message failed. ret=%d"
,
ret
);
return
ret
;
}
}
return
ret
;
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer_publish
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle check publish_refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"fmle check publish_refer success."
);
SrsPithyPrint
pithy_print
(
SRS_STAGE_PUBLISH_USER
);
// notify the hls to prepare when publish start.
if
((
ret
=
source
->
on_publish
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle hls on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"fmle hls on_publish success."
);
while
(
true
)
{
// switch to other st-threads.
st_usleep
(
0
);
SrsCommonMessage
*
msg
=
NULL
;
if
((
ret
=
rtmp
->
recv_message
(
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle recv identify client message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
pithy_print
.
set_age
(
msg
->
header
.
timestamp
);
// reportable
if
(
pithy_print
.
can_print
())
{
srs_trace
(
"<- time=%"
PRId64
", obytes=%"
PRId64
", ibytes=%"
PRId64
", okbps=%d, ikbps=%d"
,
pithy_print
.
get_age
(),
rtmp
->
get_send_bytes
(),
rtmp
->
get_recv_bytes
(),
rtmp
->
get_send_kbps
(),
rtmp
->
get_recv_kbps
());
}
// process UnPublish event.
if
(
msg
->
header
.
is_amf0_command
()
||
msg
->
header
.
is_amf3_command
())
{
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle decode unpublish message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsPacket
*
pkt
=
msg
->
get_packet
();
if
(
dynamic_cast
<
SrsFMLEStartPacket
*>
(
pkt
))
{
SrsFMLEStartPacket
*
unpublish
=
dynamic_cast
<
SrsFMLEStartPacket
*>
(
pkt
);
if
((
ret
=
rtmp
->
fmle_unpublish
(
res
->
stream_id
,
unpublish
->
transaction_id
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ERROR_CONTROL_REPUBLISH
;
}
srs_trace
(
"fmle ignore AMF0/AMF3 command message."
);
continue
;
}
// video, audio, data message
if
((
ret
=
process_publish_message
(
source
,
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"fmle process publish message failed. ret=%d"
,
ret
);
return
ret
;
}
}
return
ret
;
}
int
SrsClient
::
flash_publish
(
SrsSource
*
source
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer_publish
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash check publish_refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"flash check publish_refer success."
);
SrsPithyPrint
pithy_print
(
SRS_STAGE_PUBLISH_USER
);
// notify the hls to prepare when publish start.
if
((
ret
=
source
->
on_publish
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash hls on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"flash hls on_publish success."
);
while
(
true
)
{
// switch to other st-threads.
st_usleep
(
0
);
SrsCommonMessage
*
msg
=
NULL
;
if
((
ret
=
rtmp
->
recv_message
(
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash recv identify client message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
pithy_print
.
set_age
(
msg
->
header
.
timestamp
);
// reportable
if
(
pithy_print
.
can_print
())
{
srs_trace
(
"<- time=%"
PRId64
", obytes=%"
PRId64
", ibytes=%"
PRId64
", okbps=%d, ikbps=%d"
,
pithy_print
.
get_age
(),
rtmp
->
get_send_bytes
(),
rtmp
->
get_recv_bytes
(),
rtmp
->
get_send_kbps
(),
rtmp
->
get_recv_kbps
());
}
// process UnPublish event.
if
(
msg
->
header
.
is_amf0_command
()
||
msg
->
header
.
is_amf3_command
())
{
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash decode unpublish message failed. ret=%d"
,
ret
);
return
ret
;
}
// flash unpublish.
// TODO: maybe need to support republish.
srs_trace
(
"flash flash publish finished."
);
return
ERROR_CONTROL_REPUBLISH
;
}
// video, audio, data message
if
((
ret
=
process_publish_message
(
source
,
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash process publish message failed. ret=%d"
,
ret
);
return
ret
;
}
}
return
ret
;
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
refer
->
check
(
req
->
pageUrl
,
_srs_config
->
get_refer_publish
(
req
->
vhost
)))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash check publish_refer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"flash check publish_refer success."
);
SrsPithyPrint
pithy_print
(
SRS_STAGE_PUBLISH_USER
);
// notify the hls to prepare when publish start.
if
((
ret
=
source
->
on_publish
(
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash hls on_publish failed. ret=%d"
,
ret
);
return
ret
;
}
srs_verbose
(
"flash hls on_publish success."
);
while
(
true
)
{
// switch to other st-threads.
st_usleep
(
0
);
SrsCommonMessage
*
msg
=
NULL
;
if
((
ret
=
rtmp
->
recv_message
(
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash recv identify client message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
pithy_print
.
set_age
(
msg
->
header
.
timestamp
);
// reportable
if
(
pithy_print
.
can_print
())
{
srs_trace
(
"<- time=%"
PRId64
", obytes=%"
PRId64
", ibytes=%"
PRId64
", okbps=%d, ikbps=%d"
,
pithy_print
.
get_age
(),
rtmp
->
get_send_bytes
(),
rtmp
->
get_recv_bytes
(),
rtmp
->
get_send_kbps
(),
rtmp
->
get_recv_kbps
());
}
// process UnPublish event.
if
(
msg
->
header
.
is_amf0_command
()
||
msg
->
header
.
is_amf3_command
())
{
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash decode unpublish message failed. ret=%d"
,
ret
);
return
ret
;
}
// flash unpublish.
// TODO: maybe need to support republish.
srs_trace
(
"flash flash publish finished."
);
return
ERROR_CONTROL_REPUBLISH
;
}
// video, audio, data message
if
((
ret
=
process_publish_message
(
source
,
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"flash process publish message failed. ret=%d"
,
ret
);
return
ret
;
}
}
return
ret
;
}
int
SrsClient
::
process_publish_message
(
SrsSource
*
source
,
SrsCommonMessage
*
msg
)
{
int
ret
=
ERROR_SUCCESS
;
// process audio packet
if
(
msg
->
header
.
is_audio
())
{
if
((
ret
=
source
->
on_audio
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"source process audio message failed. ret=%d"
,
ret
);
return
ret
;
}
}
// process video packet
if
(
msg
->
header
.
is_video
())
{
if
((
ret
=
source
->
on_video
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"source process video message failed. ret=%d"
,
ret
);
return
ret
;
}
}
// process onMetaData
if
(
msg
->
header
.
is_amf0_data
()
||
msg
->
header
.
is_amf3_data
())
{
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"decode onMetaData message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsPacket
*
pkt
=
msg
->
get_packet
();
if
(
dynamic_cast
<
SrsOnMetaDataPacket
*>
(
pkt
))
{
SrsOnMetaDataPacket
*
metadata
=
dynamic_cast
<
SrsOnMetaDataPacket
*>
(
pkt
);
if
((
ret
=
source
->
on_meta_data
(
msg
,
metadata
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"source process onMetaData message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_trace
(
"process onMetaData message success."
);
return
ret
;
}
srs_trace
(
"ignore AMF0/AMF3 data message."
);
return
ret
;
}
return
ret
;
int
ret
=
ERROR_SUCCESS
;
// process audio packet
if
(
msg
->
header
.
is_audio
())
{
if
((
ret
=
source
->
on_audio
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"source process audio message failed. ret=%d"
,
ret
);
return
ret
;
}
}
// process video packet
if
(
msg
->
header
.
is_video
())
{
if
((
ret
=
source
->
on_video
(
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"source process video message failed. ret=%d"
,
ret
);
return
ret
;
}
}
// process onMetaData
if
(
msg
->
header
.
is_amf0_data
()
||
msg
->
header
.
is_amf3_data
())
{
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"decode onMetaData message failed. ret=%d"
,
ret
);
return
ret
;
}
SrsPacket
*
pkt
=
msg
->
get_packet
();
if
(
dynamic_cast
<
SrsOnMetaDataPacket
*>
(
pkt
))
{
SrsOnMetaDataPacket
*
metadata
=
dynamic_cast
<
SrsOnMetaDataPacket
*>
(
pkt
);
if
((
ret
=
source
->
on_meta_data
(
msg
,
metadata
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"source process onMetaData message failed. ret=%d"
,
ret
);
return
ret
;
}
srs_trace
(
"process onMetaData message success."
);
return
ret
;
}
srs_trace
(
"ignore AMF0/AMF3 data message."
);
return
ret
;
}
return
ret
;
}
int
SrsClient
::
get_peer_ip
()
{
int
ret
=
ERROR_SUCCESS
;
int
ret
=
ERROR_SUCCESS
;
int
fd
=
st_netfd_fileno
(
stfd
);
// discovery client information
...
...
@@ -674,71 +674,71 @@ int SrsClient::get_peer_ip()
int
SrsClient
::
process_play_control_msg
(
SrsConsumer
*
consumer
,
SrsCommonMessage
*
msg
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
!
msg
)
{
srs_verbose
(
"ignore all empty message."
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
if
(
!
msg
->
header
.
is_amf0_command
()
&&
!
msg
->
header
.
is_amf3_command
())
{
srs_info
(
"ignore all message except amf0/amf3 command."
);
return
ret
;
}
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"decode the amf0/amf3 command packet failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"decode the amf0/amf3 command packet success."
);
SrsCloseStreamPacket
*
close
=
dynamic_cast
<
SrsCloseStreamPacket
*>
(
msg
->
get_packet
());
if
(
close
)
{
ret
=
ERROR_CONTROL_RTMP_CLOSE
;
srs_trace
(
"system control message: rtmp close stream. ret=%d"
,
ret
);
return
ret
;
}
SrsPausePacket
*
pause
=
dynamic_cast
<
SrsPausePacket
*>
(
msg
->
get_packet
());
if
(
!
pause
)
{
srs_info
(
"ignore all amf0/amf3 command except pause."
);
return
ret
;
}
if
((
ret
=
rtmp
->
on_play_client_pause
(
res
->
stream_id
,
pause
->
is_pause
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtmp process play client pause failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
consumer
->
on_play_client_pause
(
pause
->
is_pause
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"consumer process play client pause failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"process pause success, is_pause=%d, time=%d."
,
pause
->
is_pause
,
pause
->
time_ms
);
int
ret
=
ERROR_SUCCESS
;
if
(
!
msg
)
{
srs_verbose
(
"ignore all empty message."
);
return
ret
;
}
SrsAutoFree
(
SrsCommonMessage
,
msg
,
false
);
if
(
!
msg
->
header
.
is_amf0_command
()
&&
!
msg
->
header
.
is_amf3_command
())
{
srs_info
(
"ignore all message except amf0/amf3 command."
);
return
ret
;
}
if
((
ret
=
msg
->
decode_packet
(
rtmp
->
get_protocol
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"decode the amf0/amf3 command packet failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"decode the amf0/amf3 command packet success."
);
SrsCloseStreamPacket
*
close
=
dynamic_cast
<
SrsCloseStreamPacket
*>
(
msg
->
get_packet
());
if
(
close
)
{
ret
=
ERROR_CONTROL_RTMP_CLOSE
;
srs_trace
(
"system control message: rtmp close stream. ret=%d"
,
ret
);
return
ret
;
}
SrsPausePacket
*
pause
=
dynamic_cast
<
SrsPausePacket
*>
(
msg
->
get_packet
());
if
(
!
pause
)
{
srs_info
(
"ignore all amf0/amf3 command except pause."
);
return
ret
;
}
if
((
ret
=
rtmp
->
on_play_client_pause
(
res
->
stream_id
,
pause
->
is_pause
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtmp process play client pause failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
consumer
->
on_play_client_pause
(
pause
->
is_pause
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"consumer process play client pause failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"process pause success, is_pause=%d, time=%d."
,
pause
->
is_pause
,
pause
->
time_ms
);
return
ret
;
}
int
SrsClient
::
on_connect
()
{
int
ret
=
ERROR_SUCCESS
;
#ifdef SRS_HTTP_CALLBACK
// HTTP: on_connect
SrsConfDirective
*
on_connect
=
_srs_config
->
get_vhost_on_connect
(
req
->
vhost
);
if
(
!
on_connect
)
{
srs_info
(
"ignore the empty http callback: on_connect"
);
return
ret
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_connect
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_connect
->
args
.
at
(
i
);
if
((
ret
=
http_hooks
->
on_connect
(
url
,
connection_id
,
ip
,
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hook client on_connect failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
}
int
ret
=
ERROR_SUCCESS
;
#ifdef SRS_HTTP_CALLBACK
// HTTP: on_connect
SrsConfDirective
*
on_connect
=
_srs_config
->
get_vhost_on_connect
(
req
->
vhost
);
if
(
!
on_connect
)
{
srs_info
(
"ignore the empty http callback: on_connect"
);
return
ret
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_connect
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_connect
->
args
.
at
(
i
);
if
((
ret
=
http_hooks
->
on_connect
(
url
,
connection_id
,
ip
,
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hook client on_connect failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
}
#endif
return
ret
;
...
...
@@ -747,40 +747,40 @@ int SrsClient::on_connect()
void
SrsClient
::
on_close
()
{
#ifdef SRS_HTTP_CALLBACK
// whatever the ret code, notify the api hooks.
// HTTP: on_close
SrsConfDirective
*
on_close
=
_srs_config
->
get_vhost_on_close
(
req
->
vhost
);
if
(
!
on_close
)
{
srs_info
(
"ignore the empty http callback: on_close"
);
return
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_close
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_close
->
args
.
at
(
i
);
http_hooks
->
on_close
(
url
,
connection_id
,
ip
,
req
);
}
// whatever the ret code, notify the api hooks.
// HTTP: on_close
SrsConfDirective
*
on_close
=
_srs_config
->
get_vhost_on_close
(
req
->
vhost
);
if
(
!
on_close
)
{
srs_info
(
"ignore the empty http callback: on_close"
);
return
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_close
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_close
->
args
.
at
(
i
);
http_hooks
->
on_close
(
url
,
connection_id
,
ip
,
req
);
}
#endif
}
int
SrsClient
::
on_publish
()
{
int
ret
=
ERROR_SUCCESS
;
#ifdef SRS_HTTP_CALLBACK
// HTTP: on_publish
SrsConfDirective
*
on_publish
=
_srs_config
->
get_vhost_on_publish
(
req
->
vhost
);
if
(
!
on_publish
)
{
srs_info
(
"ignore the empty http callback: on_publish"
);
return
ret
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_publish
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_publish
->
args
.
at
(
i
);
if
((
ret
=
http_hooks
->
on_publish
(
url
,
connection_id
,
ip
,
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hook client on_publish failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
}
int
ret
=
ERROR_SUCCESS
;
#ifdef SRS_HTTP_CALLBACK
// HTTP: on_publish
SrsConfDirective
*
on_publish
=
_srs_config
->
get_vhost_on_publish
(
req
->
vhost
);
if
(
!
on_publish
)
{
srs_info
(
"ignore the empty http callback: on_publish"
);
return
ret
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_publish
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_publish
->
args
.
at
(
i
);
if
((
ret
=
http_hooks
->
on_publish
(
url
,
connection_id
,
ip
,
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hook client on_publish failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
}
#endif
return
ret
;
...
...
@@ -789,40 +789,40 @@ int SrsClient::on_publish()
void
SrsClient
::
on_unpublish
()
{
#ifdef SRS_HTTP_CALLBACK
// whatever the ret code, notify the api hooks.
// HTTP: on_unpublish
SrsConfDirective
*
on_unpublish
=
_srs_config
->
get_vhost_on_unpublish
(
req
->
vhost
);
if
(
!
on_unpublish
)
{
srs_info
(
"ignore the empty http callback: on_unpublish"
);
return
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_unpublish
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_unpublish
->
args
.
at
(
i
);
http_hooks
->
on_unpublish
(
url
,
connection_id
,
ip
,
req
);
}
// whatever the ret code, notify the api hooks.
// HTTP: on_unpublish
SrsConfDirective
*
on_unpublish
=
_srs_config
->
get_vhost_on_unpublish
(
req
->
vhost
);
if
(
!
on_unpublish
)
{
srs_info
(
"ignore the empty http callback: on_unpublish"
);
return
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_unpublish
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_unpublish
->
args
.
at
(
i
);
http_hooks
->
on_unpublish
(
url
,
connection_id
,
ip
,
req
);
}
#endif
}
int
SrsClient
::
on_play
()
{
int
ret
=
ERROR_SUCCESS
;
#ifdef SRS_HTTP_CALLBACK
// HTTP: on_play
SrsConfDirective
*
on_play
=
_srs_config
->
get_vhost_on_play
(
req
->
vhost
);
if
(
!
on_play
)
{
srs_info
(
"ignore the empty http callback: on_play"
);
return
ret
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_play
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_play
->
args
.
at
(
i
);
if
((
ret
=
http_hooks
->
on_play
(
url
,
connection_id
,
ip
,
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hook client on_play failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
}
int
ret
=
ERROR_SUCCESS
;
#ifdef SRS_HTTP_CALLBACK
// HTTP: on_play
SrsConfDirective
*
on_play
=
_srs_config
->
get_vhost_on_play
(
req
->
vhost
);
if
(
!
on_play
)
{
srs_info
(
"ignore the empty http callback: on_play"
);
return
ret
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_play
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_play
->
args
.
at
(
i
);
if
((
ret
=
http_hooks
->
on_play
(
url
,
connection_id
,
ip
,
req
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hook client on_play failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
}
#endif
return
ret
;
...
...
@@ -831,17 +831,17 @@ int SrsClient::on_play()
void
SrsClient
::
on_stop
()
{
#ifdef SRS_HTTP_CALLBACK
// whatever the ret code, notify the api hooks.
// HTTP: on_stop
SrsConfDirective
*
on_stop
=
_srs_config
->
get_vhost_on_stop
(
req
->
vhost
);
if
(
!
on_stop
)
{
srs_info
(
"ignore the empty http callback: on_stop"
);
return
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_stop
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_stop
->
args
.
at
(
i
);
http_hooks
->
on_stop
(
url
,
connection_id
,
ip
,
req
);
}
// whatever the ret code, notify the api hooks.
// HTTP: on_stop
SrsConfDirective
*
on_stop
=
_srs_config
->
get_vhost_on_stop
(
req
->
vhost
);
if
(
!
on_stop
)
{
srs_info
(
"ignore the empty http callback: on_stop"
);
return
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_stop
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_stop
->
args
.
at
(
i
);
http_hooks
->
on_stop
(
url
,
connection_id
,
ip
,
req
);
}
#endif
}
...
...
trunk/src/app/srs_app_client.hpp
查看文件 @
c85dde7
...
...
@@ -42,7 +42,7 @@ class SrsRefer;
class
SrsConsumer
;
class
SrsCommonMessage
;
class
SrsSocket
;
#ifdef SRS_HTTP_CALLBACK
#ifdef SRS_HTTP_CALLBACK
class
SrsHttpHooks
;
#endif
class
SrsBandwidth
;
...
...
@@ -53,43 +53,43 @@ class SrsBandwidth;
class
SrsClient
:
public
SrsConnection
,
public
ISrsReloadHandler
{
private
:
char
*
ip
;
SrsRequest
*
req
;
SrsResponse
*
res
;
SrsSocket
*
skt
;
SrsRtmpServer
*
rtmp
;
SrsRefer
*
refer
;
#ifdef SRS_HTTP_CALLBACK
SrsHttpHooks
*
http_hooks
;
char
*
ip
;
SrsRequest
*
req
;
SrsResponse
*
res
;
SrsSocket
*
skt
;
SrsRtmpServer
*
rtmp
;
SrsRefer
*
refer
;
#ifdef SRS_HTTP_CALLBACK
SrsHttpHooks
*
http_hooks
;
#endif
SrsBandwidth
*
bandwidth
;
SrsBandwidth
*
bandwidth
;
public
:
SrsClient
(
SrsServer
*
srs_server
,
st_netfd_t
client_stfd
);
virtual
~
SrsClient
();
SrsClient
(
SrsServer
*
srs_server
,
st_netfd_t
client_stfd
);
virtual
~
SrsClient
();
protected
:
virtual
int
do_cycle
();
virtual
int
do_cycle
();
// interface ISrsReloadHandler
public:
virtual
int
on_reload_vhost_removed
(
std
::
string
vhost
);
virtual
int
on_reload_vhost_removed
(
std
::
string
vhost
);
private
:
// when valid and connected to vhost/app, service the client.
virtual
int
service_cycle
();
// stream(play/publish) service cycle, identify client first.
virtual
int
stream_service_cycle
();
virtual
int
check_vhost
();
virtual
int
playing
(
SrsSource
*
source
);
virtual
int
fmle_publish
(
SrsSource
*
source
);
virtual
int
flash_publish
(
SrsSource
*
source
);
virtual
int
process_publish_message
(
SrsSource
*
source
,
SrsCommonMessage
*
msg
);
virtual
int
get_peer_ip
();
virtual
int
process_play_control_msg
(
SrsConsumer
*
consumer
,
SrsCommonMessage
*
msg
);
// when valid and connected to vhost/app, service the client.
virtual
int
service_cycle
();
// stream(play/publish) service cycle, identify client first.
virtual
int
stream_service_cycle
();
virtual
int
check_vhost
();
virtual
int
playing
(
SrsSource
*
source
);
virtual
int
fmle_publish
(
SrsSource
*
source
);
virtual
int
flash_publish
(
SrsSource
*
source
);
virtual
int
process_publish_message
(
SrsSource
*
source
,
SrsCommonMessage
*
msg
);
virtual
int
get_peer_ip
();
virtual
int
process_play_control_msg
(
SrsConsumer
*
consumer
,
SrsCommonMessage
*
msg
);
private
:
virtual
int
on_connect
();
virtual
void
on_close
();
virtual
int
on_publish
();
virtual
void
on_unpublish
();
virtual
int
on_play
();
virtual
void
on_stop
();
virtual
int
on_connect
();
virtual
void
on_close
();
virtual
int
on_publish
();
virtual
void
on_unpublish
();
virtual
int
on_play
();
virtual
void
on_stop
();
};
#endif
...
...
trunk/src/app/srs_app_codec.cpp
查看文件 @
c85dde7
...
...
@@ -33,29 +33,29 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SrsCodecBuffer
::
SrsCodecBuffer
()
{
size
=
0
;
bytes
=
NULL
;
size
=
0
;
bytes
=
NULL
;
}
void
SrsCodecBuffer
::
append
(
void
*
data
,
int
len
)
{
srs_assert
(
data
);
srs_assert
(
len
>
0
);
srs_assert
(
data
);
srs_assert
(
len
>
0
);
bytes
=
(
char
*
)
realloc
(
bytes
,
size
+
len
);
memcpy
(
bytes
+
size
,
data
,
len
);
size
+=
len
;
bytes
=
(
char
*
)
realloc
(
bytes
,
size
+
len
);
memcpy
(
bytes
+
size
,
data
,
len
);
size
+=
len
;
}
void
SrsCodecBuffer
::
free
()
{
size
=
0
;
srs_freepa
(
bytes
);
size
=
0
;
srs_freepa
(
bytes
);
}
SrsCodecSample
::
SrsCodecSample
()
{
clear
();
clear
();
}
SrsCodecSample
::~
SrsCodecSample
()
...
...
@@ -64,468 +64,468 @@ SrsCodecSample::~SrsCodecSample()
void
SrsCodecSample
::
clear
()
{
is_video
=
false
;
nb_buffers
=
0
;
cts
=
0
;
frame_type
=
SrsCodecVideoAVCFrameReserved
;
avc_packet_type
=
SrsCodecVideoAVCTypeReserved
;
sound_rate
=
SrsCodecAudioSampleRateReserved
;
sound_size
=
SrsCodecAudioSampleSizeReserved
;
sound_type
=
SrsCodecAudioSoundTypeReserved
;
aac_packet_type
=
SrsCodecAudioTypeReserved
;
is_video
=
false
;
nb_buffers
=
0
;
cts
=
0
;
frame_type
=
SrsCodecVideoAVCFrameReserved
;
avc_packet_type
=
SrsCodecVideoAVCTypeReserved
;
sound_rate
=
SrsCodecAudioSampleRateReserved
;
sound_size
=
SrsCodecAudioSampleSizeReserved
;
sound_type
=
SrsCodecAudioSoundTypeReserved
;
aac_packet_type
=
SrsCodecAudioTypeReserved
;
}
int
SrsCodecSample
::
add_sample
(
char
*
bytes
,
int
size
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
nb_buffers
>=
SRS_MAX_CODEC_SAMPLE
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode samples error, "
"exceed the max count: %d, ret=%d"
,
SRS_MAX_CODEC_SAMPLE
,
ret
);
return
ret
;
}
SrsCodecBuffer
*
buf
=
&
buffers
[
nb_buffers
++
];
buf
->
bytes
=
bytes
;
buf
->
size
=
size
;
return
ret
;
int
ret
=
ERROR_SUCCESS
;
if
(
nb_buffers
>=
SRS_MAX_CODEC_SAMPLE
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode samples error, "
"exceed the max count: %d, ret=%d"
,
SRS_MAX_CODEC_SAMPLE
,
ret
);
return
ret
;
}
SrsCodecBuffer
*
buf
=
&
buffers
[
nb_buffers
++
];
buf
->
bytes
=
bytes
;
buf
->
size
=
size
;
return
ret
;
}
SrsCodec
::
SrsCodec
()
{
width
=
0
;
height
=
0
;
duration
=
0
;
NAL_unit_length
=
0
;
frame_rate
=
0
;
video_data_rate
=
0
;
video_codec_id
=
0
;
audio_data_rate
=
0
;
audio_codec_id
=
0
;
avc_profile
=
0
;
avc_level
=
0
;
aac_profile
=
0
;
aac_sample_rate
=
0
;
aac_channels
=
0
;
avc_extra_size
=
0
;
avc_extra_data
=
NULL
;
aac_extra_size
=
0
;
aac_extra_data
=
NULL
;
sequenceParameterSetLength
=
0
;
sequenceParameterSetNALUnit
=
NULL
;
pictureParameterSetLength
=
0
;
pictureParameterSetNALUnit
=
NULL
;
stream
=
new
SrsStream
();
width
=
0
;
height
=
0
;
duration
=
0
;
NAL_unit_length
=
0
;
frame_rate
=
0
;
video_data_rate
=
0
;
video_codec_id
=
0
;
audio_data_rate
=
0
;
audio_codec_id
=
0
;
avc_profile
=
0
;
avc_level
=
0
;
aac_profile
=
0
;
aac_sample_rate
=
0
;
aac_channels
=
0
;
avc_extra_size
=
0
;
avc_extra_data
=
NULL
;
aac_extra_size
=
0
;
aac_extra_data
=
NULL
;
sequenceParameterSetLength
=
0
;
sequenceParameterSetNALUnit
=
NULL
;
pictureParameterSetLength
=
0
;
pictureParameterSetNALUnit
=
NULL
;
stream
=
new
SrsStream
();
}
SrsCodec
::~
SrsCodec
()
{
srs_freepa
(
avc_extra_data
);
srs_freepa
(
aac_extra_data
);
srs_freepa
(
avc_extra_data
);
srs_freepa
(
aac_extra_data
);
srs_freep
(
stream
);
srs_freepa
(
sequenceParameterSetNALUnit
);
srs_freepa
(
pictureParameterSetNALUnit
);
srs_freep
(
stream
);
srs_freepa
(
sequenceParameterSetNALUnit
);
srs_freepa
(
pictureParameterSetNALUnit
);
}
int
SrsCodec
::
audio_aac_demux
(
int8_t
*
data
,
int
size
,
SrsCodecSample
*
sample
)
{
int
ret
=
ERROR_SUCCESS
;
sample
->
is_video
=
false
;
if
(
!
data
||
size
<=
0
)
{
srs_trace
(
"no audio present, hls ignore it."
);
return
ret
;
}
if
((
ret
=
stream
->
initialize
((
char
*
)
data
,
size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// audio decode
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio sound_format failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
sound_format
=
stream
->
read_1bytes
();
int8_t
sound_type
=
sound_format
&
0x01
;
int8_t
sound_size
=
(
sound_format
>>
1
)
&
0x01
;
int8_t
sound_rate
=
(
sound_format
>>
2
)
&
0x03
;
sound_format
=
(
sound_format
>>
4
)
&
0x0f
;
audio_codec_id
=
sound_format
;
sample
->
sound_type
=
(
SrsCodecAudioSoundType
)
sound_type
;
sample
->
sound_rate
=
(
SrsCodecAudioSampleRate
)
sound_rate
;
sample
->
sound_size
=
(
SrsCodecAudioSampleSize
)
sound_size
;
// reset the sample rate by sequence header
int
ret
=
ERROR_SUCCESS
;
sample
->
is_video
=
false
;
if
(
!
data
||
size
<=
0
)
{
srs_trace
(
"no audio present, hls ignore it."
);
return
ret
;
}
if
((
ret
=
stream
->
initialize
((
char
*
)
data
,
size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// audio decode
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio sound_format failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
sound_format
=
stream
->
read_1bytes
();
int8_t
sound_type
=
sound_format
&
0x01
;
int8_t
sound_size
=
(
sound_format
>>
1
)
&
0x01
;
int8_t
sound_rate
=
(
sound_format
>>
2
)
&
0x03
;
sound_format
=
(
sound_format
>>
4
)
&
0x0f
;
audio_codec_id
=
sound_format
;
sample
->
sound_type
=
(
SrsCodecAudioSoundType
)
sound_type
;
sample
->
sound_rate
=
(
SrsCodecAudioSampleRate
)
sound_rate
;
sample
->
sound_size
=
(
SrsCodecAudioSampleSize
)
sound_size
;
// reset the sample rate by sequence header
static
int
aac_sample_rates
[]
=
{
96000
,
88200
,
64000
,
48000
,
44100
,
32000
,
24000
,
22050
,
16000
,
12000
,
11025
,
8000
,
7350
,
0
,
0
,
0
96000
,
88200
,
64000
,
48000
,
44100
,
32000
,
24000
,
22050
,
16000
,
12000
,
11025
,
8000
,
7350
,
0
,
0
,
0
};
switch
(
aac_sample_rates
[
aac_sample_rate
])
{
case
11025
:
sample
->
sound_rate
=
SrsCodecAudioSampleRate11025
;
break
;
sample
->
sound_rate
=
SrsCodecAudioSampleRate11025
;
break
;
case
22050
:
sample
->
sound_rate
=
SrsCodecAudioSampleRate22050
;
break
;
sample
->
sound_rate
=
SrsCodecAudioSampleRate22050
;
break
;
case
44100
:
sample
->
sound_rate
=
SrsCodecAudioSampleRate44100
;
break
;
sample
->
sound_rate
=
SrsCodecAudioSampleRate44100
;
break
;
};
// only support aac
if
(
audio_codec_id
!=
SrsCodecAudioAAC
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls only support audio aac codec. ret=%d"
,
ret
);
return
ret
;
}
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac_packet_type failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
aac_packet_type
=
stream
->
read_1bytes
();
sample
->
aac_packet_type
=
(
SrsCodecAudioType
)
aac_packet_type
;
if
(
aac_packet_type
==
SrsCodecAudioTypeSequenceHeader
)
{
// AudioSpecificConfig
// 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33.
aac_extra_size
=
stream
->
left
();
if
(
aac_extra_size
>
0
)
{
srs_freepa
(
aac_extra_data
);
aac_extra_data
=
new
char
[
aac_extra_size
];
memcpy
(
aac_extra_data
,
stream
->
current
(),
aac_extra_size
);
}
// only need to decode the first 2bytes:
// audioObjectType, aac_profile, 5bits.
// samplingFrequencyIndex, aac_sample_rate, 4bits.
// channelConfiguration, aac_channels, 4bits
if
(
!
stream
->
require
(
2
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac sequence header failed. ret=%d"
,
ret
);
return
ret
;
}
aac_profile
=
stream
->
read_1bytes
();
aac_sample_rate
=
stream
->
read_1bytes
();
aac_channels
=
(
aac_sample_rate
>>
3
)
&
0x0f
;
aac_sample_rate
=
((
aac_profile
<<
1
)
&
0x0e
)
|
((
aac_sample_rate
>>
7
)
&
0x01
);
aac_profile
=
(
aac_profile
>>
3
)
&
0x1f
;
if
(
aac_profile
==
0
||
aac_profile
==
0x1f
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac sequence header failed, "
"adts object=%d invalid. ret=%d"
,
aac_profile
,
ret
);
return
ret
;
}
// aac_profile = audioObjectType - 1
aac_profile
--
;
if
(
aac_profile
>
3
)
{
// Mark all extended profiles as LC
// to make Android as happy as possible.
// @see: ngx_rtmp_hls_parse_aac_header
aac_profile
=
1
;
}
}
else
if
(
aac_packet_type
==
SrsCodecAudioTypeRawData
)
{
// ensure the sequence header demuxed
if
(
aac_extra_size
<=
0
||
!
aac_extra_data
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac failed, sequence header not found. ret=%d"
,
ret
);
return
ret
;
}
// Raw AAC frame data in UI8 []
// 6.3 Raw Data, aac-iso-13818-7.pdf, page 28
if
((
ret
=
sample
->
add_sample
(
stream
->
current
(),
stream
->
left
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hls add audio sample failed. ret=%d"
,
ret
);
return
ret
;
}
}
else
{
// ignored.
}
srs_info
(
"audio decoded, type=%d, codec=%d, asize=%d, rate=%d, format=%d, size=%d"
,
sound_type
,
audio_codec_id
,
sound_size
,
sound_rate
,
sound_format
,
size
);
return
ret
;
// only support aac
if
(
audio_codec_id
!=
SrsCodecAudioAAC
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls only support audio aac codec. ret=%d"
,
ret
);
return
ret
;
}
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac_packet_type failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
aac_packet_type
=
stream
->
read_1bytes
();
sample
->
aac_packet_type
=
(
SrsCodecAudioType
)
aac_packet_type
;
if
(
aac_packet_type
==
SrsCodecAudioTypeSequenceHeader
)
{
// AudioSpecificConfig
// 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33.
aac_extra_size
=
stream
->
left
();
if
(
aac_extra_size
>
0
)
{
srs_freepa
(
aac_extra_data
);
aac_extra_data
=
new
char
[
aac_extra_size
];
memcpy
(
aac_extra_data
,
stream
->
current
(),
aac_extra_size
);
}
// only need to decode the first 2bytes:
// audioObjectType, aac_profile, 5bits.
// samplingFrequencyIndex, aac_sample_rate, 4bits.
// channelConfiguration, aac_channels, 4bits
if
(
!
stream
->
require
(
2
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac sequence header failed. ret=%d"
,
ret
);
return
ret
;
}
aac_profile
=
stream
->
read_1bytes
();
aac_sample_rate
=
stream
->
read_1bytes
();
aac_channels
=
(
aac_sample_rate
>>
3
)
&
0x0f
;
aac_sample_rate
=
((
aac_profile
<<
1
)
&
0x0e
)
|
((
aac_sample_rate
>>
7
)
&
0x01
);
aac_profile
=
(
aac_profile
>>
3
)
&
0x1f
;
if
(
aac_profile
==
0
||
aac_profile
==
0x1f
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac sequence header failed, "
"adts object=%d invalid. ret=%d"
,
aac_profile
,
ret
);
return
ret
;
}
// aac_profile = audioObjectType - 1
aac_profile
--
;
if
(
aac_profile
>
3
)
{
// Mark all extended profiles as LC
// to make Android as happy as possible.
// @see: ngx_rtmp_hls_parse_aac_header
aac_profile
=
1
;
}
}
else
if
(
aac_packet_type
==
SrsCodecAudioTypeRawData
)
{
// ensure the sequence header demuxed
if
(
aac_extra_size
<=
0
||
!
aac_extra_data
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode audio aac failed, sequence header not found. ret=%d"
,
ret
);
return
ret
;
}
// Raw AAC frame data in UI8 []
// 6.3 Raw Data, aac-iso-13818-7.pdf, page 28
if
((
ret
=
sample
->
add_sample
(
stream
->
current
(),
stream
->
left
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hls add audio sample failed. ret=%d"
,
ret
);
return
ret
;
}
}
else
{
// ignored.
}
srs_info
(
"audio decoded, type=%d, codec=%d, asize=%d, rate=%d, format=%d, size=%d"
,
sound_type
,
audio_codec_id
,
sound_size
,
sound_rate
,
sound_format
,
size
);
return
ret
;
}
int
SrsCodec
::
video_avc_demux
(
int8_t
*
data
,
int
size
,
SrsCodecSample
*
sample
)
{
int
ret
=
ERROR_SUCCESS
;
sample
->
is_video
=
true
;
if
(
!
data
||
size
<=
0
)
{
srs_trace
(
"no video present, hls ignore it."
);
return
ret
;
}
if
((
ret
=
stream
->
initialize
((
char
*
)
data
,
size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// video decode
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video frame_type failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
frame_type
=
stream
->
read_1bytes
();
int8_t
codec_id
=
frame_type
&
0x0f
;
frame_type
=
(
frame_type
>>
4
)
&
0x0f
;
sample
->
frame_type
=
(
SrsCodecVideoAVCFrame
)
frame_type
;
// only support h.264/avc
if
(
codec_id
!=
SrsCodecVideoAVC
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls only support video h.264/avc codec. ret=%d"
,
ret
);
return
ret
;
}
video_codec_id
=
codec_id
;
if
(
!
stream
->
require
(
4
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc_packet_type failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
avc_packet_type
=
stream
->
read_1bytes
();
int32_t
composition_time
=
stream
->
read_3bytes
();
// pts = dts + cts.
sample
->
cts
=
composition_time
;
sample
->
avc_packet_type
=
(
SrsCodecVideoAVCType
)
avc_packet_type
;
if
(
avc_packet_type
==
SrsCodecVideoAVCTypeSequenceHeader
)
{
// AVCDecoderConfigurationRecord
// 5.2.4.1.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
avc_extra_size
=
stream
->
left
();
if
(
avc_extra_size
>
0
)
{
srs_freepa
(
avc_extra_data
);
avc_extra_data
=
new
char
[
avc_extra_size
];
memcpy
(
avc_extra_data
,
stream
->
current
(),
avc_extra_size
);
}
if
(
!
stream
->
require
(
6
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header failed. ret=%d"
,
ret
);
return
ret
;
}
//int8_t configurationVersion = stream->read_1bytes();
//int8_t AVCProfileIndication = stream->read_1bytes();
//int8_t profile_compatibility = stream->read_1bytes();
//int8_t AVCLevelIndication = stream->read_1bytes();
stream
->
skip
(
4
);
// parse the NALU size.
int8_t
lengthSizeMinusOne
=
stream
->
read_1bytes
();
lengthSizeMinusOne
&=
0x03
;
NAL_unit_length
=
lengthSizeMinusOne
;
// 1 sps
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
numOfSequenceParameterSets
=
stream
->
read_1bytes
();
numOfSequenceParameterSets
&=
0x1f
;
if
(
numOfSequenceParameterSets
!=
1
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
!
stream
->
require
(
2
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps size failed. ret=%d"
,
ret
);
return
ret
;
}
sequenceParameterSetLength
=
stream
->
read_2bytes
();
if
(
!
stream
->
require
(
sequenceParameterSetLength
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps data failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
sequenceParameterSetLength
>
0
)
{
srs_freepa
(
sequenceParameterSetNALUnit
);
sequenceParameterSetNALUnit
=
new
char
[
sequenceParameterSetLength
];
memcpy
(
sequenceParameterSetNALUnit
,
stream
->
current
(),
sequenceParameterSetLength
);
stream
->
skip
(
sequenceParameterSetLength
);
}
// 1 pps
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
numOfPictureParameterSets
=
stream
->
read_1bytes
();
numOfPictureParameterSets
&=
0x1f
;
if
(
numOfPictureParameterSets
!=
1
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
!
stream
->
require
(
2
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps size failed. ret=%d"
,
ret
);
return
ret
;
}
pictureParameterSetLength
=
stream
->
read_2bytes
();
if
(
!
stream
->
require
(
pictureParameterSetLength
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps data failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
pictureParameterSetLength
>
0
)
{
srs_freepa
(
pictureParameterSetNALUnit
);
pictureParameterSetNALUnit
=
new
char
[
pictureParameterSetLength
];
memcpy
(
pictureParameterSetNALUnit
,
stream
->
current
(),
pictureParameterSetLength
);
stream
->
skip
(
pictureParameterSetLength
);
}
}
else
if
(
avc_packet_type
==
SrsCodecVideoAVCTypeNALU
){
// ensure the sequence header demuxed
if
(
avc_extra_size
<=
0
||
!
avc_extra_data
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc failed, sequence header not found. ret=%d"
,
ret
);
return
ret
;
}
// One or more NALUs (Full frames are required)
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 20
int
PictureLength
=
stream
->
left
();
for
(
int
i
=
0
;
i
<
PictureLength
;)
{
if
(
!
stream
->
require
(
NAL_unit_length
+
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc NALU size failed. ret=%d"
,
ret
);
return
ret
;
}
int32_t
NALUnitLength
=
0
;
if
(
NAL_unit_length
==
3
)
{
NALUnitLength
=
stream
->
read_4bytes
();
}
else
if
(
NALUnitLength
==
2
)
{
NALUnitLength
=
stream
->
read_3bytes
();
}
else
if
(
NALUnitLength
==
1
)
{
NALUnitLength
=
stream
->
read_2bytes
();
}
else
{
NALUnitLength
=
stream
->
read_1bytes
();
}
// NALUnit
if
(
!
stream
->
require
(
NALUnitLength
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc NALU data failed. ret=%d"
,
ret
);
return
ret
;
}
// 7.3.1 NAL unit syntax, H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
if
((
ret
=
sample
->
add_sample
(
stream
->
current
(),
NALUnitLength
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hls add video sample failed. ret=%d"
,
ret
);
return
ret
;
}
stream
->
skip
(
NALUnitLength
);
i
+=
NAL_unit_length
+
1
+
NALUnitLength
;
}
}
else
{
// ignored.
}
srs_info
(
"video decoded, type=%d, codec=%d, avc=%d, time=%d, size=%d"
,
frame_type
,
video_codec_id
,
avc_packet_type
,
composition_time
,
size
);
return
ret
;
int
ret
=
ERROR_SUCCESS
;
sample
->
is_video
=
true
;
if
(
!
data
||
size
<=
0
)
{
srs_trace
(
"no video present, hls ignore it."
);
return
ret
;
}
if
((
ret
=
stream
->
initialize
((
char
*
)
data
,
size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// video decode
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video frame_type failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
frame_type
=
stream
->
read_1bytes
();
int8_t
codec_id
=
frame_type
&
0x0f
;
frame_type
=
(
frame_type
>>
4
)
&
0x0f
;
sample
->
frame_type
=
(
SrsCodecVideoAVCFrame
)
frame_type
;
// only support h.264/avc
if
(
codec_id
!=
SrsCodecVideoAVC
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls only support video h.264/avc codec. ret=%d"
,
ret
);
return
ret
;
}
video_codec_id
=
codec_id
;
if
(
!
stream
->
require
(
4
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc_packet_type failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
avc_packet_type
=
stream
->
read_1bytes
();
int32_t
composition_time
=
stream
->
read_3bytes
();
// pts = dts + cts.
sample
->
cts
=
composition_time
;
sample
->
avc_packet_type
=
(
SrsCodecVideoAVCType
)
avc_packet_type
;
if
(
avc_packet_type
==
SrsCodecVideoAVCTypeSequenceHeader
)
{
// AVCDecoderConfigurationRecord
// 5.2.4.1.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
avc_extra_size
=
stream
->
left
();
if
(
avc_extra_size
>
0
)
{
srs_freepa
(
avc_extra_data
);
avc_extra_data
=
new
char
[
avc_extra_size
];
memcpy
(
avc_extra_data
,
stream
->
current
(),
avc_extra_size
);
}
if
(
!
stream
->
require
(
6
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header failed. ret=%d"
,
ret
);
return
ret
;
}
//int8_t configurationVersion = stream->read_1bytes();
//int8_t AVCProfileIndication = stream->read_1bytes();
//int8_t profile_compatibility = stream->read_1bytes();
//int8_t AVCLevelIndication = stream->read_1bytes();
stream
->
skip
(
4
);
// parse the NALU size.
int8_t
lengthSizeMinusOne
=
stream
->
read_1bytes
();
lengthSizeMinusOne
&=
0x03
;
NAL_unit_length
=
lengthSizeMinusOne
;
// 1 sps
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
numOfSequenceParameterSets
=
stream
->
read_1bytes
();
numOfSequenceParameterSets
&=
0x1f
;
if
(
numOfSequenceParameterSets
!=
1
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
!
stream
->
require
(
2
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps size failed. ret=%d"
,
ret
);
return
ret
;
}
sequenceParameterSetLength
=
stream
->
read_2bytes
();
if
(
!
stream
->
require
(
sequenceParameterSetLength
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header sps data failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
sequenceParameterSetLength
>
0
)
{
srs_freepa
(
sequenceParameterSetNALUnit
);
sequenceParameterSetNALUnit
=
new
char
[
sequenceParameterSetLength
];
memcpy
(
sequenceParameterSetNALUnit
,
stream
->
current
(),
sequenceParameterSetLength
);
stream
->
skip
(
sequenceParameterSetLength
);
}
// 1 pps
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
numOfPictureParameterSets
=
stream
->
read_1bytes
();
numOfPictureParameterSets
&=
0x1f
;
if
(
numOfPictureParameterSets
!=
1
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
!
stream
->
require
(
2
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps size failed. ret=%d"
,
ret
);
return
ret
;
}
pictureParameterSetLength
=
stream
->
read_2bytes
();
if
(
!
stream
->
require
(
pictureParameterSetLength
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc sequenc header pps data failed. ret=%d"
,
ret
);
return
ret
;
}
if
(
pictureParameterSetLength
>
0
)
{
srs_freepa
(
pictureParameterSetNALUnit
);
pictureParameterSetNALUnit
=
new
char
[
pictureParameterSetLength
];
memcpy
(
pictureParameterSetNALUnit
,
stream
->
current
(),
pictureParameterSetLength
);
stream
->
skip
(
pictureParameterSetLength
);
}
}
else
if
(
avc_packet_type
==
SrsCodecVideoAVCTypeNALU
){
// ensure the sequence header demuxed
if
(
avc_extra_size
<=
0
||
!
avc_extra_data
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc failed, sequence header not found. ret=%d"
,
ret
);
return
ret
;
}
// One or more NALUs (Full frames are required)
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 20
int
PictureLength
=
stream
->
left
();
for
(
int
i
=
0
;
i
<
PictureLength
;)
{
if
(
!
stream
->
require
(
NAL_unit_length
+
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc NALU size failed. ret=%d"
,
ret
);
return
ret
;
}
int32_t
NALUnitLength
=
0
;
if
(
NAL_unit_length
==
3
)
{
NALUnitLength
=
stream
->
read_4bytes
();
}
else
if
(
NALUnitLength
==
2
)
{
NALUnitLength
=
stream
->
read_3bytes
();
}
else
if
(
NALUnitLength
==
1
)
{
NALUnitLength
=
stream
->
read_2bytes
();
}
else
{
NALUnitLength
=
stream
->
read_1bytes
();
}
// NALUnit
if
(
!
stream
->
require
(
NALUnitLength
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"hls decode video avc NALU data failed. ret=%d"
,
ret
);
return
ret
;
}
// 7.3.1 NAL unit syntax, H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
if
((
ret
=
sample
->
add_sample
(
stream
->
current
(),
NALUnitLength
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hls add video sample failed. ret=%d"
,
ret
);
return
ret
;
}
stream
->
skip
(
NALUnitLength
);
i
+=
NAL_unit_length
+
1
+
NALUnitLength
;
}
}
else
{
// ignored.
}
srs_info
(
"video decoded, type=%d, codec=%d, avc=%d, time=%d, size=%d"
,
frame_type
,
video_codec_id
,
avc_packet_type
,
composition_time
,
size
);
return
ret
;
}
bool
SrsCodec
::
video_is_keyframe
(
int8_t
*
data
,
int
size
)
{
// 2bytes required.
if
(
size
<
1
)
{
return
false
;
}
char
frame_type
=
*
(
char
*
)
data
;
frame_type
=
(
frame_type
>>
4
)
&
0x0F
;
return
frame_type
==
SrsCodecVideoAVCFrameKeyFrame
;
// 2bytes required.
if
(
size
<
1
)
{
return
false
;
}
char
frame_type
=
*
(
char
*
)
data
;
frame_type
=
(
frame_type
>>
4
)
&
0x0F
;
return
frame_type
==
SrsCodecVideoAVCFrameKeyFrame
;
}
bool
SrsCodec
::
video_is_sequence_header
(
int8_t
*
data
,
int
size
)
{
// sequence header only for h264
if
(
!
video_is_h264
(
data
,
size
))
{
return
false
;
}
// 2bytes required.
if
(
size
<
2
)
{
return
false
;
}
char
frame_type
=
*
(
char
*
)
data
;
frame_type
=
(
frame_type
>>
4
)
&
0x0F
;
char
avc_packet_type
=
*
(
char
*
)(
data
+
1
);
return
frame_type
==
SrsCodecVideoAVCFrameKeyFrame
&&
avc_packet_type
==
SrsCodecVideoAVCTypeSequenceHeader
;
// sequence header only for h264
if
(
!
video_is_h264
(
data
,
size
))
{
return
false
;
}
// 2bytes required.
if
(
size
<
2
)
{
return
false
;
}
char
frame_type
=
*
(
char
*
)
data
;
frame_type
=
(
frame_type
>>
4
)
&
0x0F
;
char
avc_packet_type
=
*
(
char
*
)(
data
+
1
);
return
frame_type
==
SrsCodecVideoAVCFrameKeyFrame
&&
avc_packet_type
==
SrsCodecVideoAVCTypeSequenceHeader
;
}
bool
SrsCodec
::
audio_is_sequence_header
(
int8_t
*
data
,
int
size
)
{
// sequence header only for aac
if
(
!
audio_is_aac
(
data
,
size
))
{
return
false
;
}
// 2bytes required.
if
(
size
<
2
)
{
return
false
;
}
char
aac_packet_type
=
*
(
char
*
)(
data
+
1
);
return
aac_packet_type
==
SrsCodecAudioTypeSequenceHeader
;
// sequence header only for aac
if
(
!
audio_is_aac
(
data
,
size
))
{
return
false
;
}
// 2bytes required.
if
(
size
<
2
)
{
return
false
;
}
char
aac_packet_type
=
*
(
char
*
)(
data
+
1
);
return
aac_packet_type
==
SrsCodecAudioTypeSequenceHeader
;
}
bool
SrsCodec
::
video_is_h264
(
int8_t
*
data
,
int
size
)
{
// 1bytes required.
if
(
size
<
1
)
{
return
false
;
}
char
codec_id
=
*
(
char
*
)
data
;
codec_id
=
codec_id
&
0x0F
;
return
codec_id
==
SrsCodecVideoAVC
;
// 1bytes required.
if
(
size
<
1
)
{
return
false
;
}
char
codec_id
=
*
(
char
*
)
data
;
codec_id
=
codec_id
&
0x0F
;
return
codec_id
==
SrsCodecVideoAVC
;
}
bool
SrsCodec
::
audio_is_aac
(
int8_t
*
data
,
int
size
)
{
// 1bytes required.
if
(
size
<
1
)
{
return
false
;
}
char
sound_format
=
*
(
char
*
)
data
;
sound_format
=
(
sound_format
>>
4
)
&
0x0F
;
return
sound_format
==
SrsCodecAudioAAC
;
// 1bytes required.
if
(
size
<
1
)
{
return
false
;
}
char
sound_format
=
*
(
char
*
)
data
;
sound_format
=
(
sound_format
>>
4
)
&
0x0F
;
return
sound_format
==
SrsCodecAudioAAC
;
}
...
...
trunk/src/app/srs_app_codec.hpp
查看文件 @
c85dde7
...
...
@@ -37,104 +37,104 @@ class SrsStream;
// E.4.3.1 VIDEODATA
// CodecID UB [4]
// Codec Identifier. The following values are defined:
// 2 = Sorenson H.263
// 3 = Screen video
// 4 = On2 VP6
// 5 = On2 VP6 with alpha channel
// 6 = Screen video version 2
// 7 = AVC
// 2 = Sorenson H.263
// 3 = Screen video
// 4 = On2 VP6
// 5 = On2 VP6 with alpha channel
// 6 = Screen video version 2
// 7 = AVC
enum
SrsCodecVideo
{
SrsCodecVideoReserved
=
0
,
SrsCodecVideoSorensonH263
=
2
,
SrsCodecVideoScreenVideo
=
3
,
SrsCodecVideoOn2VP6
=
4
,
SrsCodecVideoOn2VP6WithAlphaChannel
=
5
,
SrsCodecVideoScreenVideoVersion2
=
6
,
SrsCodecVideoAVC
=
7
,
SrsCodecVideoReserved
=
0
,
SrsCodecVideoSorensonH263
=
2
,
SrsCodecVideoScreenVideo
=
3
,
SrsCodecVideoOn2VP6
=
4
,
SrsCodecVideoOn2VP6WithAlphaChannel
=
5
,
SrsCodecVideoScreenVideoVersion2
=
6
,
SrsCodecVideoAVC
=
7
,
};
// E.4.3.1 VIDEODATA
// Frame Type UB [4]
// Type of video frame. The following values are defined:
// 1 = key frame (for AVC, a seekable frame)
// 2 = inter frame (for AVC, a non-seekable frame)
// 3 = disposable inter frame (H.263 only)
// 4 = generated key frame (reserved for server use only)
// 5 = video info/command frame
// 1 = key frame (for AVC, a seekable frame)
// 2 = inter frame (for AVC, a non-seekable frame)
// 3 = disposable inter frame (H.263 only)
// 4 = generated key frame (reserved for server use only)
// 5 = video info/command frame
enum
SrsCodecVideoAVCFrame
{
SrsCodecVideoAVCFrameReserved
=
0
,
SrsCodecVideoAVCFrameKeyFrame
=
1
,
SrsCodecVideoAVCFrameInterFrame
=
2
,
SrsCodecVideoAVCFrameDisposableInterFrame
=
3
,
SrsCodecVideoAVCFrameGeneratedKeyFrame
=
4
,
SrsCodecVideoAVCFrameVideoInfoFrame
=
5
,
SrsCodecVideoAVCFrameReserved
=
0
,
SrsCodecVideoAVCFrameKeyFrame
=
1
,
SrsCodecVideoAVCFrameInterFrame
=
2
,
SrsCodecVideoAVCFrameDisposableInterFrame
=
3
,
SrsCodecVideoAVCFrameGeneratedKeyFrame
=
4
,
SrsCodecVideoAVCFrameVideoInfoFrame
=
5
,
};
// AVCPacketType IF CodecID == 7 UI8
// The following values are defined:
// 0 = AVC sequence header
// 1 = AVC NALU
// 2 = AVC end of sequence (lower level NALU sequence ender is
// not required or supported)
// 0 = AVC sequence header
// 1 = AVC NALU
// 2 = AVC end of sequence (lower level NALU sequence ender is
// not required or supported)
enum
SrsCodecVideoAVCType
{
SrsCodecVideoAVCTypeReserved
=
-
1
,
SrsCodecVideoAVCTypeSequenceHeader
=
0
,
SrsCodecVideoAVCTypeNALU
=
1
,
SrsCodecVideoAVCTypeSequenceHeaderEOF
=
2
,
SrsCodecVideoAVCTypeReserved
=
-
1
,
SrsCodecVideoAVCTypeSequenceHeader
=
0
,
SrsCodecVideoAVCTypeNALU
=
1
,
SrsCodecVideoAVCTypeSequenceHeaderEOF
=
2
,
};
// SoundFormat UB [4]
// Format of SoundData. The following values are defined:
// 0 = Linear PCM, platform endian
// 1 = ADPCM
// 2 = MP3
// 3 = Linear PCM, little endian
// 4 = Nellymoser 16 kHz mono
// 5 = Nellymoser 8 kHz mono
// 6 = Nellymoser
// 7 = G.711 A-law logarithmic PCM
// 8 = G.711 mu-law logarithmic PCM
// 9 = reserved
// 10 = AAC
// 11 = Speex
// 14 = MP3 8 kHz
// 15 = Device-specific sound
// 0 = Linear PCM, platform endian
// 1 = ADPCM
// 2 = MP3
// 3 = Linear PCM, little endian
// 4 = Nellymoser 16 kHz mono
// 5 = Nellymoser 8 kHz mono
// 6 = Nellymoser
// 7 = G.711 A-law logarithmic PCM
// 8 = G.711 mu-law logarithmic PCM
// 9 = reserved
// 10 = AAC
// 11 = Speex
// 14 = MP3 8 kHz
// 15 = Device-specific sound
// Formats 7, 8, 14, and 15 are reserved.
// AAC is supported in Flash Player 9,0,115,0 and higher.
// Speex is supported in Flash Player 10 and higher.
enum
SrsCodecAudio
{
SrsCodecAudioLinearPCMPlatformEndian
=
0
,
SrsCodecAudioADPCM
=
1
,
SrsCodecAudioMP3
=
2
,
SrsCodecAudioLinearPCMLittleEndian
=
3
,
SrsCodecAudioNellymoser16kHzMono
=
4
,
SrsCodecAudioNellymoser8kHzMono
=
5
,
SrsCodecAudioNellymoser
=
6
,
SrsCodecAudioReservedG711AlawLogarithmicPCM
=
7
,
SrsCodecAudioReservedG711MuLawLogarithmicPCM
=
8
,
SrsCodecAudioReserved
=
9
,
SrsCodecAudioAAC
=
10
,
SrsCodecAudioSpeex
=
11
,
SrsCodecAudioReservedMP3_8kHz
=
14
,
SrsCodecAudioReservedDeviceSpecificSound
=
15
,
SrsCodecAudioLinearPCMPlatformEndian
=
0
,
SrsCodecAudioADPCM
=
1
,
SrsCodecAudioMP3
=
2
,
SrsCodecAudioLinearPCMLittleEndian
=
3
,
SrsCodecAudioNellymoser16kHzMono
=
4
,
SrsCodecAudioNellymoser8kHzMono
=
5
,
SrsCodecAudioNellymoser
=
6
,
SrsCodecAudioReservedG711AlawLogarithmicPCM
=
7
,
SrsCodecAudioReservedG711MuLawLogarithmicPCM
=
8
,
SrsCodecAudioReserved
=
9
,
SrsCodecAudioAAC
=
10
,
SrsCodecAudioSpeex
=
11
,
SrsCodecAudioReservedMP3_8kHz
=
14
,
SrsCodecAudioReservedDeviceSpecificSound
=
15
,
};
// AACPacketType IF SoundFormat == 10 UI8
// The following values are defined:
// 0 = AAC sequence header
// 1 = AAC raw
// 0 = AAC sequence header
// 1 = AAC raw
enum
SrsCodecAudioType
{
SrsCodecAudioTypeReserved
=
-
1
,
SrsCodecAudioTypeSequenceHeader
=
0
,
SrsCodecAudioTypeRawData
=
1
,
SrsCodecAudioTypeReserved
=
-
1
,
SrsCodecAudioTypeSequenceHeader
=
0
,
SrsCodecAudioTypeRawData
=
1
,
};
// Sampling rate. The following values are defined:
...
...
@@ -144,12 +144,12 @@ enum SrsCodecAudioType
// 3 = 44 kHz = 44100 Hz
enum
SrsCodecAudioSampleRate
{
SrsCodecAudioSampleRateReserved
=
-
1
,
SrsCodecAudioSampleRate5512
=
0
,
SrsCodecAudioSampleRate11025
=
1
,
SrsCodecAudioSampleRate22050
=
2
,
SrsCodecAudioSampleRate44100
=
3
,
SrsCodecAudioSampleRateReserved
=
-
1
,
SrsCodecAudioSampleRate5512
=
0
,
SrsCodecAudioSampleRate11025
=
1
,
SrsCodecAudioSampleRate22050
=
2
,
SrsCodecAudioSampleRate44100
=
3
,
};
// Size of each audio sample. This parameter only pertains to
...
...
@@ -159,10 +159,10 @@ enum SrsCodecAudioSampleRate
// 1 = 16-bit samples
enum
SrsCodecAudioSampleSize
{
SrsCodecAudioSampleSizeReserved
=
-
1
,
SrsCodecAudioSampleSize8bit
=
0
,
SrsCodecAudioSampleSize16bit
=
1
,
SrsCodecAudioSampleSizeReserved
=
-
1
,
SrsCodecAudioSampleSize8bit
=
0
,
SrsCodecAudioSampleSize16bit
=
1
,
};
// Mono or stereo sound
...
...
@@ -170,10 +170,10 @@ enum SrsCodecAudioSampleSize
// 1 = Stereo sound
enum
SrsCodecAudioSoundType
{
SrsCodecAudioSoundTypeReserved
=
-
1
,
SrsCodecAudioSoundTypeMono
=
0
,
SrsCodecAudioSoundTypeStereo
=
1
,
SrsCodecAudioSoundTypeReserved
=
-
1
,
SrsCodecAudioSoundTypeMono
=
0
,
SrsCodecAudioSoundTypeStereo
=
1
,
};
/**
...
...
@@ -181,21 +181,21 @@ enum SrsCodecAudioSoundType
*/
struct
SrsCodecBuffer
{
/**
* @remark user must manage the bytes.
*/
int
size
;
char
*
bytes
;
SrsCodecBuffer
();
void
append
(
void
*
data
,
int
len
);
/**
* free the bytes,
* user can invoke it to free the bytes,
* the SrsCodecBuffer never free automatically.
*/
void
free
();
/**
* @remark user must manage the bytes.
*/
int
size
;
char
*
bytes
;
SrsCodecBuffer
();
void
append
(
void
*
data
,
int
len
);
/**
* free the bytes,
* user can invoke it to free the bytes,
* the SrsCodecBuffer never free automatically.
*/
void
free
();
};
/**
...
...
@@ -204,26 +204,26 @@ struct SrsCodecBuffer
class
SrsCodecSample
{
public
:
int
nb_buffers
;
SrsCodecBuffer
buffers
[
SRS_MAX_CODEC_SAMPLE
];
int
nb_buffers
;
SrsCodecBuffer
buffers
[
SRS_MAX_CODEC_SAMPLE
];
public
:
bool
is_video
;
// video specified
SrsCodecVideoAVCFrame
frame_type
;
SrsCodecVideoAVCType
avc_packet_type
;
// CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
// cts = pts - dts, where dts = flvheader->timestamp.
int32_t
cts
;
// audio specified
SrsCodecAudioSampleRate
sound_rate
;
SrsCodecAudioSampleSize
sound_size
;
SrsCodecAudioSoundType
sound_type
;
SrsCodecAudioType
aac_packet_type
;
bool
is_video
;
// video specified
SrsCodecVideoAVCFrame
frame_type
;
SrsCodecVideoAVCType
avc_packet_type
;
// CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
// cts = pts - dts, where dts = flvheader->timestamp.
int32_t
cts
;
// audio specified
SrsCodecAudioSampleRate
sound_rate
;
SrsCodecAudioSampleSize
sound_size
;
SrsCodecAudioSoundType
sound_type
;
SrsCodecAudioType
aac_packet_type
;
public
:
SrsCodecSample
();
virtual
~
SrsCodecSample
();
void
clear
();
int
add_sample
(
char
*
bytes
,
int
size
);
SrsCodecSample
();
virtual
~
SrsCodecSample
();
void
clear
();
int
add_sample
(
char
*
bytes
,
int
size
);
};
/**
...
...
@@ -232,81 +232,81 @@ public:
class
SrsCodec
{
private
:
SrsStream
*
stream
;
SrsStream
*
stream
;
public
:
/**
* video specified
*/
// @see: SrsCodecVideo
int
video_codec_id
;
// profile_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
u_int8_t
avc_profile
;
// level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
u_int8_t
avc_level
;
int
width
;
int
height
;
int
video_data_rate
;
// in bps
int
frame_rate
;
int
duration
;
// lengthSizeMinusOne, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
int8_t
NAL_unit_length
;
u_int16_t
sequenceParameterSetLength
;
char
*
sequenceParameterSetNALUnit
;
u_int16_t
pictureParameterSetLength
;
char
*
pictureParameterSetNALUnit
;
/**
* audio specified
*/
// @see: SrsCodecAudioType
int
audio_codec_id
;
int
audio_data_rate
;
// in bps
// 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33.
// audioObjectType, value defines in 7.1 Profiles, aac-iso-13818-7.pdf, page 40.
u_int8_t
aac_profile
;
// samplingFrequencyIndex
u_int8_t
aac_sample_rate
;
// channelConfiguration
u_int8_t
aac_channels
;
// the avc extra data, the AVC sequence header,
// without the flv codec header,
// @see: ffmpeg, AVCodecContext::extradata
int
avc_extra_size
;
char
*
avc_extra_data
;
// the aac extra data, the AAC sequence header,
// without the flv codec header,
// @see: ffmpeg, AVCodecContext::extradata
int
aac_extra_size
;
char
*
aac_extra_data
;
/**
* video specified
*/
// @see: SrsCodecVideo
int
video_codec_id
;
// profile_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
u_int8_t
avc_profile
;
// level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
u_int8_t
avc_level
;
int
width
;
int
height
;
int
video_data_rate
;
// in bps
int
frame_rate
;
int
duration
;
// lengthSizeMinusOne, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
int8_t
NAL_unit_length
;
u_int16_t
sequenceParameterSetLength
;
char
*
sequenceParameterSetNALUnit
;
u_int16_t
pictureParameterSetLength
;
char
*
pictureParameterSetNALUnit
;
/**
* audio specified
*/
// @see: SrsCodecAudioType
int
audio_codec_id
;
int
audio_data_rate
;
// in bps
// 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33.
// audioObjectType, value defines in 7.1 Profiles, aac-iso-13818-7.pdf, page 40.
u_int8_t
aac_profile
;
// samplingFrequencyIndex
u_int8_t
aac_sample_rate
;
// channelConfiguration
u_int8_t
aac_channels
;
// the avc extra data, the AVC sequence header,
// without the flv codec header,
// @see: ffmpeg, AVCodecContext::extradata
int
avc_extra_size
;
char
*
avc_extra_data
;
// the aac extra data, the AAC sequence header,
// without the flv codec header,
// @see: ffmpeg, AVCodecContext::extradata
int
aac_extra_size
;
char
*
aac_extra_data
;
public
:
SrsCodec
();
virtual
~
SrsCodec
();
SrsCodec
();
virtual
~
SrsCodec
();
// the following function used for hls to build the codec info.
public:
virtual
int
audio_aac_demux
(
int8_t
*
data
,
int
size
,
SrsCodecSample
*
sample
);
virtual
int
video_avc_demux
(
int8_t
*
data
,
int
size
,
SrsCodecSample
*
sample
);
virtual
int
audio_aac_demux
(
int8_t
*
data
,
int
size
,
SrsCodecSample
*
sample
);
virtual
int
video_avc_demux
(
int8_t
*
data
,
int
size
,
SrsCodecSample
*
sample
);
// the following function used to finger out the flv/rtmp packet detail.
public:
/**
* only check the frame_type, not check the codec type.
*/
static
bool
video_is_keyframe
(
int8_t
*
data
,
int
size
);
/**
* check codec h264, keyframe, sequence header
*/
static
bool
video_is_sequence_header
(
int8_t
*
data
,
int
size
);
/**
* check codec aac, sequence header
*/
static
bool
audio_is_sequence_header
(
int8_t
*
data
,
int
size
);
/**
* check codec h264.
*/
static
bool
video_is_h264
(
int8_t
*
data
,
int
size
);
/**
* only check the frame_type, not check the codec type.
*/
static
bool
video_is_keyframe
(
int8_t
*
data
,
int
size
);
/**
* check codec h264, keyframe, sequence header
*/
static
bool
video_is_sequence_header
(
int8_t
*
data
,
int
size
);
/**
* check codec aac, sequence header
*/
static
bool
audio_is_sequence_header
(
int8_t
*
data
,
int
size
);
/**
* check codec h264.
*/
static
bool
video_is_h264
(
int8_t
*
data
,
int
size
);
private
:
/**
* check codec aac.
*/
static
bool
audio_is_aac
(
int8_t
*
data
,
int
size
);
/**
* check codec aac.
*/
static
bool
audio_is_aac
(
int8_t
*
data
,
int
size
);
};
#endif
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论