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 23:20:00 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
16afe7ddbb43a000b848679501a746cef25b07d7
16afe7dd
1 parent
4246be92
fix #250, support push MPEGTS over UDP to SRS. 2.0.111
隐藏空白字符变更
内嵌
并排对比
正在显示
7 个修改的文件
包含
505 行增加
和
249 行删除
README.md
trunk/src/app/srs_app_mpegts_udp.cpp
trunk/src/app/srs_app_mpegts_udp.hpp
trunk/src/core/srs_core.hpp
trunk/src/libs/srs_librtmp.cpp
trunk/src/protocol/srs_raw_avc.cpp
trunk/src/protocol/srs_raw_avc.hpp
README.md
查看文件 @
16afe7d
...
...
@@ -486,7 +486,7 @@ Supported operating systems and hardware:
).
1.
Support HLS(h.264+mp3) streaming, read
[
#301
](
https://github.com/winlinvip/simple-rtmp-server/issues/301
)
.
1.
[
dev
]
Support push MPEG-TS over UDP to SRS, read
1.
Support push MPEG-TS over UDP to SRS, read
[
#250
](
https://github.com/winlinvip/simple-rtmp-server/issues/250
)
.
1.
[
no-plan
]
Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech).
1.
[
no-plan
]
Support RTMP 302 redirect
[
#92
](
https://github.com/winlinvip/simple-rtmp-server/issues/92
)
.
...
...
@@ -525,6 +525,7 @@ Supported operating systems and hardware:
### SRS 2.0 history
*
v2.0, 2015-01-31, for
[
#250
](
https://github.com/winlinvip/simple-rtmp-server/issues/250
)
, support push MPEGTS over UDP to SRS. 2.0.111
*
v2.0, 2015-01-29, build libfdk-aac in ffmpeg. 2.0.108
*
v2.0, 2015-01-25, for
[
#301
](
https://github.com/winlinvip/simple-rtmp-server/issues/301
)
, hls support h.264+mp3, ok for vlc. 2.0.107
*
v2.0, 2015-01-25, for
[
#301
](
https://github.com/winlinvip/simple-rtmp-server/issues/301
)
, http ts stream support h.264+mp3. 2.0.106
...
...
trunk/src/app/srs_app_mpegts_udp.cpp
查看文件 @
16afe7d
...
...
@@ -76,10 +76,20 @@ int SrsMpegtsQueue::push(SrsSharedPtrMessage* msg)
{
int
ret
=
ERROR_SUCCESS
;
if
(
msgs
.
find
(
msg
->
timestamp
)
!=
msgs
.
end
())
{
srs_warn
(
"mpegts: free the msg for dts exists, dts=%"
PRId64
,
msg
->
timestamp
);
srs_freep
(
msg
);
return
ret
;
// TODO: FIXME: use right way.
for
(
int
i
=
0
;
i
<
10
;
i
++
)
{
if
(
msgs
.
find
(
msg
->
timestamp
)
==
msgs
.
end
())
{
break
;
}
// adjust the ts, add 1ms.
msg
->
timestamp
+=
1
;
if
(
i
>=
5
)
{
srs_warn
(
"mpegts: free the msg for dts exists, dts=%"
PRId64
,
msg
->
timestamp
);
srs_freep
(
msg
);
return
ret
;
}
}
if
(
msg
->
is_audio
())
{
...
...
@@ -114,6 +124,8 @@ SrsSharedPtrMessage* SrsMpegtsQueue::dequeue()
if
(
msg
->
is_video
())
{
nb_videos
--
;
}
return
msg
;
}
return
NULL
;
...
...
@@ -131,6 +143,7 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c)
stfd
=
NULL
;
stream_id
=
0
;
avc
=
new
SrsRawH264Stream
();
aac
=
new
SrsRawAacStream
();
h264_sps_changed
=
false
;
h264_pps_changed
=
false
;
h264_sps_pps_sent
=
false
;
...
...
@@ -145,6 +158,7 @@ SrsMpegtsOverUdp::~SrsMpegtsOverUdp()
srs_freep
(
stream
);
srs_freep
(
context
);
srs_freep
(
avc
);
srs_freep
(
aac
);
srs_freep
(
queue
);
}
...
...
@@ -309,6 +323,9 @@ int SrsMpegtsOverUdp::on_ts_message(SrsTsMessage* msg)
if
(
msg
->
channel
->
stream
==
SrsTsStreamVideoH264
)
{
return
on_ts_video
(
msg
,
&
avs
);
}
if
(
msg
->
channel
->
stream
==
SrsTsStreamAudioAAC
)
{
return
on_ts_audio
(
msg
,
&
avs
);
}
// TODO: FIXME: implements it.
return
ret
;
...
...
@@ -326,6 +343,10 @@ int SrsMpegtsOverUdp::on_ts_video(SrsTsMessage* msg, SrsStream* avs)
// ts tbn to flv tbn.
u_int32_t
dts
=
msg
->
dts
/
90
;
u_int32_t
pts
=
msg
->
dts
/
90
;
// the whole ts pes video packet must be a flv frame packet.
char
*
ibpframe
=
avs
->
data
()
+
avs
->
pos
();
int
ibpframe_size
=
avs
->
size
()
-
avs
->
pos
();
// send each frame.
while
(
!
avs
->
empty
())
{
...
...
@@ -342,59 +363,50 @@ int SrsMpegtsOverUdp::on_ts_video(SrsTsMessage* msg, SrsStream* avs)
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
)
{
// 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
)
{
continue
;
}
return
ret
;
}
// for video, drop others with same pts/dts.
break
;
}
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
;
}
h264_sps_changed
=
true
;
h264_sps
=
sps
;
if
(
h264_sps
==
sps
)
{
return
ret
;
if
((
ret
=
write_h264_sps_pps
(
dts
,
pts
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
continue
;
}
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
;
}
// 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
;
if
(
h264_pps
==
pps
)
{
continue
;
}
h264_pps_changed
=
true
;
h264_pps
=
pps
;
return
write_h264_sps_pps
(
dts
,
pts
);
if
((
ret
=
write_h264_sps_pps
(
dts
,
pts
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
continue
;
}
break
;
}
// ibp frame.
return
write_h264_ipb_frame
(
frame
,
frame_size
,
dts
,
pts
);
srs_info
(
"mpegts: demux avc ibp frame size=%d, dts=%d"
,
ibpframe_size
,
dts
);
return
write_h264_ipb_frame
(
ibpframe
,
ibpframe_size
,
dts
,
pts
);
}
int
SrsMpegtsOverUdp
::
write_h264_sps_pps
(
u_int32_t
dts
,
u_int32_t
pts
)
...
...
@@ -421,14 +433,18 @@ int SrsMpegtsOverUdp::write_h264_sps_pps(u_int32_t dts, u_int32_t pts)
return
ret
;
}
// the timestamp in rtmp message header is dts.
u_int32_t
timestamp
=
dts
;
if
((
ret
=
rtmp_write_packet
(
SrsCodecFlvTagVideo
,
timestamp
,
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
);
return
ret
;
}
int
SrsMpegtsOverUdp
::
write_h264_ipb_frame
(
char
*
frame
,
int
frame_size
,
u_int32_t
dts
,
u_int32_t
pts
)
...
...
@@ -459,6 +475,72 @@ int SrsMpegtsOverUdp::write_h264_ipb_frame(char* frame, int frame_size, u_int32_
return
rtmp_write_packet
(
SrsCodecFlvTagVideo
,
timestamp
,
flv
,
nb_flv
);
}
int
SrsMpegtsOverUdp
::
on_ts_audio
(
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
;
// send each frame.
while
(
!
avs
->
empty
())
{
char
*
frame
=
NULL
;
int
frame_size
=
0
;
SrsRawAacStreamCodec
codec
;
if
((
ret
=
aac
->
adts_demux
(
avs
,
&
frame
,
&
frame_size
,
codec
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// ignore invalid frame,
// * atleast 1bytes for aac to decode the data.
if
(
frame_size
<=
0
)
{
continue
;
}
srs_info
(
"mpegts: demux aac frame size=%d, dts=%d"
,
frame_size
,
dts
);
// generate sh.
if
(
aac_specific_config
.
empty
())
{
std
::
string
sh
;
if
((
ret
=
aac
->
mux_sequence_header
(
&
codec
,
sh
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
aac_specific_config
=
sh
;
codec
.
aac_packet_type
=
0
;
if
((
ret
=
write_audio_raw_frame
((
char
*
)
sh
.
data
(),
(
int
)
sh
.
length
(),
&
codec
,
dts
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
// audio raw data.
codec
.
aac_packet_type
=
1
;
if
((
ret
=
write_audio_raw_frame
(
frame
,
frame_size
,
&
codec
,
dts
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
return
ret
;
}
int
SrsMpegtsOverUdp
::
write_audio_raw_frame
(
char
*
frame
,
int
frame_size
,
SrsRawAacStreamCodec
*
codec
,
u_int32_t
dts
)
{
int
ret
=
ERROR_SUCCESS
;
char
*
data
=
NULL
;
int
size
=
0
;
if
((
ret
=
aac
->
mux_aac2flv
(
frame
,
frame_size
,
codec
,
dts
,
&
data
,
&
size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
rtmp_write_packet
(
SrsCodecFlvTagAudio
,
dts
,
data
,
size
);
}
int
SrsMpegtsOverUdp
::
rtmp_write_packet
(
char
type
,
u_int32_t
timestamp
,
char
*
data
,
int
size
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -482,6 +564,10 @@ int SrsMpegtsOverUdp::rtmp_write_packet(char type, u_int32_t timestamp, char* da
if
((
msg
=
queue
->
dequeue
())
==
NULL
)
{
break
;
}
// TODO: FIXME: use pithy print.
srs_info
(
"mpegts: send msg %s dts=%"
PRId64
", size=%d"
,
msg
->
is_audio
()
?
"A"
:
msg
->
is_video
()
?
"V"
:
"N"
,
msg
->
timestamp
,
msg
->
size
);
// send out encoded msg.
if
((
ret
=
client
->
send_and_free_message
(
msg
,
stream_id
))
!=
ERROR_SUCCESS
)
{
...
...
trunk/src/app/srs_app_mpegts_udp.hpp
查看文件 @
16afe7d
...
...
@@ -45,6 +45,8 @@ class SrsStSocket;
class
SrsRequest
;
class
SrsRawH264Stream
;
class
SrsSharedPtrMessage
;
class
SrsRawAacStream
;
class
SrsRawAacStreamCodec
;
#include <srs_app_st.hpp>
#include <srs_kernel_ts.hpp>
...
...
@@ -114,6 +116,10 @@ private:
std
::
string
h264_pps
;
bool
h264_pps_changed
;
bool
h264_sps_pps_sent
;
private
:
SrsRawAacStream
*
aac
;
std
::
string
aac_specific_config
;
private
:
SrsMpegtsQueue
*
queue
;
public
:
SrsMpegtsOverUdp
(
SrsConfDirective
*
c
);
...
...
@@ -126,9 +132,11 @@ 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
on_ts_audio
(
SrsTsMessage
*
msg
,
SrsStream
*
avs
);
virtual
int
write_audio_raw_frame
(
char
*
frame
,
int
frame_size
,
SrsRawAacStreamCodec
*
codec
,
u_int32_t
dts
);
private
:
virtual
int
rtmp_write_packet
(
char
type
,
u_int32_t
timestamp
,
char
*
data
,
int
size
);
private
:
// connect to rtmp output url.
...
...
trunk/src/core/srs_core.hpp
查看文件 @
16afe7d
...
...
@@ -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 11
0
#define VERSION_REVISION 11
1
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
...
...
trunk/src/libs/srs_librtmp.cpp
查看文件 @
16afe7d
...
...
@@ -81,9 +81,10 @@ struct Context
SimpleSocketStream
*
skt
;
int
stream_id
;
// for h264 raw stream,
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521
// the remux raw codec.
SrsRawH264Stream
avc_raw
;
SrsRawAacStream
aac_raw
;
// for h264 raw stream,
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521
SrsStream
h264_raw_stream
;
...
...
@@ -1073,106 +1074,44 @@ srs_bool srs_rtmp_is_onMetaData(char type, char* data, int size)
* directly write a audio frame.
*/
int
__srs_write_audio_raw_frame
(
Context
*
context
,
char
sound_format
,
char
sound_rate
,
char
sound_size
,
char
sound_type
,
char
aac_packet_type
,
char
*
frame
,
int
frame_size
,
u_int32_t
timestamp
char
*
frame
,
int
frame_size
,
SrsRawAacStreamCodec
*
codec
,
u_int32_t
timestamp
)
{
// for audio frame, there is 1 or 2 bytes header:
// 1bytes, SoundFormat|SoundRate|SoundSize|SoundType
// 1bytes, AACPacketType for SoundFormat == 10, 0 is sequence header.
int
size
=
frame_size
+
1
;
if
(
sound_format
==
SrsCodecAudioAAC
)
{
size
+=
1
;
}
char
*
data
=
new
char
[
size
];
char
*
p
=
data
;
u_int8_t
audio_header
=
sound_type
&
0x01
;
audio_header
|=
(
sound_size
<<
1
)
&
0x02
;
audio_header
|=
(
sound_rate
<<
2
)
&
0x0c
;
audio_header
|=
(
sound_format
<<
4
)
&
0xf0
;
*
p
++
=
audio_header
;
if
(
sound_format
==
SrsCodecAudioAAC
)
{
*
p
++
=
aac_packet_type
;
int
ret
=
ERROR_SUCCESS
;
char
*
data
=
NULL
;
int
size
=
0
;
if
((
ret
=
context
->
aac_raw
.
mux_aac2flv
(
frame
,
frame_size
,
codec
,
timestamp
,
&
data
,
&
size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
memcpy
(
p
,
frame
,
frame_size
);
return
srs_rtmp_write_packet
(
context
,
SRS_RTMP_TYPE_AUDIO
,
timestamp
,
data
,
size
);
}
/**
* write aac frame in adts.
*/
int
__srs_write_aac_adts_frame
(
Context
*
context
,
char
sound_format
,
char
sound_rate
,
char
sound_size
,
char
sound_type
,
char
aac_profile
,
char
aac_samplerate
,
char
aac_channel
,
char
*
frame
,
int
frame_size
,
u_int32_t
timestamp
int
__srs_write_aac_adts_frame
(
Context
*
context
,
SrsRawAacStreamCodec
*
codec
,
char
*
frame
,
int
frame_size
,
u_int32_t
timestamp
)
{
int
ret
=
ERROR_SUCCESS
;
// override the aac samplerate by user specified.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64146899
switch
(
sound_rate
)
{
case
SrsCodecAudioSampleRate11025
:
aac_samplerate
=
0x0a
;
break
;
case
SrsCodecAudioSampleRate22050
:
aac_samplerate
=
0x07
;
break
;
case
SrsCodecAudioSampleRate44100
:
aac_samplerate
=
0x04
;
break
;
default
:
break
;
}
// send out aac sequence header if not sent.
if
(
context
->
aac_specific_config
.
empty
())
{
char
ch
=
0
;
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf
// AudioSpecificConfig (), page 33
// 1.6.2.1 AudioSpecificConfig
// audioObjectType; 5 bslbf
ch
=
(
aac_profile
<<
3
)
&
0xf8
;
// 3bits left.
// samplingFrequencyIndex; 4 bslbf
ch
|=
(
aac_samplerate
>>
1
)
&
0x07
;
context
->
aac_specific_config
+=
ch
;
ch
=
(
aac_samplerate
<<
7
)
&
0x80
;
if
(
aac_samplerate
==
0x0f
)
{
return
ERROR_AAC_DATA_INVALID
;
}
// 7bits left.
// channelConfiguration; 4 bslbf
ch
|=
(
aac_channel
<<
3
)
&
0x78
;
// 3bits left.
// only support aac profile 1-4.
if
(
aac_profile
<
1
||
aac_profile
>
4
)
{
return
ERROR_AAC_DATA_INVALID
;
std
::
string
sh
;
if
((
ret
=
context
->
aac_raw
.
mux_sequence_header
(
codec
,
sh
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// GASpecificConfig(), page 451
// 4.4.1 Decoder configuration (GASpecificConfig)
// frameLengthFlag; 1 bslbf
// dependsOnCoreCoder; 1 bslbf
// extensionFlag; 1 bslbf
context
->
aac_specific_config
+=
ch
;
char
*
sh
=
(
char
*
)
context
->
aac_specific_config
.
data
();
int
nb_sh
=
(
int
)
context
->
aac_specific_config
.
length
();
if
((
ret
=
__srs_write_audio_raw_frame
(
context
,
sound_format
,
sound_rate
,
sound_size
,
sound_type
,
0
,
sh
,
nb_sh
,
timestamp
))
!=
ERROR_SUCCESS
)
{
context
->
aac_specific_config
=
sh
;
codec
->
aac_packet_type
=
0
;
if
((
ret
=
__srs_write_audio_raw_frame
(
context
,
(
char
*
)
sh
.
data
(),
(
int
)
sh
.
length
(),
codec
,
timestamp
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
return
__srs_write_audio_raw_frame
(
context
,
sound_format
,
sound_rate
,
sound_size
,
sound_type
,
1
,
frame
,
frame_size
,
timestamp
);
codec
->
aac_packet_type
=
1
;
return
__srs_write_audio_raw_frame
(
context
,
frame
,
frame_size
,
codec
,
timestamp
);
}
/**
...
...
@@ -1180,126 +1119,32 @@ int __srs_write_aac_adts_frame(Context* context,
*/
int
__srs_write_aac_adts_frames
(
Context
*
context
,
char
sound_format
,
char
sound_rate
,
char
sound_size
,
char
sound_type
,
char
*
frame
,
int
frame
_size
,
u_int32_t
timestamp
char
*
frame
s
,
int
frames
_size
,
u_int32_t
timestamp
)
{
int
ret
=
ERROR_SUCCESS
;
SrsStream
*
stream
=
&
context
->
aac_raw_stream
;
if
((
ret
=
stream
->
initialize
(
frame
,
frame
_size
))
!=
ERROR_SUCCESS
)
{
if
((
ret
=
stream
->
initialize
(
frame
s
,
frames
_size
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
while
(
!
stream
->
empty
())
{
int
adts_header_start
=
stream
->
pos
();
// decode the ADTS.
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75,
// 1.A.2.2 Audio_Data_Transport_Stream frame, ADTS
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64145885
// byte_alignment()
// adts_fixed_header:
// 12bits syncword,
// 16bits left.
// adts_variable_header:
// 28bits
// 12+16+28=56bits
// adts_error_check:
// 16bits if protection_absent
// 56+16=72bits
// if protection_absent:
// require(7bytes)=56bits
// else
// require(9bytes)=72bits
if
(
!
stream
->
require
(
7
))
{
return
ERROR_AAC_ADTS_HEADER
;
}
// for aac, the frame must be ADTS format.
if
(
!
srs_aac_startswith_adts
(
stream
))
{
return
ERROR_AAC_REQUIRED_ADTS
;
}
// Syncword 12 bslbf
stream
->
read_1bytes
();
// 4bits left.
// adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS
// ID 1 bslbf
// Layer 2 uimsbf
// protection_absent 1 bslbf
int8_t
fh0
=
(
stream
->
read_1bytes
()
&
0x0f
);
/*int8_t fh_id = (fh0 >> 3) & 0x01;*/
/*int8_t fh_layer = (fh0 >> 1) & 0x03;*/
int8_t
fh_protection_absent
=
fh0
&
0x01
;
int16_t
fh1
=
stream
->
read_2bytes
();
// Profile_ObjectType 2 uimsbf
// sampling_frequency_index 4 uimsbf
// private_bit 1 bslbf
// channel_configuration 3 uimsbf
// original/copy 1 bslbf
// home 1 bslbf
int8_t
fh_Profile_ObjectType
=
(
fh1
>>
14
)
&
0x03
;
int8_t
fh_sampling_frequency_index
=
(
fh1
>>
10
)
&
0x0f
;
/*int8_t fh_private_bit = (fh1 >> 9) & 0x01;*/
int8_t
fh_channel_configuration
=
(
fh1
>>
6
)
&
0x07
;
/*int8_t fh_original = (fh1 >> 5) & 0x01;*/
/*int8_t fh_home = (fh1 >> 4) & 0x01;*/
// @remark, Emphasis is removed,
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64154736
//int8_t fh_Emphasis = (fh1 >> 2) & 0x03;
// 4bits left.
// adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS
// copyright_identification_bit 1 bslbf
// copyright_identification_start 1 bslbf
/*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/
/*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/
// aac_frame_length 13 bslbf: Length of the frame including headers and error_check in bytes.
// use the left 2bits as the 13 and 12 bit,
// the aac_frame_length is 13bits, so we move 13-2=11.
int16_t
fh_aac_frame_length
=
(
fh1
<<
11
)
&
0x0800
;
int32_t
fh2
=
stream
->
read_3bytes
();
// aac_frame_length 13 bslbf: consume the first 13-2=11bits
// the fh2 is 24bits, so we move right 24-11=13.
fh_aac_frame_length
|=
(
fh2
>>
13
)
&
0x07ff
;
// adts_buffer_fullness 11 bslbf
/*int16_t fh_adts_buffer_fullness = (fh2 >> 2) & 0x7ff;*/
// no_raw_data_blocks_in_frame 2 uimsbf
/*int16_t fh_no_raw_data_blocks_in_frame = fh2 & 0x03;*/
// adts_error_check(), 1.A.2.2.3 Error detection
if
(
!
fh_protection_absent
)
{
if
(
!
stream
->
require
(
2
))
{
return
ERROR_AAC_ADTS_HEADER
;
}
// crc_check 16 Rpchof
/*int16_t crc_check = */
stream
->
read_2bytes
();
}
// TODO: check the fh_sampling_frequency_index
// TODO: check the fh_channel_configuration
// raw_data_blocks
int
adts_header_size
=
stream
->
pos
()
-
adts_header_start
;
int
raw_data_size
=
fh_aac_frame_length
-
adts_header_size
;
if
(
!
stream
->
require
(
raw_data_size
))
{
return
ERROR_AAC_ADTS_HEADER
;
char
*
frame
=
NULL
;
int
frame_size
=
0
;
SrsRawAacStreamCodec
codec
;
if
((
ret
=
context
->
aac_raw
.
adts_demux
(
stream
,
&
frame
,
&
frame_size
,
codec
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// the profile = object_id + 1
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78,
// Table 1. A.9 – MPEG-2 Audio profiles and MPEG-4 Audio object types
char
aac_profile
=
fh_Profile_ObjectType
+
1
;
char
*
raw_data
=
stream
->
data
()
+
stream
->
pos
();
if
((
ret
=
__srs_write_aac_adts_frame
(
context
,
sound_format
,
sound_rate
,
sound_size
,
sound_type
,
aac_profile
,
fh_sampling_frequency_index
,
fh_channel_configuration
,
raw_data
,
raw_data_size
,
timestamp
))
!=
ERROR_SUCCESS
)
{
// override by user specified.
codec
.
sound_format
=
sound_format
;
codec
.
sound_rate
=
sound_rate
;
codec
.
sound_size
=
sound_size
;
codec
.
sound_type
=
sound_type
;
if
((
ret
=
__srs_write_aac_adts_frame
(
context
,
&
codec
,
frame
,
frame_size
,
timestamp
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
stream
->
skip
(
raw_data_size
);
}
return
ret
;
...
...
@@ -1328,10 +1173,16 @@ int srs_audio_write_raw_frame(srs_rtmp_t rtmp,
sound_format
,
sound_rate
,
sound_size
,
sound_type
,
frame
,
frame_size
,
timestamp
);
}
else
{
// use codec info for aac.
SrsRawAacStreamCodec
codec
;
codec
.
sound_format
=
sound_format
;
codec
.
sound_rate
=
sound_rate
;
codec
.
sound_size
=
sound_size
;
codec
.
sound_type
=
sound_type
;
codec
.
aac_packet_type
=
0
;
// for other data, directly write frame.
return
__srs_write_audio_raw_frame
(
context
,
sound_format
,
sound_rate
,
sound_size
,
sound_type
,
0
,
frame
,
frame_size
,
timestamp
);
return
__srs_write_audio_raw_frame
(
context
,
frame
,
frame_size
,
&
codec
,
timestamp
);
}
...
...
trunk/src/protocol/srs_raw_avc.cpp
查看文件 @
16afe7d
...
...
@@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using
namespace
std
;
#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_core_autofree.hpp>
...
...
@@ -312,3 +313,254 @@ int SrsRawH264Stream::mux_avc2flv(string video, int8_t frame_type, int8_t avc_pa
return
ret
;
}
SrsRawAacStream
::
SrsRawAacStream
()
{
}
SrsRawAacStream
::~
SrsRawAacStream
()
{
}
int
SrsRawAacStream
::
adts_demux
(
SrsStream
*
stream
,
char
**
pframe
,
int
*
pnb_frame
,
SrsRawAacStreamCodec
&
codec
)
{
int
ret
=
ERROR_SUCCESS
;
while
(
!
stream
->
empty
())
{
int
adts_header_start
=
stream
->
pos
();
// decode the ADTS.
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75,
// 1.A.2.2 Audio_Data_Transport_Stream frame, ADTS
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64145885
// byte_alignment()
// adts_fixed_header:
// 12bits syncword,
// 16bits left.
// adts_variable_header:
// 28bits
// 12+16+28=56bits
// adts_error_check:
// 16bits if protection_absent
// 56+16=72bits
// if protection_absent:
// require(7bytes)=56bits
// else
// require(9bytes)=72bits
if
(
!
stream
->
require
(
7
))
{
return
ERROR_AAC_ADTS_HEADER
;
}
// for aac, the frame must be ADTS format.
if
(
!
srs_aac_startswith_adts
(
stream
))
{
return
ERROR_AAC_REQUIRED_ADTS
;
}
// Syncword 12 bslbf
stream
->
read_1bytes
();
// 4bits left.
// adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS
// ID 1 bslbf
// Layer 2 uimsbf
// protection_absent 1 bslbf
int8_t
fh0
=
(
stream
->
read_1bytes
()
&
0x0f
);
/*int8_t fh_id = (fh0 >> 3) & 0x01;*/
/*int8_t fh_layer = (fh0 >> 1) & 0x03;*/
int8_t
fh_protection_absent
=
fh0
&
0x01
;
int16_t
fh1
=
stream
->
read_2bytes
();
// Profile_ObjectType 2 uimsbf
// sampling_frequency_index 4 uimsbf
// private_bit 1 bslbf
// channel_configuration 3 uimsbf
// original/copy 1 bslbf
// home 1 bslbf
int8_t
fh_Profile_ObjectType
=
(
fh1
>>
14
)
&
0x03
;
int8_t
fh_sampling_frequency_index
=
(
fh1
>>
10
)
&
0x0f
;
/*int8_t fh_private_bit = (fh1 >> 9) & 0x01;*/
int8_t
fh_channel_configuration
=
(
fh1
>>
6
)
&
0x07
;
/*int8_t fh_original = (fh1 >> 5) & 0x01;*/
/*int8_t fh_home = (fh1 >> 4) & 0x01;*/
// @remark, Emphasis is removed,
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64154736
//int8_t fh_Emphasis = (fh1 >> 2) & 0x03;
// 4bits left.
// adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS
// copyright_identification_bit 1 bslbf
// copyright_identification_start 1 bslbf
/*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/
/*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/
// aac_frame_length 13 bslbf: Length of the frame including headers and error_check in bytes.
// use the left 2bits as the 13 and 12 bit,
// the aac_frame_length is 13bits, so we move 13-2=11.
int16_t
fh_aac_frame_length
=
(
fh1
<<
11
)
&
0x0800
;
int32_t
fh2
=
stream
->
read_3bytes
();
// aac_frame_length 13 bslbf: consume the first 13-2=11bits
// the fh2 is 24bits, so we move right 24-11=13.
fh_aac_frame_length
|=
(
fh2
>>
13
)
&
0x07ff
;
// adts_buffer_fullness 11 bslbf
/*int16_t fh_adts_buffer_fullness = (fh2 >> 2) & 0x7ff;*/
// no_raw_data_blocks_in_frame 2 uimsbf
/*int16_t fh_no_raw_data_blocks_in_frame = fh2 & 0x03;*/
// adts_error_check(), 1.A.2.2.3 Error detection
if
(
!
fh_protection_absent
)
{
if
(
!
stream
->
require
(
2
))
{
return
ERROR_AAC_ADTS_HEADER
;
}
// crc_check 16 Rpchof
/*int16_t crc_check = */
stream
->
read_2bytes
();
}
// TODO: check the fh_sampling_frequency_index
// TODO: check the fh_channel_configuration
// raw_data_blocks
int
adts_header_size
=
stream
->
pos
()
-
adts_header_start
;
int
raw_data_size
=
fh_aac_frame_length
-
adts_header_size
;
if
(
!
stream
->
require
(
raw_data_size
))
{
return
ERROR_AAC_ADTS_HEADER
;
}
// the profile = object_id + 1
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78,
// Table 1. A.9 ¨C MPEG-2 Audio profiles and MPEG-4 Audio object types
char
aac_profile
=
fh_Profile_ObjectType
+
1
;
// the codec info.
codec
.
protection_absent
=
fh_protection_absent
;
codec
.
Profile_ObjectType
=
fh_Profile_ObjectType
;
codec
.
sampling_frequency_index
=
fh_sampling_frequency_index
;
codec
.
channel_configuration
=
fh_channel_configuration
;
codec
.
aac_frame_length
=
fh_aac_frame_length
;
codec
.
aac_profile
=
aac_profile
;
codec
.
aac_samplerate
=
fh_sampling_frequency_index
;
codec
.
aac_channel
=
fh_channel_configuration
;
// @see srs_audio_write_raw_frame().
codec
.
sound_format
=
10
;
// AAC
if
(
fh_sampling_frequency_index
<=
0x0c
&&
fh_sampling_frequency_index
>
0x0a
)
{
codec
.
sound_rate
=
SrsCodecAudioSampleRate5512
;
}
else
if
(
fh_sampling_frequency_index
<=
0x0a
&&
fh_sampling_frequency_index
>
0x07
)
{
codec
.
sound_rate
=
SrsCodecAudioSampleRate11025
;
}
else
if
(
fh_sampling_frequency_index
<=
0x07
&&
fh_sampling_frequency_index
>
0x04
)
{
codec
.
sound_rate
=
SrsCodecAudioSampleRate22050
;
}
else
if
(
fh_sampling_frequency_index
<=
0x04
)
{
codec
.
sound_rate
=
SrsCodecAudioSampleRate44100
;
}
else
{
codec
.
sound_rate
=
SrsCodecAudioSampleRate44100
;
srs_warn
(
"adts invalid sample rate for flv, rate=%#x"
,
fh_sampling_frequency_index
);
}
codec
.
sound_size
=
srs_max
(
0
,
srs_min
(
1
,
fh_channel_configuration
-
1
));
// TODO: FIXME: finger it out the sound size by adts.
codec
.
sound_size
=
1
;
// 0(8bits) or 1(16bits).
// frame data.
*
pframe
=
stream
->
data
()
+
stream
->
pos
();
*
pnb_frame
=
raw_data_size
;
stream
->
skip
(
raw_data_size
);
break
;
}
return
ret
;
}
int
SrsRawAacStream
::
mux_sequence_header
(
SrsRawAacStreamCodec
*
codec
,
string
&
sh
)
{
int
ret
=
ERROR_SUCCESS
;
char
aac_channel
=
codec
->
aac_channel
;
char
aac_profile
=
codec
->
aac_profile
;
char
aac_samplerate
=
codec
->
aac_samplerate
;
// override the aac samplerate by user specified.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64146899
switch
(
codec
->
sound_rate
)
{
case
SrsCodecAudioSampleRate11025
:
aac_samplerate
=
0x0a
;
break
;
case
SrsCodecAudioSampleRate22050
:
aac_samplerate
=
0x07
;
break
;
case
SrsCodecAudioSampleRate44100
:
aac_samplerate
=
0x04
;
break
;
default
:
break
;
}
sh
=
""
;
char
ch
=
0
;
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf
// AudioSpecificConfig (), page 33
// 1.6.2.1 AudioSpecificConfig
// audioObjectType; 5 bslbf
ch
=
(
aac_profile
<<
3
)
&
0xf8
;
// 3bits left.
// samplingFrequencyIndex; 4 bslbf
ch
|=
(
aac_samplerate
>>
1
)
&
0x07
;
sh
+=
ch
;
ch
=
(
aac_samplerate
<<
7
)
&
0x80
;
if
(
aac_samplerate
==
0x0f
)
{
return
ERROR_AAC_DATA_INVALID
;
}
// 7bits left.
// channelConfiguration; 4 bslbf
ch
|=
(
aac_channel
<<
3
)
&
0x78
;
// 3bits left.
// only support aac profile 1-4.
if
(
aac_profile
<
1
||
aac_profile
>
4
)
{
return
ERROR_AAC_DATA_INVALID
;
}
// GASpecificConfig(), page 451
// 4.4.1 Decoder configuration (GASpecificConfig)
// frameLengthFlag; 1 bslbf
// dependsOnCoreCoder; 1 bslbf
// extensionFlag; 1 bslbf
sh
+=
ch
;
return
ret
;
}
int
SrsRawAacStream
::
mux_aac2flv
(
char
*
frame
,
int
nb_frame
,
SrsRawAacStreamCodec
*
codec
,
u_int32_t
dts
,
char
**
flv
,
int
*
nb_flv
)
{
int
ret
=
ERROR_SUCCESS
;
char
sound_format
=
codec
->
sound_format
;
char
sound_type
=
codec
->
sound_type
;
char
sound_size
=
codec
->
sound_size
;
char
sound_rate
=
codec
->
sound_rate
;
char
aac_packet_type
=
codec
->
aac_packet_type
;
// for audio frame, there is 1 or 2 bytes header:
// 1bytes, SoundFormat|SoundRate|SoundSize|SoundType
// 1bytes, AACPacketType for SoundFormat == 10, 0 is sequence header.
int
size
=
nb_frame
+
1
;
if
(
sound_format
==
SrsCodecAudioAAC
)
{
size
+=
1
;
}
char
*
data
=
new
char
[
size
];
char
*
p
=
data
;
u_int8_t
audio_header
=
sound_type
&
0x01
;
audio_header
|=
(
sound_size
<<
1
)
&
0x02
;
audio_header
|=
(
sound_rate
<<
2
)
&
0x0c
;
audio_header
|=
(
sound_format
<<
4
)
&
0xf0
;
*
p
++
=
audio_header
;
if
(
sound_format
==
SrsCodecAudioAAC
)
{
*
p
++
=
aac_packet_type
;
}
memcpy
(
p
,
frame
,
nb_frame
);
*
flv
=
data
;
*
nb_flv
=
size
;
return
ret
;
}
...
...
trunk/src/protocol/srs_raw_avc.hpp
查看文件 @
16afe7d
...
...
@@ -86,4 +86,62 @@ public:
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
);
};
/**
* the header of adts sample.
*/
struct
SrsRawAacStreamCodec
{
int8_t
protection_absent
;
int8_t
Profile_ObjectType
;
int8_t
sampling_frequency_index
;
int8_t
channel_configuration
;
int16_t
aac_frame_length
;
// calc by Profile_ObjectType+1
char
aac_profile
;
char
aac_samplerate
;
char
aac_channel
;
char
sound_format
;
char
sound_rate
;
char
sound_size
;
char
sound_type
;
// 0 for sh; 1 for raw data.
int8_t
aac_packet_type
;
};
/**
* the raw aac stream, in adts.
*/
class
SrsRawAacStream
{
public
:
SrsRawAacStream
();
virtual
~
SrsRawAacStream
();
public
:
/**
* demux the stream in adts format.
* @param stream the input stream bytes.
* @param pframe the output aac frame in stream. user should never free it.
* @param pnb_frame the output aac frame size.
* @param codec the output codec info.
*/
virtual
int
adts_demux
(
SrsStream
*
stream
,
char
**
pframe
,
int
*
pnb_frame
,
SrsRawAacStreamCodec
&
codec
);
/**
* aac raw data to aac packet, without flv payload header.
* mux the aac specific config to flv sequence header packet.
* @param sh output the sequence header.
*/
virtual
int
mux_sequence_header
(
SrsRawAacStreamCodec
*
codec
,
std
::
string
&
sh
);
/**
* mux the aac audio packet to flv audio packet.
* @param frame the aac raw data.
* @param nb_frame the count of aac frame.
* @param codec the codec info of aac.
* @param flv output the muxed flv packet.
* @param nb_flv output the muxed flv size.
*/
virtual
int
mux_aac2flv
(
char
*
frame
,
int
nb_frame
,
SrsRawAacStreamCodec
*
codec
,
u_int32_t
dts
,
char
**
flv
,
int
*
nb_flv
);
};
#endif
...
...
请
注册
或
登录
后发表评论