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
2013-11-24 23:13:14 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
4fca9146944f8088382a437a0c5a4e4586dc84d6
4fca9146
1 parent
ca6720aa
support write ts file
显示空白字符变更
内嵌
并排对比
正在显示
7 个修改的文件
包含
441 行增加
和
9 行删除
README.md
trunk/configure
trunk/src/core/srs_core_codec.cpp
trunk/src/core/srs_core_codec.hpp
trunk/src/core/srs_core_error.hpp
trunk/src/core/srs_core_hls.cpp
trunk/src/core/srs_core_hls.hpp
README.md
查看文件 @
4fca914
...
...
@@ -50,6 +50,7 @@ url: rtmp://127.0.0.1:1935/live/livestream
*
nginx v1.5.0: 139524 lines
<br/>
### History
*
v0.5, 2013-11-24, support write ts file.
*
v0.5, 2013-11-21, add ts_info tool to demux ts file.
*
v0.5, 2013-11-16, add rtmp players(OSMF/jwplayer5/jwplayer6).
*
v0.4, 2013-11-10, v0.4 released. 12500 lines.
...
...
trunk/configure
100644 → 100755
查看文件 @
4fca914
trunk/src/core/srs_core_codec.cpp
查看文件 @
4fca914
...
...
@@ -24,12 +24,35 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_core_codec.hpp>
#include <string.h>
#include <stdlib.h>
#include <srs_core_error.hpp>
#include <srs_core_stream.hpp>
#include <srs_core_log.hpp>
#include <srs_core_autofree.hpp>
SrsCodecBuffer
::
SrsCodecBuffer
()
{
size
=
0
;
bytes
=
NULL
;
}
void
SrsCodecBuffer
::
append
(
void
*
data
,
int
len
)
{
srs_assert
(
data
);
srs_assert
(
len
>
0
);
bytes
=
(
char
*
)
realloc
(
bytes
,
size
+
len
);
memcpy
(
bytes
+
size
,
data
,
len
);
size
+=
len
;
}
void
SrsCodecBuffer
::
free
()
{
size
=
0
;
srs_freepa
(
bytes
);
}
SrsCodecSample
::
SrsCodecSample
()
{
clear
();
...
...
@@ -83,8 +106,11 @@ SrsCodec::SrsCodec()
video_codec_id
=
0
;
audio_data_rate
=
0
;
audio_codec_id
=
0
;
profile
=
0
;
level
=
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
;
...
...
@@ -160,6 +186,39 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample)
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
)
{
...
...
trunk/src/core/srs_core_codec.hpp
查看文件 @
4fca914
...
...
@@ -181,8 +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
();
};
/**
...
...
@@ -227,9 +240,9 @@ public:
// @see: SrsCodecVideo
int
video_codec_id
;
// profile_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
u_int8_t
profile
;
u_int8_t
avc_
profile
;
// level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
u_int8_t
level
;
u_int8_t
avc_
level
;
int
width
;
int
height
;
int
video_data_rate
;
// in bps
...
...
@@ -243,6 +256,13 @@ public:
// @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
...
...
trunk/src/core/srs_core_error.hpp
查看文件 @
4fca914
...
...
@@ -112,5 +112,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_HLS_BUSY 602
#define ERROR_HLS_OPEN_FAILED 603
#define ERROR_HLS_WRITE_FAILED 604
#define ERROR_HLS_AAC_FRAME_LENGTH 605
#define ERROR_HLS_AVC_SAMPLE_SIZE 606
#endif
\ No newline at end of file
...
...
trunk/src/core/srs_core_hls.cpp
查看文件 @
4fca914
...
...
@@ -26,6 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <srs_core_error.hpp>
#include <srs_core_codec.hpp>
...
...
@@ -275,18 +277,249 @@ u_int8_t mpegts_header[] = {
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
// @see: NGX_RTMP_HLS_DELAY, 700ms, ts_tbn=90000
#define SRS_HLS_DELAY 63000
// @see: ngx_rtmp_mpegts.c
// TODO: support full mpegts feature in future.
class
SrsMpegtsWriter
{
public
:
static
int
write_header
(
int
fd
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
::
write
(
fd
,
mpegts_header
,
sizeof
(
mpegts_header
))
!=
sizeof
(
mpegts_header
))
{
ret
=
ERROR_HLS_WRITE_FAILED
;
srs_error
(
"write ts file header failed. ret=%d"
,
ret
);
return
ret
;
}
return
ret
;
}
static
int
write_frame
(
int
fd
,
mpegts_frame
*
frame
,
SrsCodecBuffer
*
buffer
)
{
int
ret
=
ERROR_SUCCESS
;
char
*
last
=
buffer
->
bytes
+
buffer
->
size
;
char
*
pos
=
buffer
->
bytes
;
bool
first
=
true
;
while
(
pos
<
last
)
{
static
char
packet
[
188
];
char
*
p
=
packet
;
frame
->
cc
++
;
// sync_byte; //8bits
*
p
++
=
0x47
;
// pid; //13bits
*
p
++
=
(
frame
->
pid
>>
8
)
&
0x1f
;
// payload_unit_start_indicator; //1bit
if
(
first
)
{
p
[
-
1
]
|=
0x40
;
}
*
p
++
=
frame
->
pid
;
// transport_scrambling_control; //2bits
// adaption_field_control; //2bits, 0x01: PayloadOnly
// continuity_counter; //4bits
*
p
++
=
0x10
|
(
frame
->
cc
&
0x0f
);
if
(
first
)
{
first
=
false
;
if
(
frame
->
key
)
{
p
[
-
1
]
|=
0x20
;
// Both Adaption and Payload
*
p
++
=
7
;
// size
*
p
++
=
0x50
;
// random access + PCR
p
=
write_pcr
(
p
,
frame
->
dts
-
SRS_HLS_DELAY
);
}
// PES header
// packet_start_code_prefix; //24bits, '00 00 01'
*
p
++
=
0x00
;
*
p
++
=
0x00
;
*
p
++
=
0x01
;
//8bits
*
p
++
=
frame
->
sid
;
// pts(33bits) need 5bytes.
u_int8_t
header_size
=
5
;
u_int8_t
flags
=
0x80
;
// pts
// dts(33bits) need 5bytes also
if
(
frame
->
dts
!=
frame
->
pts
)
{
header_size
+=
5
;
flags
|=
0x40
;
// dts
}
// 3bytes: flag fields from PES_packet_length to PES_header_data_length
int
pes_size
=
(
last
-
pos
)
+
header_size
+
3
;
if
(
pes_size
>
0xffff
)
{
/**
* when actual packet length > 0xffff(65535),
* which exceed the max u_int16_t packet length,
* use 0 packet length, the next unit start indicates the end of packet.
*/
pes_size
=
0
;
}
// PES_packet_length; //16bits
*
p
++
=
(
pes_size
>>
8
);
*
p
++
=
pes_size
;
// PES_scrambling_control; //2bits, '10'
// PES_priority; //1bit
// data_alignment_indicator; //1bit
// copyright; //1bit
// original_or_copy; //1bit
*
p
++
=
0x80
;
/* H222 */
// PTS_DTS_flags; //2bits
// ESCR_flag; //1bit
// ES_rate_flag; //1bit
// DSM_trick_mode_flag; //1bit
// additional_copy_info_flag; //1bit
// PES_CRC_flag; //1bit
// PES_extension_flag; //1bit
*
p
++
=
flags
;
// PES_header_data_length; //8bits
*
p
++
=
header_size
;
// pts; // 33bits
p
=
write_pts
(
p
,
flags
>>
6
,
frame
->
pts
+
SRS_HLS_DELAY
);
// dts; // 33bits
if
(
frame
->
dts
!=
frame
->
pts
)
{
p
=
write_pts
(
p
,
1
,
frame
->
dts
+
SRS_HLS_DELAY
);
}
}
int
body_size
=
sizeof
(
packet
)
-
(
p
-
packet
);
int
in_size
=
last
-
pos
;
if
(
body_size
<=
in_size
)
{
memcpy
(
p
,
pos
,
body_size
);
pos
+=
body_size
;
}
else
{
p
=
fill_stuff
(
p
,
packet
,
body_size
,
in_size
);
memcpy
(
p
,
pos
,
in_size
);
pos
=
last
;
}
// write ts packet
if
(
::
write
(
fd
,
packet
,
sizeof
(
packet
))
!=
sizeof
(
packet
))
{
ret
=
ERROR_HLS_WRITE_FAILED
;
srs_error
(
"write ts file failed. ret=%d"
,
ret
);
return
ret
;
}
}
// write success, clear and free the buffer
buffer
->
free
();
return
ret
;
}
private
:
static
char
*
fill_stuff
(
char
*
pes_body_end
,
char
*
packet
,
int
body_size
,
int
in_size
)
{
char
*
p
=
pes_body_end
;
// insert the stuff bytes before PES body
int
stuff_size
=
(
body_size
-
in_size
);
// adaption_field_control; //2bits
if
(
packet
[
3
]
&
0x20
)
{
// has adaptation
// packet[4]: adaption_field_length
// packet[5]: adaption field data
// base: start of PES body
char
*
base
=
&
packet
[
5
]
+
packet
[
4
];
int
len
=
p
-
base
;
p
=
(
char
*
)
memmove
(
base
+
stuff_size
,
base
,
len
)
+
len
;
// increase the adaption field size.
packet
[
4
]
+=
stuff_size
;
return
p
;
}
// create adaption field.
// adaption_field_control; //2bits
packet
[
3
]
|=
0x20
;
// base: start of PES body
char
*
base
=
&
packet
[
4
];
int
len
=
p
-
base
;
p
=
(
char
*
)
memmove
(
base
+
stuff_size
,
base
,
len
)
+
len
;
// adaption_field_length; //8bits
packet
[
4
]
=
(
stuff_size
-
1
);
if
(
stuff_size
>=
2
)
{
// adaption field flags.
packet
[
5
]
=
0
;
// adaption data.
if
(
stuff_size
>
2
)
{
memset
(
&
packet
[
6
],
0xff
,
stuff_size
-
2
);
}
}
return
p
;
}
static
char
*
write_pcr
(
char
*
p
,
int64_t
pcr
)
{
*
p
++
=
(
char
)
(
pcr
>>
25
);
*
p
++
=
(
char
)
(
pcr
>>
17
);
*
p
++
=
(
char
)
(
pcr
>>
9
);
*
p
++
=
(
char
)
(
pcr
>>
1
);
*
p
++
=
(
char
)
(
pcr
<<
7
|
0x7e
);
*
p
++
=
0
;
return
p
;
}
static
char
*
write_pts
(
char
*
p
,
u_int8_t
fb
,
int64_t
pts
)
{
int32_t
val
;
val
=
fb
<<
4
|
(((
pts
>>
30
)
&
0x07
)
<<
1
)
|
1
;
*
p
++
=
val
;
val
=
(((
pts
>>
15
)
&
0x7fff
)
<<
1
)
|
1
;
*
p
++
=
(
val
>>
8
);
*
p
++
=
val
;
val
=
(((
pts
)
&
0x7fff
)
<<
1
)
|
1
;
*
p
++
=
(
val
>>
8
);
*
p
++
=
val
;
return
p
;
}
};
// the mpegts header specifed the video/audio pid.
#define TS_VIDEO_PID 256
#define TS_AUDIO_PID 257
// ts aac stream id.
#define TS_AUDIO_AAC 0xc0
// ts avc stream id.
#define TS_VIDEO_AVC 0xe0
SrsTSMuxer
::
SrsTSMuxer
()
{
fd
=
-
1
;
audio_buffer
=
new
SrsCodecBuffer
();
video_buffer
=
new
SrsCodecBuffer
();
}
SrsTSMuxer
::~
SrsTSMuxer
()
{
close
();
audio_buffer
->
free
();
video_buffer
->
free
();
srs_freep
(
audio_buffer
);
srs_freep
(
video_buffer
);
}
int
SrsTSMuxer
::
open
(
std
::
string
_path
)
...
...
@@ -306,9 +539,7 @@ int SrsTSMuxer::open(std::string _path)
}
// write mpegts header
if
(
::
write
(
fd
,
mpegts_header
,
sizeof
(
mpegts_header
))
!=
sizeof
(
mpegts_header
))
{
ret
=
ERROR_HLS_WRITE_FAILED
;
srs_error
(
"write ts file header %s failed. ret=%d"
,
path
.
c_str
(),
ret
);
if
((
ret
=
SrsMpegtsWriter
::
write_header
(
fd
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
...
...
@@ -319,7 +550,64 @@ int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam
{
int
ret
=
ERROR_SUCCESS
;
static
u_int8_t
packet
[
188
];
for
(
int
i
=
0
;
i
<
sample
->
nb_buffers
;
i
++
)
{
SrsCodecBuffer
*
buf
=
&
sample
->
buffers
[
i
];
int32_t
size
=
buf
->
size
;
if
(
!
buf
->
bytes
||
size
<=
0
||
size
>
0x1fff
)
{
ret
=
ERROR_HLS_AAC_FRAME_LENGTH
;
srs_error
(
"invalid aac frame length=%d, ret=%d"
,
size
,
ret
);
return
ret
;
}
// AAC-ADTS
// 6.2 Audio Data Transport Stream, ADTS
// in aac-iso-13818-7.pdf, page 26.
// fixed 7bytes header
static
u_int8_t
adts_header
[
7
]
=
{
0xff
,
0xf1
,
0x00
,
0x00
,
0x00
,
0x0f
,
0xfc
};
/*
// adts_fixed_header
// 2B, 16bits
int16_t syncword; //12bits, '1111 1111 1111'
int8_t ID; //1bit, '0'
int8_t layer; //2bits, '00'
int8_t protection_absent; //1bit, can be '1'
// 12bits
int8_t profile; //2bit, 7.1 Profiles, page 40
TSAacSampleFrequency sampling_frequency_index; //4bits, Table 35, page 46
int8_t private_bit; //1bit, can be '0'
int8_t channel_configuration; //3bits, Table 8
int8_t original_or_copy; //1bit, can be '0'
int8_t home; //1bit, can be '0'
// adts_variable_header
// 28bits
int8_t copyright_identification_bit; //1bit, can be '0'
int8_t copyright_identification_start; //1bit, can be '0'
int16_t frame_length; //13bits
int16_t adts_buffer_fullness; //11bits, 7FF signals that the bitstream is a variable rate bitstream.
int8_t number_of_raw_data_blocks_in_frame; //2bits, 0 indicating 1 raw_data_block()
*/
// profile, 2bits
adts_header
[
2
]
=
(
codec
->
aac_profile
<<
6
)
&
0xc0
;
// sampling_frequency_index 4bits
adts_header
[
2
]
|=
(
codec
->
aac_sample_rate
<<
2
)
&
0x3c
;
// channel_configuration 3bits
adts_header
[
2
]
|=
(
codec
->
aac_channels
>>
1
)
&
0x01
;
adts_header
[
3
]
=
(
codec
->
aac_channels
<<
5
)
&
0xc0
;
// frame_length 13bits
adts_header
[
3
]
|=
(
size
>>
11
)
&
0x03
;
adts_header
[
4
]
=
(
size
>>
3
)
&
0xff
;
adts_header
[
5
]
=
(
size
<<
5
)
&
0xcf
;
// copy to audio buffer
audio_buffer
->
append
(
adts_header
,
sizeof
(
adts_header
));
audio_buffer
->
append
(
buf
->
bytes
,
buf
->
size
);
}
audio_frame
.
dts
=
audio_frame
.
pts
=
time
*
90
;
audio_frame
.
pid
=
TS_AUDIO_PID
;
audio_frame
.
sid
=
TS_AUDIO_AAC
;
return
ret
;
}
...
...
@@ -328,7 +616,45 @@ int SrsTSMuxer::write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam
{
int
ret
=
ERROR_SUCCESS
;
static
u_int8_t
packet
[
188
];
static
u_int8_t
aud_nal
[]
=
{
0x00
,
0x00
,
0x00
,
0x01
,
0x09
,
0xf0
};
video_buffer
->
append
(
aud_nal
,
sizeof
(
aud_nal
));
for
(
int
i
=
0
;
i
<
sample
->
nb_buffers
;
i
++
)
{
SrsCodecBuffer
*
buf
=
&
sample
->
buffers
[
i
];
int32_t
size
=
buf
->
size
;
if
(
!
buf
->
bytes
||
size
<=
0
)
{
ret
=
ERROR_HLS_AVC_SAMPLE_SIZE
;
srs_error
(
"invalid avc sample length=%d, ret=%d"
,
size
,
ret
);
return
ret
;
}
// sample start prefix, '00 00 00 01' or '00 00 01'
u_int8_t
*
p
=
aud_nal
+
1
;
u_int8_t
*
end
=
p
+
3
;
// first AnnexB prefix is long (4 bytes)
if
(
i
==
0
)
{
p
=
aud_nal
;
}
video_buffer
->
append
(
p
,
end
-
p
);
// sample data
video_buffer
->
append
(
buf
->
bytes
,
buf
->
size
);
}
video_frame
.
dts
=
time
*
90
;
video_frame
.
pts
=
video_frame
.
dts
+
sample
->
cts
*
90
;
video_frame
.
pid
=
TS_VIDEO_PID
;
video_frame
.
sid
=
TS_VIDEO_AVC
;
video_frame
.
key
=
sample
->
frame_type
==
SrsCodecVideoAVCFrameKeyFrame
;
if
((
ret
=
SrsMpegtsWriter
::
write_frame
(
fd
,
&
video_frame
,
video_buffer
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
((
ret
=
SrsMpegtsWriter
::
write_frame
(
fd
,
&
audio_frame
,
audio_buffer
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
...
...
trunk/src/core/srs_core_hls.hpp
查看文件 @
4fca914
...
...
@@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
class
SrsOnMetaDataPacket
;
class
SrsCommonMessage
;
class
SrsCodecSample
;
class
SrsCodecBuffer
;
class
SrsTSMuxer
;
class
SrsCodec
;
...
...
@@ -56,11 +57,34 @@ public:
virtual
int
on_video
(
SrsCommonMessage
*
video
);
};
// @see: ngx_rtmp_mpegts_frame_t
struct
mpegts_frame
{
int64_t
pts
;
int64_t
dts
;
int
pid
;
int
sid
;
int
cc
;
bool
key
;
mpegts_frame
()
{
pts
=
dts
=
0
;
pid
=
sid
=
cc
=
0
;
key
=
false
;
}
};
class
SrsTSMuxer
{
private
:
int
fd
;
std
::
string
path
;
private
:
mpegts_frame
audio_frame
;
SrsCodecBuffer
*
audio_buffer
;
mpegts_frame
video_frame
;
SrsCodecBuffer
*
video_buffer
;
public
:
SrsTSMuxer
();
virtual
~
SrsTSMuxer
();
...
...
请
注册
或
登录
后发表评论