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-22 18:32:10 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
2a05783d5cb854f690fa09eb9b84f6c5fff23fd6
2a05783d
1 parent
dfe385d0
for #293, support http ts stream. 2.0.101
隐藏空白字符变更
内嵌
并排对比
正在显示
7 个修改的文件
包含
419 行增加
和
375 行删除
trunk/src/app/srs_app_hls.cpp
trunk/src/app/srs_app_hls.hpp
trunk/src/core/srs_core.hpp
trunk/src/kernel/srs_kernel_avc.cpp
trunk/src/kernel/srs_kernel_avc.hpp
trunk/src/kernel/srs_kernel_ts.cpp
trunk/src/kernel/srs_kernel_ts.hpp
trunk/src/app/srs_app_hls.cpp
查看文件 @
2a05783
...
...
@@ -51,369 +51,23 @@ using namespace std;
#include <srs_kernel_file.hpp>
#include <srs_protocol_buffer.hpp>
// max PES packets size to flush the video.
#define SRS_AUTO_HLS_AUDIO_CACHE_SIZE 1024 * 1024
// drop the segment when duration of ts too small.
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
// @see: NGX_RTMP_HLS_DELAY,
// 63000: 700ms, ts_tbn=90000
#define SRS_AUTO_HLS_DELAY 63000
// @see: ngx_rtmp_mpegts_header
u_int8_t
mpegts_header
[]
=
{
/* TS */
0x47
,
0x40
,
0x00
,
0x10
,
0x00
,
/* PSI */
0x00
,
0xb0
,
0x0d
,
0x00
,
0x01
,
0xc1
,
0x00
,
0x00
,
/* PAT */
0x00
,
0x01
,
0xf0
,
0x01
,
/* CRC */
0x2e
,
0x70
,
0x19
,
0x05
,
/* stuffing 167 bytes */
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
/* TS */
0x47
,
0x50
,
0x01
,
0x10
,
0x00
,
/* PSI */
0x02
,
0xb0
,
0x17
,
0x00
,
0x01
,
0xc1
,
0x00
,
0x00
,
/* PMT */
0xe1
,
0x00
,
0xf0
,
0x00
,
// must generate header with/without video, @see:
// https://github.com/winlinvip/simple-rtmp-server/issues/40
0x1b
,
0xe1
,
0x00
,
0xf0
,
0x00
,
/* h264, pid=0x100=256 */
0x0f
,
0xe1
,
0x01
,
0xf0
,
0x00
,
/* aac, pid=0x101=257 */
/*0x03, 0xe1, 0x01, 0xf0, 0x00,*/
/* mp3 */
/* CRC */
0x2f
,
0x44
,
0xb9
,
0x9b
,
/* crc for aac */
/*0x4e, 0x59, 0x3d, 0x1e,*/
/* crc for mp3 */
/* stuffing 157 bytes */
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
// @see: ngx_rtmp_mpegts.c
// TODO: support full mpegts feature in future.
class
SrsMpegtsWriter
{
public
:
static
int
write_header
(
SrsFileWriter
*
writer
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
writer
->
write
(
mpegts_header
,
sizeof
(
mpegts_header
),
NULL
))
!=
ERROR_SUCCESS
)
{
ret
=
ERROR_HLS_WRITE_FAILED
;
srs_error
(
"write ts file header failed. ret=%d"
,
ret
);
return
ret
;
}
return
ret
;
}
static
int
write_frame
(
SrsFileWriter
*
writer
,
SrsMpegtsFrame
*
frame
,
SrsSimpleBuffer
*
buffer
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
!
buffer
->
bytes
()
||
buffer
->
length
()
<=
0
)
{
return
ret
;
}
char
*
last
=
buffer
->
bytes
()
+
buffer
->
length
();
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_AUTO_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_AUTO_HLS_DELAY
);
// dts; // 33bits
if
(
frame
->
dts
!=
frame
->
pts
)
{
p
=
write_pts
(
p
,
1
,
frame
->
dts
+
SRS_AUTO_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
((
ret
=
writer
->
write
(
packet
,
sizeof
(
packet
),
NULL
))
!=
ERROR_SUCCESS
)
{
ret
=
ERROR_HLS_WRITE_FAILED
;
srs_error
(
"write ts file failed. ret=%d"
,
ret
);
return
ret
;
}
}
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
)
{
// the pcr=dts-delay
// and the pcr maybe negative
// @see https://github.com/winlinvip/simple-rtmp-server/issues/268
int64_t
v
=
srs_max
(
0
,
pcr
);
*
p
++
=
(
char
)
(
v
>>
25
);
*
p
++
=
(
char
)
(
v
>>
17
);
*
p
++
=
(
char
)
(
v
>>
9
);
*
p
++
=
(
char
)
(
v
>>
1
);
*
p
++
=
(
char
)
(
v
<<
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
;
}
};
SrsTSMuxer
::
SrsTSMuxer
()
{
writer
=
new
SrsFileWriter
();
}
SrsTSMuxer
::~
SrsTSMuxer
()
{
close
();
srs_freep
(
writer
);
}
int
SrsTSMuxer
::
open
(
string
_path
)
{
int
ret
=
ERROR_SUCCESS
;
path
=
_path
;
close
();
if
((
ret
=
writer
->
open
(
path
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// write mpegts header
if
((
ret
=
SrsMpegtsWriter
::
write_header
(
writer
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
int
SrsTSMuxer
::
write_audio
(
SrsMpegtsFrame
*
af
,
SrsSimpleBuffer
*
ab
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
SrsMpegtsWriter
::
write_frame
(
writer
,
af
,
ab
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
int
SrsTSMuxer
::
write_video
(
SrsMpegtsFrame
*
vf
,
SrsSimpleBuffer
*
vb
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
SrsMpegtsWriter
::
write_frame
(
writer
,
vf
,
vb
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
void
SrsTSMuxer
::
close
()
{
writer
->
close
();
}
SrsHlsSegment
::
SrsHlsSegment
()
{
duration
=
0
;
sequence_no
=
0
;
muxer
=
new
SrsTSMuxer
();
segment_start_dts
=
0
;
is_sequence_header
=
false
;
writer
=
new
SrsFileWriter
();
muxer
=
new
SrsTSMuxer
(
writer
);
}
SrsHlsSegment
::~
SrsHlsSegment
()
{
srs_freep
(
muxer
);
srs_freep
(
writer
);
}
void
SrsHlsSegment
::
update_duration
(
int64_t
current_frame_dts
)
...
...
@@ -926,6 +580,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
return
ret
;
}
}
// TODO: config it.
// in ms, audio delay to flush the audios.
int64_t
audio_delay
=
SRS_CONF_DEFAULT_AAC_DELAY
;
...
...
trunk/src/app/srs_app_hls.hpp
查看文件 @
2a05783
...
...
@@ -53,25 +53,6 @@ class SrsTsAacJitter;
class
SrsTsCache
;
/**
* write data from frame(header info) and buffer(data) to ts file.
* it's a simple object wrapper for utility from nginx-rtmp: SrsMpegtsWriter
*/
class
SrsTSMuxer
{
private
:
SrsFileWriter
*
writer
;
std
::
string
path
;
public
:
SrsTSMuxer
();
virtual
~
SrsTSMuxer
();
public
:
virtual
int
open
(
std
::
string
_path
);
virtual
int
write_audio
(
SrsMpegtsFrame
*
af
,
SrsSimpleBuffer
*
ab
);
virtual
int
write_video
(
SrsMpegtsFrame
*
vf
,
SrsSimpleBuffer
*
vb
);
virtual
void
close
();
};
/**
* the wrapper of m3u8 segment from specification:
*
* 3.3.2. EXTINF
...
...
@@ -89,6 +70,7 @@ public:
// ts full file to write.
std
::
string
full_path
;
// the muxer to write ts.
SrsFileWriter
*
writer
;
SrsTSMuxer
*
muxer
;
// current segment start dts for m3u8
int64_t
segment_start_dts
;
...
...
trunk/src/core/srs_core.hpp
查看文件 @
2a05783
...
...
@@ -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 10
1
#define VERSION_REVISION 10
2
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
...
...
trunk/src/kernel/srs_kernel_avc.cpp
查看文件 @
2a05783
...
...
@@ -28,6 +28,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_kernel_stream.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_file.hpp>
using
namespace
std
;
// in ms, for HLS aac sync time.
#define SRS_CONF_DEFAULT_AAC_SYNC 100
...
...
@@ -65,6 +68,294 @@ int aac_sample_rates[] =
7350
,
0
,
0
,
0
};
// @see: NGX_RTMP_HLS_DELAY,
// 63000: 700ms, ts_tbn=90000
#define SRS_AUTO_HLS_DELAY 63000
// @see: ngx_rtmp_mpegts_header
u_int8_t
mpegts_header
[]
=
{
/* TS */
0x47
,
0x40
,
0x00
,
0x10
,
0x00
,
/* PSI */
0x00
,
0xb0
,
0x0d
,
0x00
,
0x01
,
0xc1
,
0x00
,
0x00
,
/* PAT */
0x00
,
0x01
,
0xf0
,
0x01
,
/* CRC */
0x2e
,
0x70
,
0x19
,
0x05
,
/* stuffing 167 bytes */
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
/* TS */
0x47
,
0x50
,
0x01
,
0x10
,
0x00
,
/* PSI */
0x02
,
0xb0
,
0x17
,
0x00
,
0x01
,
0xc1
,
0x00
,
0x00
,
/* PMT */
0xe1
,
0x00
,
0xf0
,
0x00
,
// must generate header with/without video, @see:
// https://github.com/winlinvip/simple-rtmp-server/issues/40
0x1b
,
0xe1
,
0x00
,
0xf0
,
0x00
,
/* h264, pid=0x100=256 */
0x0f
,
0xe1
,
0x01
,
0xf0
,
0x00
,
/* aac, pid=0x101=257 */
/*0x03, 0xe1, 0x01, 0xf0, 0x00,*/
/* mp3 */
/* CRC */
0x2f
,
0x44
,
0xb9
,
0x9b
,
/* crc for aac */
/*0x4e, 0x59, 0x3d, 0x1e,*/
/* crc for mp3 */
/* stuffing 157 bytes */
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
// @see: ngx_rtmp_mpegts.c
// TODO: support full mpegts feature in future.
class
SrsMpegtsWriter
{
public
:
static
int
write_header
(
SrsFileWriter
*
writer
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
writer
->
write
(
mpegts_header
,
sizeof
(
mpegts_header
),
NULL
))
!=
ERROR_SUCCESS
)
{
ret
=
ERROR_HLS_WRITE_FAILED
;
srs_error
(
"write ts file header failed. ret=%d"
,
ret
);
return
ret
;
}
return
ret
;
}
static
int
write_frame
(
SrsFileWriter
*
writer
,
SrsMpegtsFrame
*
frame
,
SrsSimpleBuffer
*
buffer
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
!
buffer
->
bytes
()
||
buffer
->
length
()
<=
0
)
{
return
ret
;
}
char
*
last
=
buffer
->
bytes
()
+
buffer
->
length
();
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_AUTO_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_AUTO_HLS_DELAY
);
// dts; // 33bits
if
(
frame
->
dts
!=
frame
->
pts
)
{
p
=
write_pts
(
p
,
1
,
frame
->
dts
+
SRS_AUTO_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
((
ret
=
writer
->
write
(
packet
,
sizeof
(
packet
),
NULL
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"write ts file failed. ret=%d"
,
ret
);
}
return
ret
;
}
}
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
)
{
// the pcr=dts-delay
// and the pcr maybe negative
// @see https://github.com/winlinvip/simple-rtmp-server/issues/268
int64_t
v
=
srs_max
(
0
,
pcr
);
*
p
++
=
(
char
)
(
v
>>
25
);
*
p
++
=
(
char
)
(
v
>>
17
);
*
p
++
=
(
char
)
(
v
>>
9
);
*
p
++
=
(
char
)
(
v
>>
1
);
*
p
++
=
(
char
)
(
v
<<
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
;
}
};
SrsMpegtsFrame
::
SrsMpegtsFrame
()
{
pts
=
dts
=
0
;
...
...
@@ -72,6 +363,63 @@ SrsMpegtsFrame::SrsMpegtsFrame()
key
=
false
;
}
SrsTSMuxer
::
SrsTSMuxer
(
SrsFileWriter
*
w
)
{
writer
=
w
;
}
SrsTSMuxer
::~
SrsTSMuxer
()
{
close
();
}
int
SrsTSMuxer
::
open
(
string
_path
)
{
int
ret
=
ERROR_SUCCESS
;
path
=
_path
;
close
();
if
((
ret
=
writer
->
open
(
path
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// write mpegts header
if
((
ret
=
SrsMpegtsWriter
::
write_header
(
writer
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
int
SrsTSMuxer
::
write_audio
(
SrsMpegtsFrame
*
af
,
SrsSimpleBuffer
*
ab
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
SrsMpegtsWriter
::
write_frame
(
writer
,
af
,
ab
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
int
SrsTSMuxer
::
write_video
(
SrsMpegtsFrame
*
vf
,
SrsSimpleBuffer
*
vb
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
SrsMpegtsWriter
::
write_frame
(
writer
,
vf
,
vb
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
void
SrsTSMuxer
::
close
()
{
writer
->
close
();
}
SrsTsAacJitter
::
SrsTsAacJitter
()
{
base_pts
=
0
;
...
...
trunk/src/kernel/srs_kernel_avc.hpp
查看文件 @
2a05783
...
...
@@ -30,6 +30,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_core.hpp>
#include <string>
#include <srs_kernel_codec.hpp>
class
SrsStream
;
...
...
@@ -37,6 +39,7 @@ class SrsMpegtsFrame;
class
SrsSimpleBuffer
;
class
SrsAvcAacCodec
;
class
SrsCodecSample
;
class
SrsFileWriter
;
/**
* the public data, event HLS disable, others can use it.
...
...
@@ -57,6 +60,9 @@ extern int aac_sample_rates[];
// in ms, for HLS aac flush the audio
#define SRS_CONF_DEFAULT_AAC_DELAY 100
// max PES packets size to flush the video.
#define SRS_AUTO_HLS_AUDIO_CACHE_SIZE 1024 * 1024
/**
* the FLV/RTMP supported audio sample size.
* Size of each audio sample. This parameter only pertains to
...
...
@@ -104,6 +110,25 @@ public:
};
/**
* write data from frame(header info) and buffer(data) to ts file.
* it's a simple object wrapper for utility from nginx-rtmp: SrsMpegtsWriter
*/
class
SrsTSMuxer
{
private
:
SrsFileWriter
*
writer
;
std
::
string
path
;
public
:
SrsTSMuxer
(
SrsFileWriter
*
w
);
virtual
~
SrsTSMuxer
();
public
:
virtual
int
open
(
std
::
string
_path
);
virtual
int
write_audio
(
SrsMpegtsFrame
*
af
,
SrsSimpleBuffer
*
ab
);
virtual
int
write_video
(
SrsMpegtsFrame
*
vf
,
SrsSimpleBuffer
*
vb
);
virtual
void
close
();
};
/**
* jitter correct for audio,
* the sample rate 44100/32000 will lost precise,
* when mp4/ts(tbn=90000) covert to flv/rtmp(1000),
...
...
trunk/src/kernel/srs_kernel_ts.cpp
查看文件 @
2a05783
...
...
@@ -36,18 +36,23 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_kernel_file.hpp>
#include <srs_kernel_avc.hpp>
#include <srs_kernel_buffer.hpp>
SrsTsEncoder
::
SrsTsEncoder
()
{
_fs
=
NULL
;
codec
=
new
SrsAvcAacCodec
();
sample
=
new
SrsCodecSample
();
cache
=
new
SrsTsCache
();
muxer
=
NULL
;
}
SrsTsEncoder
::~
SrsTsEncoder
()
{
srs_freep
(
codec
);
srs_freep
(
sample
);
srs_freep
(
cache
);
srs_freep
(
muxer
);
}
int
SrsTsEncoder
::
initialize
(
SrsFileWriter
*
fs
)
...
...
@@ -63,6 +68,13 @@ int SrsTsEncoder::initialize(SrsFileWriter* fs)
}
_fs
=
fs
;
srs_freep
(
muxer
);
muxer
=
new
SrsTSMuxer
(
fs
);
if
((
ret
=
muxer
->
open
(
""
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
ret
;
}
...
...
@@ -91,10 +103,20 @@ int SrsTsEncoder::write_audio(int64_t timestamp, char* data, int size)
// for the packet is filtered by consumer.
int64_t
dts
=
timestamp
*
90
;
/*if ((ret = hls_cache->write_audio(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
srs_error("http: ts cache write audio failed. ret=%d", ret);
// write audio to cache.
if
((
ret
=
cache
->
cache_audio
(
codec
,
dts
,
sample
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}*/
}
// flush if buffer exceed max size.
if
(
cache
->
ab
->
length
()
>
SRS_AUTO_HLS_AUDIO_CACHE_SIZE
)
{
if
((
ret
=
muxer
->
write_audio
(
cache
->
af
,
cache
->
ab
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// write success, clear and free the buffer
cache
->
ab
->
erase
(
cache
->
ab
->
length
());
}
return
ret
;
}
...
...
@@ -126,10 +148,18 @@ int SrsTsEncoder::write_video(int64_t timestamp, char* data, int size)
}
int64_t
dts
=
timestamp
*
90
;
/*if ((ret = hls_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
srs_error("http: ts cache write video failed. ret=%d", ret);
// write video to cache.
if
((
ret
=
cache
->
cache_video
(
codec
,
dts
,
sample
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}*/
}
if
((
ret
=
muxer
->
write_video
(
cache
->
vf
,
cache
->
vb
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// write success, clear and free the buffer
cache
->
vb
->
erase
(
cache
->
vb
->
length
());
return
ret
;
}
...
...
trunk/src/kernel/srs_kernel_ts.hpp
查看文件 @
2a05783
...
...
@@ -31,6 +31,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <string>
class
SrsTsCache
;
class
SrsTSMuxer
;
class
SrsFileWriter
;
class
SrsFileReader
;
class
SrsAvcAacCodec
;
...
...
@@ -46,6 +48,8 @@ private:
private
:
SrsAvcAacCodec
*
codec
;
SrsCodecSample
*
sample
;
SrsTsCache
*
cache
;
SrsTSMuxer
*
muxer
;
public
:
SrsTsEncoder
();
virtual
~
SrsTsEncoder
();
...
...
请
注册
或
登录
后发表评论