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
2015-01-31 19:46:55 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
70c8fe13c45508bd3e98930dd0e5fa4a99eafb21
70c8fe13
1 parent
66fccdbb
for #250, support h264 video for push mpegts over udp. 2.0.110
隐藏空白字符变更
内嵌
并排对比
正在显示
15 个修改的文件
包含
940 行增加
和
268 行删除
trunk/configure
trunk/ide/srs_upp/srs_upp.upp
trunk/ide/srs_vs2010/srs.vcxproj
trunk/ide/srs_vs2010/srs.vcxproj.filters
trunk/src/app/srs_app_edge.cpp
trunk/src/app/srs_app_mpegts_udp.cpp
trunk/src/app/srs_app_mpegts_udp.hpp
trunk/src/core/srs_core.hpp
trunk/src/kernel/srs_kernel_codec.hpp
trunk/src/kernel/srs_kernel_error.hpp
trunk/src/libs/srs_librtmp.cpp
trunk/src/protocol/srs_raw_avc.cpp
trunk/src/protocol/srs_raw_avc.hpp
trunk/src/protocol/srs_rtmp_utility.cpp
trunk/src/protocol/srs_rtmp_utility.hpp
trunk/configure
查看文件 @
70c8fe1
...
...
@@ -375,7 +375,8 @@ MODULE_ID="RTMP"
MODULE_DEPENDS
=(
"CORE"
"KERNEL"
)
ModuleLibIncs
=(
${
SRS_OBJS_DIR
}
${
LibSSLRoot
}
)
MODULE_FILES
=(
"srs_rtmp_amf0"
"srs_rtmp_io"
"srs_rtmp_stack"
"srs_rtmp_sdk"
"srs_rtmp_handshake"
"srs_rtmp_utility"
"srs_rtmp_msg_array"
"srs_rtmp_buffer"
)
"srs_rtmp_handshake"
"srs_rtmp_utility"
"srs_rtmp_msg_array"
"srs_rtmp_buffer"
"srs_raw_avc"
)
RTMP_INCS
=
"src/protocol"
;
MODULE_DIR
=
${
RTMP_INCS
}
. auto/modules.sh
RTMP_OBJS
=
"
${
MODULE_OBJS
[@]
}
"
#
...
...
trunk/ide/srs_upp/srs_upp.upp
查看文件 @
70c8fe1
...
...
@@ -45,6 +45,8 @@ file
../../src/kernel/srs_kernel_utility.hpp,
../../src/kernel/srs_kernel_utility.cpp,
protocol readonly separator,
../../src/protocol/srs_raw_avc.hpp,
../../src/protocol/srs_raw_avc.cpp,
../../src/protocol/srs_rtmp_amf0.hpp,
../../src/protocol/srs_rtmp_amf0.cpp,
../../src/protocol/srs_rtmp_buffer.hpp,
...
...
trunk/ide/srs_vs2010/srs.vcxproj
查看文件 @
70c8fe1
...
...
@@ -36,7 +36,7 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(ProjectDir)/../../src/core;$(ProjectDir)/../../src/kernel;$(ProjectDir)/../../src/protocol;$(ProjectDir)/../../src/app;$(ProjectDir)/../../src/libs;$(ProjectDir)/../../objs;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
...
...
@@ -116,6 +116,7 @@
<ClInclude Include="..\..\src\libs\srs_librtmp.hpp" />
<ClInclude Include="..\..\src\libs\srs_lib_bandwidth.hpp" />
<ClInclude Include="..\..\src\libs\srs_lib_simple_socket.hpp" />
<ClInclude Include="..\..\src\protocol\srs_raw_avc.hpp" />
<ClInclude Include="..\..\src\protocol\srs_rtmp_amf0.hpp" />
<ClInclude Include="..\..\src\protocol\srs_rtmp_buffer.hpp" />
<ClInclude Include="..\..\src\protocol\srs_rtmp_handshake.hpp" />
...
...
@@ -193,6 +194,7 @@
<ClCompile Include="..\..\src\libs\srs_lib_bandwidth.cpp" />
<ClCompile Include="..\..\src\libs\srs_lib_simple_socket.cpp" />
<ClCompile Include="..\..\src\main\srs_main_server.cpp" />
<ClCompile Include="..\..\src\protocol\srs_raw_avc.cpp" />
<ClCompile Include="..\..\src\protocol\srs_rtmp_amf0.cpp" />
<ClCompile Include="..\..\src\protocol\srs_rtmp_buffer.cpp" />
<ClCompile Include="..\..\src\protocol\srs_rtmp_handshake.cpp" />
...
...
trunk/ide/srs_vs2010/srs.vcxproj.filters
查看文件 @
70c8fe1
...
...
@@ -226,6 +226,9 @@
<ClCompile Include="..\..\src\app\srs_app_mpegts_udp.cpp">
<Filter>srs</Filter>
</ClCompile>
<ClCompile Include="..\..\src\protocol\srs_raw_avc.cpp">
<Filter>srs</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\app\srs_app_bandwidth.hpp">
...
...
@@ -414,6 +417,9 @@
<ClInclude Include="..\..\src\app\srs_app_mpegts_udp.hpp">
<Filter>srs</Filter>
</ClInclude>
<ClInclude Include="..\..\src\protocol\srs_raw_avc.hpp">
<Filter>srs</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="research">
...
...
trunk/src/app/srs_app_edge.cpp
查看文件 @
70c8fe1
...
...
@@ -447,7 +447,7 @@ int SrsEdgeForwarder::start()
}
if
((
ret
=
client
->
publish
(
req
->
stream
,
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"
connect with server
failed, stream=%s, stream_id=%d. ret=%d"
,
srs_error
(
"
publish
failed, stream=%s, stream_id=%d. ret=%d"
,
req
->
stream
.
c_str
(),
stream_id
,
ret
);
return
ret
;
}
...
...
trunk/src/app/srs_app_mpegts_udp.cpp
查看文件 @
70c8fe1
...
...
@@ -23,6 +23,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_app_mpegts_udp.hpp>
#ifdef SRS_AUTO_STREAM_CASTER
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
...
...
@@ -39,8 +42,12 @@ using namespace std;
#include <srs_kernel_file.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_utility.hpp>
#ifdef SRS_AUTO_STREAM_CASTER
#include <srs_rtmp_sdk.hpp>
#include <srs_app_st_socket.hpp>
#include <srs_rtmp_utility.hpp>
#include <srs_app_utility.hpp>
#include <srs_rtmp_amf0.hpp>
#include <srs_raw_avc.hpp>
ISrsUdpHandler
::
ISrsUdpHandler
()
{
...
...
@@ -56,13 +63,25 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c)
context
=
new
SrsTsContext
();
buffer
=
new
SrsSimpleBuffer
();
output
=
_srs_config
->
get_stream_caster_output
(
c
);
req
=
NULL
;
io
=
NULL
;
client
=
NULL
;
stfd
=
NULL
;
stream_id
=
0
;
avc
=
new
SrsRawH264Stream
();
h264_sps_changed
=
false
;
h264_pps_changed
=
false
;
h264_sps_pps_sent
=
false
;
}
SrsMpegtsOverUdp
::~
SrsMpegtsOverUdp
()
{
close
();
srs_freep
(
buffer
);
srs_freep
(
stream
);
srs_freep
(
context
);
srs_freep
(
avc
);
}
int
SrsMpegtsOverUdp
::
on_udp_packet
(
sockaddr_in
*
from
,
char
*
buf
,
int
nb_buf
)
...
...
@@ -207,8 +226,311 @@ int SrsMpegtsOverUdp::on_ts_message(SrsTsMessage* msg)
return
ret
;
}
// check supported codec
if
(
msg
->
channel
->
stream
!=
SrsTsStreamVideoH264
&&
msg
->
channel
->
stream
!=
SrsTsStreamAudioAAC
)
{
ret
=
ERROR_STREAM_CASTER_TS_CODEC
;
srs_error
(
"mpegts: unsupported stream codec=%d. ret=%d"
,
msg
->
channel
->
stream
,
ret
);
return
ret
;
}
// parse the stream.
SrsStream
avs
;
if
((
ret
=
avs
.
initialize
(
msg
->
payload
->
bytes
(),
msg
->
payload
->
length
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"mpegts: initialize av stream failed. ret=%d"
,
ret
);
return
ret
;
}
// publish audio or video.
if
(
msg
->
channel
->
stream
==
SrsTsStreamVideoH264
)
{
return
on_ts_video
(
msg
,
&
avs
);
}
// TODO: FIXME: implements it.
return
ret
;
}
int
SrsMpegtsOverUdp
::
on_ts_video
(
SrsTsMessage
*
msg
,
SrsStream
*
avs
)
{
int
ret
=
ERROR_SUCCESS
;
// ensure rtmp connected.
if
((
ret
=
connect
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// ts tbn to flv tbn.
u_int32_t
dts
=
msg
->
dts
/
90
;
u_int32_t
pts
=
msg
->
dts
/
90
;
// send each frame.
while
(
!
avs
->
empty
())
{
char
*
frame
=
NULL
;
int
frame_size
=
0
;
if
((
ret
=
avc
->
annexb_demux
(
avs
,
&
frame
,
&
frame_size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// ignore invalid frame,
// * atleast 1bytes for SPS to decode the type
// * ignore the auth bytes '09f0'
if
(
frame_size
<=
2
)
{
continue
;
}
// it may be return error, but we must process all packets.
if
((
ret
=
write_h264_raw_frame
(
frame
,
frame_size
,
dts
,
pts
))
!=
ERROR_SUCCESS
)
{
if
(
ret
=
ERROR_H264_DROP_BEFORE_SPS_PPS
)
{
continue
;
}
return
ret
;
}
}
return
ret
;
}
int
SrsMpegtsOverUdp
::
write_h264_raw_frame
(
char
*
frame
,
int
frame_size
,
u_int32_t
dts
,
u_int32_t
pts
)
{
int
ret
=
ERROR_SUCCESS
;
// for sps
if
(
avc
->
is_sps
(
frame
,
frame_size
))
{
std
::
string
sps
;
if
((
ret
=
avc
->
sps_demux
(
frame
,
frame_size
,
sps
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
h264_sps
==
sps
)
{
return
ret
;
}
h264_sps_changed
=
true
;
h264_sps
=
sps
;
return
write_h264_sps_pps
(
dts
,
pts
);
}
// for pps
if
(
avc
->
is_pps
(
frame
,
frame_size
))
{
std
::
string
pps
;
if
((
ret
=
avc
->
pps_demux
(
frame
,
frame_size
,
pps
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
h264_pps
==
pps
)
{
return
ret
;
}
h264_pps_changed
=
true
;
h264_pps
=
pps
;
return
write_h264_sps_pps
(
dts
,
pts
);
}
// ibp frame.
return
write_h264_ipb_frame
(
frame
,
frame_size
,
dts
,
pts
);
}
int
SrsMpegtsOverUdp
::
write_h264_sps_pps
(
u_int32_t
dts
,
u_int32_t
pts
)
{
int
ret
=
ERROR_SUCCESS
;
// only send when both sps and pps changed.
if
(
!
h264_sps_changed
||
!
h264_pps_changed
)
{
return
ret
;
}
// h264 raw to h264 packet.
std
::
string
sh
;
if
((
ret
=
avc
->
mux_sequence_header
(
h264_sps
,
h264_pps
,
dts
,
pts
,
sh
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// h264 packet to flv packet.
int8_t
frame_type
=
SrsCodecVideoAVCFrameKeyFrame
;
int8_t
avc_packet_type
=
SrsCodecVideoAVCTypeSequenceHeader
;
char
*
flv
=
NULL
;
int
nb_flv
=
0
;
if
((
ret
=
avc
->
mux_avc2flv
(
sh
,
frame_type
,
avc_packet_type
,
dts
,
pts
,
&
flv
,
&
nb_flv
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// reset sps and pps.
h264_sps_changed
=
false
;
h264_pps_changed
=
false
;
h264_sps_pps_sent
=
true
;
// the timestamp in rtmp message header is dts.
u_int32_t
timestamp
=
dts
;
return
rtmp_write_packet
(
SrsCodecFlvTagVideo
,
timestamp
,
flv
,
nb_flv
);
}
int
SrsMpegtsOverUdp
::
write_h264_ipb_frame
(
char
*
frame
,
int
frame_size
,
u_int32_t
dts
,
u_int32_t
pts
)
{
int
ret
=
ERROR_SUCCESS
;
// when sps or pps not sent, ignore the packet.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/203
if
(
!
h264_sps_pps_sent
)
{
return
ERROR_H264_DROP_BEFORE_SPS_PPS
;
}
std
::
string
ibp
;
int8_t
frame_type
;
if
((
ret
=
avc
->
mux_ipb_frame
(
frame
,
frame_size
,
dts
,
pts
,
ibp
,
frame_type
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int8_t
avc_packet_type
=
SrsCodecVideoAVCTypeNALU
;
char
*
flv
=
NULL
;
int
nb_flv
=
0
;
if
((
ret
=
avc
->
mux_avc2flv
(
ibp
,
frame_type
,
avc_packet_type
,
dts
,
pts
,
&
flv
,
&
nb_flv
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// the timestamp in rtmp message header is dts.
u_int32_t
timestamp
=
dts
;
return
rtmp_write_packet
(
SrsCodecFlvTagVideo
,
timestamp
,
flv
,
nb_flv
);
}
int
SrsMpegtsOverUdp
::
rtmp_write_packet
(
char
type
,
u_int32_t
timestamp
,
char
*
data
,
int
size
)
{
int
ret
=
ERROR_SUCCESS
;
SrsSharedPtrMessage
*
msg
=
NULL
;
if
((
ret
=
srs_rtmp_create_msg
(
type
,
timestamp
,
data
,
size
,
stream_id
,
&
msg
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
srs_assert
(
msg
);
// send out encoded msg.
if
((
ret
=
client
->
send_and_free_message
(
msg
,
stream_id
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
int
SrsMpegtsOverUdp
::
connect
()
{
int
ret
=
ERROR_SUCCESS
;
// when ok, ignore.
if
(
io
||
client
)
{
return
ret
;
}
// parse uri
if
(
!
req
)
{
req
=
new
SrsRequest
();
size_t
pos
=
string
::
npos
;
string
uri
=
req
->
tcUrl
=
output
;
// tcUrl, stream
if
((
pos
=
uri
.
rfind
(
"/"
))
!=
string
::
npos
)
{
req
->
stream
=
uri
.
substr
(
pos
+
1
);
req
->
tcUrl
=
uri
=
uri
.
substr
(
0
,
pos
);
}
srs_discovery_tc_url
(
req
->
tcUrl
,
req
->
schema
,
req
->
host
,
req
->
vhost
,
req
->
app
,
req
->
port
,
req
->
param
);
}
// connect host.
if
((
ret
=
srs_socket_connect
(
req
->
host
,
::
atoi
(
req
->
port
.
c_str
()),
ST_UTIME_NO_TIMEOUT
,
&
stfd
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"mpegts: connect server %s:%s failed. ret=%d"
,
req
->
host
.
c_str
(),
req
->
port
.
c_str
(),
ret
);
return
ret
;
}
io
=
new
SrsStSocket
(
stfd
);
client
=
new
SrsRtmpClient
(
io
);
client
->
set_recv_timeout
(
SRS_CONSTS_RTMP_RECV_TIMEOUT_US
);
client
->
set_send_timeout
(
SRS_CONSTS_RTMP_SEND_TIMEOUT_US
);
// connect to vhost/app
if
((
ret
=
client
->
handshake
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"mpegts: handshake with server failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
connect_app
(
req
->
host
,
req
->
port
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"mpegts: connect with server failed. ret=%d"
,
ret
);
return
ret
;
}
if
((
ret
=
client
->
create_stream
(
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"mpegts: connect with server failed, stream_id=%d. ret=%d"
,
stream_id
,
ret
);
return
ret
;
}
// publish.
if
((
ret
=
client
->
publish
(
req
->
stream
,
stream_id
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"mpegts: publish failed, stream=%s, stream_id=%d. ret=%d"
,
req
->
stream
.
c_str
(),
stream_id
,
ret
);
return
ret
;
}
return
ret
;
}
// TODO: FIXME: refine the connect_app.
int
SrsMpegtsOverUdp
::
connect_app
(
string
ep_server
,
string
ep_port
)
{
int
ret
=
ERROR_SUCCESS
;
// args of request takes the srs info.
if
(
req
->
args
==
NULL
)
{
req
->
args
=
SrsAmf0Any
::
object
();
}
// notify server the edge identity,
// @see https://github.com/winlinvip/simple-rtmp-server/issues/147
SrsAmf0Object
*
data
=
req
->
args
;
data
->
set
(
"srs_sig"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_KEY
));
data
->
set
(
"srs_server"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_KEY
" "
RTMP_SIG_SRS_VERSION
" ("
RTMP_SIG_SRS_URL_SHORT
")"
));
data
->
set
(
"srs_license"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_LICENSE
));
data
->
set
(
"srs_role"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_ROLE
));
data
->
set
(
"srs_url"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_URL
));
data
->
set
(
"srs_version"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_VERSION
));
data
->
set
(
"srs_site"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_WEB
));
data
->
set
(
"srs_email"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_EMAIL
));
data
->
set
(
"srs_copyright"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_COPYRIGHT
));
data
->
set
(
"srs_primary"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_PRIMARY
));
data
->
set
(
"srs_authors"
,
SrsAmf0Any
::
str
(
RTMP_SIG_SRS_AUTHROS
));
// for edge to directly get the id of client.
data
->
set
(
"srs_pid"
,
SrsAmf0Any
::
number
(
getpid
()));
data
->
set
(
"srs_id"
,
SrsAmf0Any
::
number
(
_srs_context
->
get_id
()));
// local ip of edge
std
::
vector
<
std
::
string
>
ips
=
srs_get_local_ipv4_ips
();
assert
(
_srs_config
->
get_stats_network
()
<
(
int
)
ips
.
size
());
std
::
string
local_ip
=
ips
[
_srs_config
->
get_stats_network
()];
data
->
set
(
"srs_server_ip"
,
SrsAmf0Any
::
str
(
local_ip
.
c_str
()));
// generate the tcUrl
std
::
string
param
=
""
;
std
::
string
tc_url
=
srs_generate_tc_url
(
ep_server
,
req
->
vhost
,
req
->
app
,
ep_port
,
param
);
// upnode server identity will show in the connect_app of client.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/160
// the debug_srs_upnode is config in vhost and default to true.
bool
debug_srs_upnode
=
_srs_config
->
get_debug_srs_upnode
(
req
->
vhost
);
if
((
ret
=
client
->
connect_app
(
req
->
app
,
tc_url
,
req
,
debug_srs_upnode
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"mpegts: connect with server failed, tcUrl=%s, dsu=%d. ret=%d"
,
tc_url
.
c_str
(),
debug_srs_upnode
,
ret
);
return
ret
;
}
return
ret
;
}
void
SrsMpegtsOverUdp
::
close
()
{
srs_freep
(
client
);
srs_freep
(
io
);
srs_freep
(
req
);
srs_close_stfd
(
stfd
);
}
#endif
...
...
trunk/src/app/srs_app_mpegts_udp.hpp
查看文件 @
70c8fe1
...
...
@@ -30,6 +30,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_core.hpp>
#ifdef SRS_AUTO_STREAM_CASTER
class
sockaddr_in
;
#include <string>
...
...
@@ -37,9 +39,12 @@ class SrsStream;
class
SrsTsContext
;
class
SrsConfDirective
;
class
SrsSimpleBuffer
;
class
SrsRtmpClient
;
class
SrsStSocket
;
class
SrsRequest
;
class
SrsRawH264Stream
;
#ifdef SRS_AUTO_STREAM_CASTER
#include <srs_app_st.hpp>
#include <srs_kernel_ts.hpp>
/**
...
...
@@ -74,6 +79,19 @@ private:
SrsTsContext
*
context
;
SrsSimpleBuffer
*
buffer
;
std
::
string
output
;
private
:
SrsRequest
*
req
;
st_netfd_t
stfd
;
SrsStSocket
*
io
;
SrsRtmpClient
*
client
;
int
stream_id
;
private
:
SrsRawH264Stream
*
avc
;
std
::
string
h264_sps
;
bool
h264_sps_changed
;
std
::
string
h264_pps
;
bool
h264_pps_changed
;
bool
h264_sps_pps_sent
;
public
:
SrsMpegtsOverUdp
(
SrsConfDirective
*
c
);
virtual
~
SrsMpegtsOverUdp
();
...
...
@@ -83,6 +101,19 @@ public:
// interface ISrsTsHandler
public:
virtual
int
on_ts_message
(
SrsTsMessage
*
msg
);
private
:
virtual
int
on_ts_video
(
SrsTsMessage
*
msg
,
SrsStream
*
avs
);
virtual
int
write_h264_raw_frame
(
char
*
frame
,
int
frame_size
,
u_int32_t
dts
,
u_int32_t
pts
);
virtual
int
write_h264_sps_pps
(
u_int32_t
dts
,
u_int32_t
pts
);
virtual
int
write_h264_ipb_frame
(
char
*
frame
,
int
frame_size
,
u_int32_t
dts
,
u_int32_t
pts
);
virtual
int
rtmp_write_packet
(
char
type
,
u_int32_t
timestamp
,
char
*
data
,
int
size
);
private
:
// connect to rtmp output url.
// @remark ignore when not connected, reconnect when disconnected.
virtual
int
connect
();
virtual
int
connect_app
(
std
::
string
ep_server
,
std
::
string
ep_port
);
// close the connected io and rtmp to ready to be re-connect.
virtual
void
close
();
};
#endif
...
...
trunk/src/core/srs_core.hpp
查看文件 @
70c8fe1
...
...
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 1
09
#define VERSION_REVISION 1
10
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
...
...
trunk/src/kernel/srs_kernel_codec.hpp
查看文件 @
70c8fe1
...
...
@@ -53,7 +53,7 @@ enum SrsCodecAudioType
// 5 = video info/command frame
enum
SrsCodecVideoAVCFrame
{
// set to the
max value
to reserved, for array map.
// set to the
zero
to reserved, for array map.
SrsCodecVideoAVCFrameReserved
=
0
,
SrsCodecVideoAVCFrameReserved1
=
6
,
...
...
@@ -91,7 +91,7 @@ enum SrsCodecVideoAVCType
// 7 = AVC
enum
SrsCodecVideo
{
// set to the
max value
to reserved, for array map.
// set to the
zero
to reserved, for array map.
SrsCodecVideoReserved
=
0
,
SrsCodecVideoReserved1
=
1
,
SrsCodecVideoReserved2
=
8
,
...
...
@@ -164,6 +164,22 @@ enum SrsCodecAudioSampleRate
};
/**
* E.4.1 FLV Tag, page 75
*/
enum
SrsCodecFlvTag
{
// set to the zero to reserved, for array map.
SrsCodecFlvTagReserved
=
0
,
// 8 = audio
SrsCodecFlvTagAudio
=
8
,
// 9 = video
SrsCodecFlvTagVideo
=
9
,
// 18 = script data
SrsCodecFlvTagScript
=
18
,
};
/**
* Annex E. The FLV File Format
* @see SrsAvcAacCodec for the media stream codec.
*/
...
...
trunk/src/kernel/srs_kernel_error.hpp
查看文件 @
70c8fe1
...
...
@@ -228,6 +228,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_STREAM_CASTER_TS_PMT 4018
#define ERROR_STREAM_CASTER_TS_PSE 4019
#define ERROR_STREAM_CASTER_TS_ES 4020
#define ERROR_STREAM_CASTER_TS_CODEC 4021
#define ERROR_STREAM_CASTER_AVC_SPS 4022
#define ERROR_STREAM_CASTER_AVC_PPS 4023
#define ERROR_STREAM_CASTER_FLV_TAG 4024
/**
* whether the error code is an system control error.
...
...
trunk/src/libs/srs_librtmp.cpp
查看文件 @
70c8fe1
...
...
@@ -47,6 +47,7 @@ using namespace std;
#include <srs_kernel_codec.hpp>
#include <srs_kernel_file.hpp>
#include <srs_lib_bandwidth.hpp>
#include <srs_raw_avc.hpp>
// kernel module.
ISrsLog
*
_srs_log
=
new
ISrsLog
();
...
...
@@ -82,6 +83,9 @@ struct Context
// for h264 raw stream,
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521
SrsRawH264Stream
avc_raw
;
// for h264 raw stream,
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521
SrsStream
h264_raw_stream
;
// about SPS, @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62
std
::
string
h264_sps
;
...
...
@@ -1021,44 +1025,16 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char*
Context
*
context
=
(
Context
*
)
rtmp
;
SrsSharedPtrMessage
*
msg
=
NULL
;
if
(
type
==
SRS_RTMP_TYPE_AUDIO
)
{
SrsMessageHeader
header
;
header
.
initialize_audio
(
size
,
timestamp
,
context
->
stream_id
);
msg
=
new
SrsSharedPtrMessage
();
if
((
ret
=
msg
->
create
(
&
header
,
data
,
size
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
data
);
return
ret
;
}
}
else
if
(
type
==
SRS_RTMP_TYPE_VIDEO
)
{
SrsMessageHeader
header
;
header
.
initialize_video
(
size
,
timestamp
,
context
->
stream_id
);
msg
=
new
SrsSharedPtrMessage
();
if
((
ret
=
msg
->
create
(
&
header
,
data
,
size
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
data
);
return
ret
;
}
}
else
if
(
type
==
SRS_RTMP_TYPE_SCRIPT
)
{
SrsMessageHeader
header
;
header
.
initialize_amf0_script
(
size
,
context
->
stream_id
);
msg
=
new
SrsSharedPtrMessage
();
if
((
ret
=
msg
->
create
(
&
header
,
data
,
size
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
data
);
return
ret
;
}
if
((
ret
=
srs_rtmp_create_msg
(
type
,
timestamp
,
data
,
size
,
context
->
stream_id
,
&
msg
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
msg
)
{
// send out encoded msg.
if
((
ret
=
context
->
rtmp
->
send_and_free_message
(
msg
,
context
->
stream_id
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
else
{
// directly free data if not sent out.
srs_freep
(
data
);
srs_assert
(
msg
);
// send out encoded msg.
if
((
ret
=
context
->
rtmp
->
send_and_free_message
(
msg
,
context
->
stream_id
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
...
...
@@ -1403,52 +1379,37 @@ int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size)
return
size
;
}
/**
* write h264 packet, with rtmp header.
* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame.
* @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU.
* @param h264_raw_data the h.264 raw data, user must free it.
* write h264 IPB-frame.
*/
int
__srs_write_h264_packet
(
Context
*
context
,
int8_t
frame_type
,
int8_t
avc_packet_type
,
char
*
h264_raw_data
,
int
h264_raw_size
,
u_int32_t
dts
,
u_int32_t
pts
int
__srs_write_h264_ipb_frame
(
Context
*
context
,
char
*
frame
,
int
frame_size
,
u_int32_t
dts
,
u_int32_t
pts
)
{
// the timestamp in rtmp message header is dts.
u_int32_t
timestamp
=
dts
;
// for h264 in RTMP video payload, there is 5bytes header:
// 1bytes, FrameType | CodecID
// 1bytes, AVCPacketType
// 3bytes, CompositionTime, the cts.
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
int
size
=
h264_raw_size
+
5
;
char
*
data
=
new
char
[
size
];
char
*
p
=
data
;
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
// Frame Type, Type of video frame.
// CodecID, Codec Identifier.
// set the rtmp header
*
p
++
=
(
frame_type
<<
4
)
|
SrsCodecVideoAVC
;
int
ret
=
ERROR_SUCCESS
;
// AVCPacketType
*
p
++
=
avc_packet_type
;
// when sps or pps not sent, ignore the packet.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/203
if
(
!
context
->
h264_sps_pps_sent
)
{
return
ERROR_H264_DROP_BEFORE_SPS_PPS
;
}
// CompositionTime
// pts = dts + cts, or
// cts = pts - dts.
// where cts is the header in rtmp video packet payload header.
u_int32_t
cts
=
pts
-
dts
;
char
*
pp
=
(
char
*
)
&
cts
;
*
p
++
=
pp
[
2
];
*
p
++
=
pp
[
1
];
*
p
++
=
pp
[
0
];
std
::
string
ibp
;
int8_t
frame_type
;
if
((
ret
=
context
->
avc_raw
.
mux_ipb_frame
(
frame
,
frame_size
,
dts
,
pts
,
ibp
,
frame_type
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// h.264 raw data.
memcpy
(
p
,
h264_raw_data
,
h264_raw_size
);
int8_t
avc_packet_type
=
SrsCodecVideoAVCTypeNALU
;
char
*
flv
=
NULL
;
int
nb_flv
=
0
;
if
((
ret
=
context
->
avc_raw
.
mux_avc2flv
(
ibp
,
frame_type
,
avc_packet_type
,
dts
,
pts
,
&
flv
,
&
nb_flv
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
srs_rtmp_write_packet
(
context
,
SRS_RTMP_TYPE_VIDEO
,
timestamp
,
data
,
size
);
// the timestamp in rtmp message header is dts.
u_int32_t
timestamp
=
dts
;
return
srs_rtmp_write_packet
(
context
,
SRS_RTMP_TYPE_VIDEO
,
timestamp
,
flv
,
nb_flv
);
}
/**
...
...
@@ -1463,78 +1424,19 @@ int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts)
return
ret
;
}
// 5bytes sps/pps header:
// configurationVersion, AVCProfileIndication, profile_compatibility,
// AVCLevelIndication, lengthSizeMinusOne
// 3bytes size of sps:
// numOfSequenceParameterSets, sequenceParameterSetLength(2B)
// Nbytes of sps.
// sequenceParameterSetNALUnit
// 3bytes size of pps:
// numOfPictureParameterSets, pictureParameterSetLength
// Nbytes of pps:
// pictureParameterSetNALUnit
int
nb_packet
=
5
+
3
+
(
int
)
context
->
h264_sps
.
length
()
+
3
+
(
int
)
context
->
h264_pps
.
length
();
char
*
packet
=
new
char
[
nb_packet
];
SrsAutoFree
(
char
,
packet
);
// use stream to generate the h264 packet.
SrsStream
stream
;
if
((
ret
=
stream
.
initialize
(
packet
,
nb_packet
))
!=
ERROR_SUCCESS
)
{
// h264 raw to h264 packet.
std
::
string
sh
;
if
((
ret
=
context
->
avc_raw
.
mux_sequence_header
(
context
->
h264_sps
,
context
->
h264_pps
,
dts
,
pts
,
sh
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// decode the SPS:
// @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62
if
(
true
)
{
srs_assert
((
int
)
context
->
h264_sps
.
length
()
>=
4
);
char
*
frame
=
(
char
*
)
context
->
h264_sps
.
data
();
// @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205
// Baseline profile profile_idc is 66(0x42).
// Main profile profile_idc is 77(0x4d).
// Extended profile profile_idc is 88(0x58).
u_int8_t
profile_idc
=
frame
[
1
];
//u_int8_t constraint_set = frame[2];
u_int8_t
level_idc
=
frame
[
3
];
// generate the sps/pps header
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// configurationVersion
stream
.
write_1bytes
(
0x01
);
// AVCProfileIndication
stream
.
write_1bytes
(
profile_idc
);
// profile_compatibility
stream
.
write_1bytes
(
0x00
);
// AVCLevelIndication
stream
.
write_1bytes
(
level_idc
);
// lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size,
// so we always set it to 0x03.
stream
.
write_1bytes
(
0x03
);
}
// sps
if
(
true
)
{
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// numOfSequenceParameterSets, always 1
stream
.
write_1bytes
(
0x01
);
// sequenceParameterSetLength
stream
.
write_2bytes
(
context
->
h264_sps
.
length
());
// sequenceParameterSetNALUnit
stream
.
write_string
(
context
->
h264_sps
);
}
// pps
if
(
true
)
{
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// numOfPictureParameterSets, always 1
stream
.
write_1bytes
(
0x01
);
// pictureParameterSetLength
stream
.
write_2bytes
(
context
->
h264_pps
.
length
());
// pictureParameterSetNALUnit
stream
.
write_string
(
context
->
h264_pps
);
// h264 packet to flv packet.
int8_t
frame_type
=
SrsCodecVideoAVCFrameKeyFrame
;
int8_t
avc_packet_type
=
SrsCodecVideoAVCTypeSequenceHeader
;
char
*
flv
=
NULL
;
int
nb_flv
=
0
;
if
((
ret
=
context
->
avc_raw
.
mux_avc2flv
(
sh
,
frame_type
,
avc_packet_type
,
dts
,
pts
,
&
flv
,
&
nb_flv
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// reset sps and pps.
...
...
@@ -1542,75 +1444,9 @@ int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts)
context
->
h264_pps_changed
=
false
;
context
->
h264_sps_pps_sent
=
true
;
// TODO: FIXME: for more profile.
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144
// send out h264 packet.
int8_t
frame_type
=
SrsCodecVideoAVCFrameKeyFrame
;
int8_t
avc_packet_type
=
SrsCodecVideoAVCTypeSequenceHeader
;
return
__srs_write_h264_packet
(
context
,
frame_type
,
avc_packet_type
,
packet
,
nb_packet
,
dts
,
pts
);
}
/**
* write h264 IPB-frame.
*/
int
__srs_write_h264_ipb_frame
(
Context
*
context
,
char
*
data
,
int
size
,
u_int32_t
dts
,
u_int32_t
pts
)
{
int
ret
=
ERROR_SUCCESS
;
// when sps or pps not sent, ignore the packet.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/203
if
(
!
context
->
h264_sps_pps_sent
)
{
return
ERROR_H264_DROP_BEFORE_SPS_PPS
;
}
// 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
// 7: SPS, 8: PPS, 5: I Frame, 1: P Frame
u_int8_t
nal_unit_type
=
(
char
)
data
[
0
]
&
0x1f
;
// 4bytes size of nalu:
// NALUnitLength
// Nbytes of nalu.
// NALUnit
int
nb_packet
=
4
+
size
;
char
*
packet
=
new
char
[
nb_packet
];
SrsAutoFree
(
char
,
packet
);
// use stream to generate the h264 packet.
SrsStream
stream
;
if
((
ret
=
stream
.
initialize
(
packet
,
nb_packet
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size
u_int32_t
NAL_unit_length
=
size
;
// mux the avc NALU in "ISO Base Media File Format"
// from H.264-AVC-ISO_IEC_14496-15.pdf, page 20
// NALUnitLength
stream
.
write_4bytes
(
NAL_unit_length
);
// NALUnit
stream
.
write_bytes
(
data
,
size
);
// send out h264 packet.
int8_t
frame_type
=
SrsCodecVideoAVCFrameInterFrame
;
if
(
nal_unit_type
!=
1
)
{
frame_type
=
SrsCodecVideoAVCFrameKeyFrame
;
}
int8_t
avc_packet_type
=
SrsCodecVideoAVCTypeNALU
;
return
__srs_write_h264_packet
(
context
,
frame_type
,
avc_packet_type
,
packet
,
nb_packet
,
dts
,
pts
);
return
ret
;
// the timestamp in rtmp message header is dts.
u_int32_t
timestamp
=
dts
;
return
srs_rtmp_write_packet
(
context
,
SRS_RTMP_TYPE_VIDEO
,
timestamp
,
flv
,
nb_flv
);
}
/**
...
...
@@ -1620,27 +1456,14 @@ int __srs_write_h264_raw_frame(Context* context,
char
*
frame
,
int
frame_size
,
u_int32_t
dts
,
u_int32_t
pts
)
{
int
ret
=
ERROR_SUCCESS
;
// ignore invalid frame,
// atleast 1bytes for SPS to decode the type
if
(
frame_size
<
1
)
{
return
ret
;
}
// 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
// 7: SPS, 8: PPS, 5: I Frame, 1: P Frame
u_int8_t
nal_unit_type
=
(
char
)
frame
[
0
]
&
0x1f
;
if
(
nal_unit_type
==
7
)
{
// atleast 1bytes for SPS to decode the type, profile, constrain and level.
if
(
frame_size
<
4
)
{
// for sps
if
(
context
->
avc_raw
.
is_sps
(
frame
,
frame_size
))
{
std
::
string
sps
;
if
((
ret
=
context
->
avc_raw
.
sps_demux
(
frame
,
frame_size
,
sps
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
std
::
string
sps
;
sps
.
append
(
frame
,
frame_size
);
if
(
context
->
h264_sps
==
sps
)
{
return
ERROR_H264_DUPLICATED_SPS
;
}
...
...
@@ -1648,10 +1471,14 @@ int __srs_write_h264_raw_frame(Context* context,
context
->
h264_sps
=
sps
;
return
__srs_write_h264_sps_pps
(
context
,
dts
,
pts
);
}
else
if
(
nal_unit_type
==
8
)
{
}
// for pps
if
(
context
->
avc_raw
.
is_pps
(
frame
,
frame_size
))
{
std
::
string
pps
;
pps
.
append
(
frame
,
frame_size
);
if
((
ret
=
context
->
avc_raw
.
pps_demux
(
frame
,
frame_size
,
pps
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
context
->
h264_pps
==
pps
)
{
return
ERROR_H264_DUPLICATED_PPS
;
...
...
@@ -1660,11 +1487,10 @@ int __srs_write_h264_raw_frame(Context* context,
context
->
h264_pps
=
pps
;
return
__srs_write_h264_sps_pps
(
context
,
dts
,
pts
);
}
else
{
return
__srs_write_h264_ipb_frame
(
context
,
frame
,
frame_size
,
dts
,
pts
);
}
return
ret
;
// ibp frame.
return
__srs_write_h264_ipb_frame
(
context
,
frame
,
frame_size
,
dts
,
pts
);
}
/**
...
...
@@ -1692,29 +1518,21 @@ int srs_h264_write_raw_frames(srs_rtmp_t rtmp,
// send each frame.
while
(
!
context
->
h264_raw_stream
.
empty
())
{
// each frame must prefixed by annexb format.
// about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
int
pnb_start_code
=
0
;
if
(
!
srs_avc_startswith_annexb
(
&
context
->
h264_raw_stream
,
&
pnb_start_code
))
{
return
ERROR_H264_API_NO_PREFIXED
;
char
*
frame
=
NULL
;
int
frame_size
=
0
;
bool
got_sps_pps
=
false
;
if
((
ret
=
context
->
avc_raw
.
annexb_demux
(
&
context
->
h264_raw_stream
,
&
frame
,
&
frame_size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int
start
=
context
->
h264_raw_stream
.
pos
()
+
pnb_start_code
;
// find the last frame prefixed by annexb format.
context
->
h264_raw_stream
.
skip
(
pnb_start_code
);
while
(
!
context
->
h264_raw_stream
.
empty
())
{
if
(
srs_avc_startswith_annexb
(
&
context
->
h264_raw_stream
,
NULL
))
{
break
;
}
context
->
h264_raw_stream
.
skip
(
1
);
// ignore invalid frame,
// atleast 1bytes for SPS to decode the type
if
(
frame_size
<=
0
)
{
continue
;
}
int
size
=
context
->
h264_raw_stream
.
pos
()
-
start
;
// send out the frame.
char
*
frame
=
context
->
h264_raw_stream
.
data
()
+
start
;
// it may be return error, but we must process all packets.
if
((
ret
=
__srs_write_h264_raw_frame
(
context
,
frame
,
size
,
dts
,
pts
))
!=
ERROR_SUCCESS
)
{
if
((
ret
=
__srs_write_h264_raw_frame
(
context
,
frame
,
frame_
size
,
dts
,
pts
))
!=
ERROR_SUCCESS
)
{
error_code_return
=
ret
;
// ignore known error, process all packets.
...
...
trunk/src/protocol/srs_raw_avc.cpp
0 → 100644
查看文件 @
70c8fe1
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_raw_avc.hpp>
#include <string.h>
using
namespace
std
;
#include <srs_kernel_error.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_codec.hpp>
SrsRawH264Stream
::
SrsRawH264Stream
()
{
}
SrsRawH264Stream
::~
SrsRawH264Stream
()
{
}
int
SrsRawH264Stream
::
annexb_demux
(
SrsStream
*
stream
,
char
**
pframe
,
int
*
pnb_frame
)
{
int
ret
=
ERROR_SUCCESS
;
*
pframe
=
NULL
;
*
pnb_frame
=
0
;
while
(
!
stream
->
empty
())
{
// each frame must prefixed by annexb format.
// about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
int
pnb_start_code
=
0
;
if
(
!
srs_avc_startswith_annexb
(
stream
,
&
pnb_start_code
))
{
return
ERROR_H264_API_NO_PREFIXED
;
}
int
start
=
stream
->
pos
()
+
pnb_start_code
;
// find the last frame prefixed by annexb format.
stream
->
skip
(
pnb_start_code
);
while
(
!
stream
->
empty
())
{
if
(
srs_avc_startswith_annexb
(
stream
,
NULL
))
{
break
;
}
stream
->
skip
(
1
);
}
// demux the frame.
*
pnb_frame
=
stream
->
pos
()
-
start
;
*
pframe
=
stream
->
data
()
+
start
;
break
;
}
return
ret
;
}
bool
SrsRawH264Stream
::
is_sps
(
char
*
frame
,
int
nb_frame
)
{
srs_assert
(
nb_frame
>
0
);
// 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
// 7: SPS, 8: PPS, 5: I Frame, 1: P Frame
u_int8_t
nal_unit_type
=
(
char
)
frame
[
0
]
&
0x1f
;
return
nal_unit_type
==
7
;
}
bool
SrsRawH264Stream
::
is_pps
(
char
*
frame
,
int
nb_frame
)
{
srs_assert
(
nb_frame
>
0
);
// 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
// 7: SPS, 8: PPS, 5: I Frame, 1: P Frame
u_int8_t
nal_unit_type
=
(
char
)
frame
[
0
]
&
0x1f
;
return
nal_unit_type
==
8
;
}
int
SrsRawH264Stream
::
sps_demux
(
char
*
frame
,
int
nb_frame
,
string
&
sps
)
{
int
ret
=
ERROR_SUCCESS
;
// atleast 1bytes for SPS to decode the type, profile, constrain and level.
if
(
nb_frame
<
4
)
{
return
ret
;
}
sps
=
""
;
if
(
nb_frame
>
0
)
{
sps
.
append
(
frame
,
nb_frame
);
}
// should never be empty.
if
(
sps
.
empty
())
{
return
ERROR_STREAM_CASTER_AVC_SPS
;
}
return
ret
;
}
int
SrsRawH264Stream
::
pps_demux
(
char
*
frame
,
int
nb_frame
,
string
&
pps
)
{
int
ret
=
ERROR_SUCCESS
;
pps
=
""
;
if
(
nb_frame
>
0
)
{
pps
.
append
(
frame
,
nb_frame
);
}
// should never be empty.
if
(
pps
.
empty
())
{
return
ERROR_STREAM_CASTER_AVC_PPS
;
}
return
ret
;
}
int
SrsRawH264Stream
::
mux_sequence_header
(
string
sps
,
string
pps
,
u_int32_t
dts
,
u_int32_t
pts
,
string
&
sh
)
{
int
ret
=
ERROR_SUCCESS
;
// 5bytes sps/pps header:
// configurationVersion, AVCProfileIndication, profile_compatibility,
// AVCLevelIndication, lengthSizeMinusOne
// 3bytes size of sps:
// numOfSequenceParameterSets, sequenceParameterSetLength(2B)
// Nbytes of sps.
// sequenceParameterSetNALUnit
// 3bytes size of pps:
// numOfPictureParameterSets, pictureParameterSetLength
// Nbytes of pps:
// pictureParameterSetNALUnit
int
nb_packet
=
5
+
3
+
(
int
)
sps
.
length
()
+
3
+
(
int
)
pps
.
length
();
char
*
packet
=
new
char
[
nb_packet
];
SrsAutoFree
(
char
,
packet
);
// use stream to generate the h264 packet.
SrsStream
stream
;
if
((
ret
=
stream
.
initialize
(
packet
,
nb_packet
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// decode the SPS:
// @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62
if
(
true
)
{
srs_assert
((
int
)
sps
.
length
()
>=
4
);
char
*
frame
=
(
char
*
)
sps
.
data
();
// @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205
// Baseline profile profile_idc is 66(0x42).
// Main profile profile_idc is 77(0x4d).
// Extended profile profile_idc is 88(0x58).
u_int8_t
profile_idc
=
frame
[
1
];
//u_int8_t constraint_set = frame[2];
u_int8_t
level_idc
=
frame
[
3
];
// generate the sps/pps header
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// configurationVersion
stream
.
write_1bytes
(
0x01
);
// AVCProfileIndication
stream
.
write_1bytes
(
profile_idc
);
// profile_compatibility
stream
.
write_1bytes
(
0x00
);
// AVCLevelIndication
stream
.
write_1bytes
(
level_idc
);
// lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size,
// so we always set it to 0x03.
stream
.
write_1bytes
(
0x03
);
}
// sps
if
(
true
)
{
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// numOfSequenceParameterSets, always 1
stream
.
write_1bytes
(
0x01
);
// sequenceParameterSetLength
stream
.
write_2bytes
(
sps
.
length
());
// sequenceParameterSetNALUnit
stream
.
write_string
(
sps
);
}
// pps
if
(
true
)
{
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// numOfPictureParameterSets, always 1
stream
.
write_1bytes
(
0x01
);
// pictureParameterSetLength
stream
.
write_2bytes
(
pps
.
length
());
// pictureParameterSetNALUnit
stream
.
write_string
(
pps
);
}
// TODO: FIXME: for more profile.
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144
sh
=
""
;
sh
.
append
(
packet
,
nb_packet
);
return
ret
;
}
int
SrsRawH264Stream
::
mux_ipb_frame
(
char
*
frame
,
int
nb_frame
,
u_int32_t
dts
,
u_int32_t
pts
,
string
&
ibp
,
int8_t
&
frame_type
)
{
int
ret
=
ERROR_SUCCESS
;
// 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
// 7: SPS, 8: PPS, 5: I Frame, 1: P Frame
u_int8_t
nal_unit_type
=
(
char
)
frame
[
0
]
&
0x1f
;
// 4bytes size of nalu:
// NALUnitLength
// Nbytes of nalu.
// NALUnit
int
nb_packet
=
4
+
nb_frame
;
char
*
packet
=
new
char
[
nb_packet
];
SrsAutoFree
(
char
,
packet
);
// use stream to generate the h264 packet.
SrsStream
stream
;
if
((
ret
=
stream
.
initialize
(
packet
,
nb_packet
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
// lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size
u_int32_t
NAL_unit_length
=
nb_frame
;
// mux the avc NALU in "ISO Base Media File Format"
// from H.264-AVC-ISO_IEC_14496-15.pdf, page 20
// NALUnitLength
stream
.
write_4bytes
(
NAL_unit_length
);
// NALUnit
stream
.
write_bytes
(
frame
,
nb_frame
);
// send out h264 packet.
frame_type
=
SrsCodecVideoAVCFrameInterFrame
;
if
(
nal_unit_type
!=
1
)
{
frame_type
=
SrsCodecVideoAVCFrameKeyFrame
;
}
ibp
=
""
;
ibp
.
append
(
packet
,
nb_packet
);
return
ret
;
}
int
SrsRawH264Stream
::
mux_avc2flv
(
string
video
,
int8_t
frame_type
,
int8_t
avc_packet_type
,
u_int32_t
dts
,
u_int32_t
pts
,
char
**
flv
,
int
*
nb_flv
)
{
int
ret
=
ERROR_SUCCESS
;
// for h264 in RTMP video payload, there is 5bytes header:
// 1bytes, FrameType | CodecID
// 1bytes, AVCPacketType
// 3bytes, CompositionTime, the cts.
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
int
size
=
video
.
length
()
+
5
;
char
*
data
=
new
char
[
size
];
char
*
p
=
data
;
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
// Frame Type, Type of video frame.
// CodecID, Codec Identifier.
// set the rtmp header
*
p
++
=
(
frame_type
<<
4
)
|
SrsCodecVideoAVC
;
// AVCPacketType
*
p
++
=
avc_packet_type
;
// CompositionTime
// pts = dts + cts, or
// cts = pts - dts.
// where cts is the header in rtmp video packet payload header.
u_int32_t
cts
=
pts
-
dts
;
char
*
pp
=
(
char
*
)
&
cts
;
*
p
++
=
pp
[
2
];
*
p
++
=
pp
[
1
];
*
p
++
=
pp
[
0
];
// h.264 raw data.
memcpy
(
p
,
video
.
data
(),
video
.
length
());
*
flv
=
data
;
*
nb_flv
=
size
;
return
ret
;
}
...
...
trunk/src/protocol/srs_raw_avc.hpp
0 → 100644
查看文件 @
70c8fe1
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_PROTOCOL_RAW_AVC_HPP
#define SRS_PROTOCOL_RAW_AVC_HPP
/*
#include <srs_raw_avc.hpp>
*/
#include <srs_core.hpp>
#include <string>
class
SrsStream
;
/**
* the raw h.264 stream, in annexb.
*/
class
SrsRawH264Stream
{
public
:
SrsRawH264Stream
();
virtual
~
SrsRawH264Stream
();
public
:
/**
* demux the stream in annexb format.
* @param stream the input stream bytes.
* @param pframe the output h.264 frame in stream. user should never free it.
* @param pnb_frame the output h.264 frame size.
*/
virtual
int
annexb_demux
(
SrsStream
*
stream
,
char
**
pframe
,
int
*
pnb_frame
);
/**
* whether the frame is sps or pps.
*/
virtual
bool
is_sps
(
char
*
frame
,
int
nb_frame
);
virtual
bool
is_pps
(
char
*
frame
,
int
nb_frame
);
/**
* demux the sps or pps to string.
* @param sps/pps output the sps/pps.
*/
virtual
int
sps_demux
(
char
*
frame
,
int
nb_frame
,
std
::
string
&
sps
);
virtual
int
pps_demux
(
char
*
frame
,
int
nb_frame
,
std
::
string
&
pps
);
public
:
/**
* h264 raw data to h264 packet, without flv payload header.
* mux the sps/pps to flv sequence header packet.
* @param sh output the sequence header.
*/
virtual
int
mux_sequence_header
(
std
::
string
sps
,
std
::
string
pps
,
u_int32_t
dts
,
u_int32_t
pts
,
std
::
string
&
sh
);
/**
* h264 raw data to h264 packet, without flv payload header.
* mux the ibp to flv ibp packet.
* @param ibp output the packet.
* @param frame_type output the frame type.
*/
virtual
int
mux_ipb_frame
(
char
*
frame
,
int
nb_frame
,
u_int32_t
dts
,
u_int32_t
pts
,
std
::
string
&
ibp
,
int8_t
&
frame_type
);
/**
* mux the avc video packet to flv video packet.
* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame.
* @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU.
* @param video the h.264 raw data.
* @param flv output the muxed flv packet.
* @param nb_flv output the muxed flv size.
*/
virtual
int
mux_avc2flv
(
std
::
string
video
,
int8_t
frame_type
,
int8_t
avc_packet_type
,
u_int32_t
dts
,
u_int32_t
pts
,
char
**
flv
,
int
*
nb_flv
);
};
#endif
...
...
trunk/src/protocol/srs_rtmp_utility.cpp
查看文件 @
70c8fe1
...
...
@@ -30,6 +30,7 @@ using namespace std;
#include <srs_kernel_utility.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_rtmp_stack.hpp>
#include <srs_kernel_codec.hpp>
void
srs_discovery_tc_url
(
string
tcUrl
,
...
...
@@ -287,3 +288,61 @@ int srs_chunk_header_c3(
return
p
-
cache
;
}
int
__srs_rtmp_create_msg
(
char
type
,
u_int32_t
timestamp
,
char
*
data
,
int
size
,
int
stream_id
,
SrsSharedPtrMessage
**
ppmsg
)
{
int
ret
=
ERROR_SUCCESS
;
*
ppmsg
=
NULL
;
SrsSharedPtrMessage
*
msg
=
NULL
;
if
(
type
==
SrsCodecFlvTagAudio
)
{
SrsMessageHeader
header
;
header
.
initialize_audio
(
size
,
timestamp
,
stream_id
);
msg
=
new
SrsSharedPtrMessage
();
if
((
ret
=
msg
->
create
(
&
header
,
data
,
size
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
msg
);
return
ret
;
}
}
else
if
(
type
==
SrsCodecFlvTagVideo
)
{
SrsMessageHeader
header
;
header
.
initialize_video
(
size
,
timestamp
,
stream_id
);
msg
=
new
SrsSharedPtrMessage
();
if
((
ret
=
msg
->
create
(
&
header
,
data
,
size
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
msg
);
return
ret
;
}
}
else
if
(
type
==
SrsCodecFlvTagScript
)
{
SrsMessageHeader
header
;
header
.
initialize_amf0_script
(
size
,
stream_id
);
msg
=
new
SrsSharedPtrMessage
();
if
((
ret
=
msg
->
create
(
&
header
,
data
,
size
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
msg
);
return
ret
;
}
}
else
{
ret
=
ERROR_STREAM_CASTER_FLV_TAG
;
srs_error
(
"rtmp unknown tag type=%#x. ret=%d"
,
type
,
ret
);
return
ret
;
}
*
ppmsg
=
msg
;
return
ret
;
}
int
srs_rtmp_create_msg
(
char
type
,
u_int32_t
timestamp
,
char
*
data
,
int
size
,
int
stream_id
,
SrsSharedPtrMessage
**
ppmsg
)
{
int
ret
=
ERROR_SUCCESS
;
// only when failed, we must free the data.
if
((
ret
=
__srs_rtmp_create_msg
(
type
,
timestamp
,
data
,
size
,
stream_id
,
ppmsg
))
!=
ERROR_SUCCESS
)
{
srs_freep
(
data
);
return
ret
;
}
return
ret
;
}
...
...
trunk/src/protocol/srs_rtmp_utility.hpp
查看文件 @
70c8fe1
...
...
@@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_kernel_consts.hpp>
class
SrsMessageHeader
;
class
SrsSharedPtrMessage
;
/**
* parse the tcUrl, output the schema, host, vhost, app and port.
...
...
@@ -110,5 +111,12 @@ extern int srs_chunk_header_c3(
char
*
cache
,
int
nb_cache
);
/**
* create shared ptr message from bytes.
* @param data the packet bytes. user should never free it.
* @param ppmsg output the shared ptr message. user should free it.
*/
extern
int
srs_rtmp_create_msg
(
char
type
,
u_int32_t
timestamp
,
char
*
data
,
int
size
,
int
stream_id
,
SrsSharedPtrMessage
**
ppmsg
);
#endif
...
...
请
注册
或
登录
后发表评论