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-04-04 13:31:02 +0800
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
4f9df4f1a0c36ffc46dddec8ab59b20e2f463c19
4f9df4f1
2 parents
90cd16aa
77c29da2
merge from 2.0.157, reap ts on the IDR.
隐藏空白字符变更
内嵌
并排对比
正在显示
15 个修改的文件
包含
634 行增加
和
119 行删除
README.md
trunk/conf/full.conf
trunk/src/app/srs_app_config.cpp
trunk/src/app/srs_app_config.hpp
trunk/src/app/srs_app_hls.cpp
trunk/src/app/srs_app_log.cpp
trunk/src/app/srs_app_utility.cpp
trunk/src/kernel/srs_kernel_codec.cpp
trunk/src/kernel/srs_kernel_codec.hpp
trunk/src/kernel/srs_kernel_error.hpp
trunk/src/kernel/srs_kernel_stream.cpp
trunk/src/kernel/srs_kernel_stream.hpp
trunk/src/kernel/srs_kernel_ts.cpp
trunk/src/kernel/srs_kernel_utility.cpp
trunk/src/kernel/srs_kernel_utility.hpp
README.md
查看文件 @
4f9df4f
...
...
@@ -566,7 +566,9 @@ Supported operating systems and hardware:
### SRS 2.0 history
*
v2.0, 2015-03-30, for
[
#372
](
https://github.com/winlinvip/simple-rtmp-server/issues/372
)
, support transform vhost of edge 2.0.155.
*
v2.0, 2015-04-04, for
[
#304
](
https://github.com/winlinvip/simple-rtmp-server/issues/304
)
, rewrite annexb mux for ts, refer to apple sample. 2.0.157.
*
v2.0, 2015-04-03, enhanced avc decode, parse the sps get width+height. 2.0.156.
*
v2.0, 2015-04-03, for
[
#372
](
https://github.com/winlinvip/simple-rtmp-server/issues/372
)
, support transform vhost of edge 2.0.155.
*
v2.0, 2015-03-30, for
[
#366
](
https://github.com/winlinvip/simple-rtmp-server/issues/366
)
, config hls to disable cleanup of ts. 2.0.154.
*
v2.0, 2015-03-31, support server cycle handler. 2.0.153.
*
v2.0, 2015-03-31, support on_hls for http hooks. 2.0.152.
...
...
trunk/conf/full.conf
查看文件 @
4f9df4f
...
...
@@ -44,6 +44,11 @@ max_connections 1000;
# @remark: donot support reload.
# default: on
daemon
on
;
# whether use utc_time to generate the time struct,
# if off, use localtime() to generate it,
# if on, use gmtime() instead, which use UTC time.
# default: off
utc_time
off
;
#############################################################################################
# heartbeat/stats sections
...
...
trunk/src/app/srs_app_config.cpp
查看文件 @
4f9df4f
...
...
@@ -1336,7 +1336,8 @@ int SrsConfig::check_config()
&&
n
!=
"srs_log_tank"
&&
n
!=
"srs_log_level"
&&
n
!=
"srs_log_file"
&&
n
!=
"max_connections"
&&
n
!=
"daemon"
&&
n
!=
"heartbeat"
&&
n
!=
"http_api"
&&
n
!=
"stats"
&&
n
!=
"vhost"
&&
n
!=
"pithy_print_ms"
&&
n
!=
"http_stream"
&&
n
!=
"http_server"
&&
n
!=
"stream_caster"
)
&&
n
!=
"http_stream"
&&
n
!=
"http_server"
&&
n
!=
"stream_caster"
&&
n
!=
"utc_time"
)
{
ret
=
ERROR_SYSTEM_CONFIG_INVALID
;
srs_error
(
"unsupported directive %s, ret=%d"
,
n
.
c_str
(),
ret
);
...
...
@@ -1896,6 +1897,16 @@ int SrsConfig::get_pithy_print_ms()
return
::
atoi
(
pithy
->
arg0
().
c_str
());
}
bool
SrsConfig
::
get_utc_time
()
{
SrsConfDirective
*
utc
=
root
->
get
(
"utc_time"
);
if
(
!
utc
||
utc
->
arg0
().
empty
())
{
return
SRS_CONF_DEFAULT_UTC_TIME
;
}
return
utc
->
arg0
()
==
"on"
;
}
vector
<
SrsConfDirective
*>
SrsConfig
::
get_stream_casters
()
{
srs_assert
(
root
);
...
...
trunk/src/app/srs_app_config.hpp
查看文件 @
4f9df4f
...
...
@@ -43,6 +43,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRS_CONF_DEFAULT_LOG_TANK_CONSOLE "console"
#define SRS_CONF_DEFAULT_COFNIG_FILE "conf/srs.conf"
#define SRS_CONF_DEFAULT_FF_LOG_DIR "./objs"
#define SRS_CONF_DEFAULT_UTC_TIME false
#define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000
#define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
...
...
@@ -435,6 +436,10 @@ public:
* every this interval in ms.
*/
virtual
int
get_pithy_print_ms
();
/**
* whether use utc-time to format the time.
*/
virtual
bool
get_utc_time
();
// stream_caster section
public:
/**
...
...
trunk/src/app/srs_app_hls.cpp
查看文件 @
4f9df4f
...
...
@@ -311,12 +311,6 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
// generate the m3u8 dir and path.
m3u8
=
path
+
"/"
+
m3u8_file
;
m3u8
=
srs_path_build_stream
(
m3u8
,
req
->
vhost
,
req
->
app
,
req
->
stream
);
m3u8_dir
=
m3u8
;
size_t
pos
=
string
::
npos
;
if
((
pos
=
m3u8_dir
.
rfind
(
"/"
))
!=
string
::
npos
)
{
m3u8_dir
=
m3u8_dir
.
substr
(
0
,
pos
);
}
// we always keep the target duration increasing.
int
max_td
=
srs_max
(
target_duration
,
(
int
)(
fragment
*
_srs_config
->
get_hls_td_ratio
(
r
->
vhost
)));
...
...
@@ -336,6 +330,14 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
should_write_file
=
true
;
}
// create m3u8 dir once.
m3u8_dir
=
srs_path_dirname
(
m3u8
);
if
(
should_write_file
&&
(
ret
=
srs_create_dir_recursively
(
m3u8_dir
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"create app dir %s failed. ret=%d"
,
m3u8_dir
.
c_str
(),
ret
);
return
ret
;
}
srs_info
(
"create m3u8 dir %s ok"
,
m3u8_dir
.
c_str
());
return
ret
;
}
...
...
@@ -434,11 +436,12 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
current
->
uri
+=
ts_url
;
// create dir recursively for hls.
if
(
should_write_file
&&
(
ret
=
srs_create_dir_recursively
(
m3u8_dir
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"create app dir %s failed. ret=%d"
,
m3u8_dir
.
c_str
(),
ret
);
std
::
string
ts_dir
=
srs_path_dirname
(
current
->
full_path
);
if
(
should_write_file
&&
(
ret
=
srs_create_dir_recursively
(
ts_dir
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"create app dir %s failed. ret=%d"
,
ts_dir
.
c_str
(),
ret
);
return
ret
;
}
srs_info
(
"create
app dir %s ok"
,
m3u8
_dir
.
c_str
());
srs_info
(
"create
ts dir %s ok"
,
ts
_dir
.
c_str
());
// open temp ts file.
std
::
string
tmp_file
=
current
->
full_path
+
".tmp"
;
...
...
@@ -751,7 +754,7 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
// "#EXTINF:4294967295.208,\n"
ss
.
precision
(
3
);
ss
.
setf
(
std
::
ios
::
fixed
,
std
::
ios
::
floatfield
);
ss
<<
"#EXTINF:"
<<
segment
->
duration
<<
","
<<
SRS_CONSTS_LF
;
ss
<<
"#EXTINF:"
<<
segment
->
duration
<<
",
no desc
"
<<
SRS_CONSTS_LF
;
srs_verbose
(
"write m3u8 segment info success."
);
// {file name}\n
...
...
@@ -896,6 +899,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
// we use absolutely overflow of segment to make jwplayer/ffplay happy
// @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-71155184
if
(
cache
->
audio
&&
muxer
->
is_segment_absolutely_overflow
())
{
srs_warn
(
"hls: absolute audio reap segment."
);
if
((
ret
=
reap_segment
(
"audio"
,
muxer
,
cache
->
audio
->
pts
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
...
...
@@ -914,9 +918,12 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
}
// new segment when:
// 1. base on gop.
// 1. base on gop
(IDR)
.
// 2. some gops duration overflow.
if
(
sample
->
frame_type
==
SrsCodecVideoAVCFrameKeyFrame
&&
muxer
->
is_segment_overflow
())
{
if
(
!
sample
->
has_idr
)
{
srs_warn
(
"hls: ts starts without IDR, first nalu=%d"
,
sample
->
first_nalu_type
);
}
if
((
ret
=
reap_segment
(
"video"
,
muxer
,
cache
->
video
->
dts
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
...
...
@@ -935,26 +942,28 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
int
SrsHlsCache
::
reap_segment
(
string
log_desc
,
SrsHlsMuxer
*
muxer
,
int64_t
segment_start_dts
)
{
int
ret
=
ERROR_SUCCESS
;
// TODO: flush audio before or after segment?
// TODO: fresh segment begin with audio or video?
// close current ts.
if
((
ret
=
muxer
->
segment_close
(
log_desc
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"m3u8 muxer close segment failed. ret=%d"
,
ret
);
return
ret
;
}
// open new ts.
if
((
ret
=
muxer
->
segment_open
(
segment_start_dts
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"m3u8 muxer open segment failed. ret=%d"
,
ret
);
return
ret
;
}
// TODO: flush audio before or after segment?
// TODO: fresh segment begin with audio or video?
// segment open, flush video first.
if
((
ret
=
muxer
->
flush_video
(
cache
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"m3u8 muxer flush video failed. ret=%d"
,
ret
);
return
ret
;
}
// segment open, flush the audio.
// @see: ngx_rtmp_hls_open_fragment
/* start fragment with audio to make iPhone happy */
...
...
trunk/src/app/srs_app_log.cpp
查看文件 @
4f9df4f
...
...
@@ -274,8 +274,14 @@ bool SrsFastLog::generate_header(bool error, const char* tag, int context_id, co
// to calendar time
struct
tm
*
tm
;
if
((
tm
=
localtime
(
&
tv
.
tv_sec
))
==
NULL
)
{
return
false
;
if
(
_srs_config
->
get_utc_time
())
{
if
((
tm
=
gmtime
(
&
tv
.
tv_sec
))
==
NULL
)
{
return
false
;
}
}
else
{
if
((
tm
=
localtime
(
&
tv
.
tv_sec
))
==
NULL
)
{
return
false
;
}
}
// write log header
...
...
trunk/src/app/srs_app_utility.cpp
查看文件 @
4f9df4f
...
...
@@ -140,8 +140,14 @@ string srs_path_build_timestamp(string template_path)
// to calendar time
struct
tm
*
tm
;
if
((
tm
=
localtime
(
&
tv
.
tv_sec
))
==
NULL
)
{
return
path
;
if
(
_srs_config
->
get_utc_time
())
{
if
((
tm
=
gmtime
(
&
tv
.
tv_sec
))
==
NULL
)
{
return
path
;
}
}
else
{
if
((
tm
=
localtime
(
&
tv
.
tv_sec
))
==
NULL
)
{
return
path
;
}
}
// the buffer to format the date and time.
...
...
@@ -154,32 +160,32 @@ string srs_path_build_timestamp(string template_path)
}
// [2006], replace with current year.
if
(
true
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
1900
+
tm
->
tm_year
);
snprintf
(
buf
,
sizeof
(
buf
),
"%
04
d"
,
1900
+
tm
->
tm_year
);
path
=
srs_string_replace
(
path
,
"[2006]"
,
buf
);
}
// [01], replace this const to current month.
if
(
true
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
1
+
tm
->
tm_mon
);
snprintf
(
buf
,
sizeof
(
buf
),
"%
02
d"
,
1
+
tm
->
tm_mon
);
path
=
srs_string_replace
(
path
,
"[01]"
,
buf
);
}
// [02], replace this const to current date.
if
(
true
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
tm
->
tm_mday
);
snprintf
(
buf
,
sizeof
(
buf
),
"%
02
d"
,
tm
->
tm_mday
);
path
=
srs_string_replace
(
path
,
"[02]"
,
buf
);
}
// [15], replace this const to current hour.
if
(
true
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
tm
->
tm_hour
);
snprintf
(
buf
,
sizeof
(
buf
),
"%
02
d"
,
tm
->
tm_hour
);
path
=
srs_string_replace
(
path
,
"[15]"
,
buf
);
}
// [04], repleace this const to current minute.
if
(
true
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
tm
->
tm_min
);
snprintf
(
buf
,
sizeof
(
buf
),
"%
02
d"
,
tm
->
tm_min
);
path
=
srs_string_replace
(
path
,
"[04]"
,
buf
);
}
// [05], repleace this const to current second.
if
(
true
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
tm
->
tm_sec
);
snprintf
(
buf
,
sizeof
(
buf
),
"%
02
d"
,
tm
->
tm_sec
);
path
=
srs_string_replace
(
path
,
"[05]"
,
buf
);
}
// [999], repleace this const to current millisecond.
...
...
trunk/src/kernel/srs_kernel_codec.cpp
查看文件 @
4f9df4f
...
...
@@ -31,6 +31,7 @@ using namespace std;
#include <srs_kernel_log.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_core_autofree.hpp>
string
srs_codec_video2str
(
SrsCodecVideo
codec
)
{
...
...
@@ -265,6 +266,30 @@ bool SrsFlvCodec::audio_is_aac(char* data, int size)
return
sound_format
==
SrsCodecAudioAAC
;
}
string
srs_codec_avc_nalu2str
(
SrsAvcNaluType
nalu_type
)
{
switch
(
nalu_type
)
{
case
SrsAvcNaluTypeNonIDR
:
return
"NonIDR"
;
case
SrsAvcNaluTypeDataPartitionA
:
return
"DataPartitionA"
;
case
SrsAvcNaluTypeDataPartitionB
:
return
"DataPartitionB"
;
case
SrsAvcNaluTypeDataPartitionC
:
return
"DataPartitionC"
;
case
SrsAvcNaluTypeIDR
:
return
"IDR"
;
case
SrsAvcNaluTypeSEI
:
return
"SEI"
;
case
SrsAvcNaluTypeSPS
:
return
"SPS"
;
case
SrsAvcNaluTypePPS
:
return
"PPS"
;
case
SrsAvcNaluTypeAccessUnitDelimiter
:
return
"AccessUnitDelimiter"
;
case
SrsAvcNaluTypeEOSequence
:
return
"EOSequence"
;
case
SrsAvcNaluTypeEOStream
:
return
"EOStream"
;
case
SrsAvcNaluTypeFilterData
:
return
"FilterData"
;
case
SrsAvcNaluTypeSPSExt
:
return
"SPSExt"
;
case
SrsAvcNaluTypePrefixNALU
:
return
"PrefixNALU"
;
case
SrsAvcNaluTypeSubsetSPS
:
return
"SubsetSPS"
;
case
SrsAvcNaluTypeLayerWithoutPartition
:
return
"LayerWithoutPartition"
;
case
SrsAvcNaluTypeCodedSliceExt
:
return
"CodedSliceExt"
;
case
SrsAvcNaluTypeReserved
:
default
:
return
"Other"
;
}
}
SrsCodecSampleUnit
::
SrsCodecSampleUnit
()
{
size
=
0
;
...
...
@@ -292,6 +317,8 @@ void SrsCodecSample::clear()
cts
=
0
;
frame_type
=
SrsCodecVideoAVCFrameReserved
;
avc_packet_type
=
SrsCodecVideoAVCTypeReserved
;
has_idr
=
false
;
first_nalu_type
=
SrsAvcNaluTypeReserved
;
acodec
=
SrsCodecAudioReserved1
;
sound_rate
=
SrsCodecAudioSampleRateReserved
;
...
...
@@ -315,6 +342,19 @@ int SrsCodecSample::add_sample_unit(char* bytes, int size)
sample_unit
->
bytes
=
bytes
;
sample_unit
->
size
=
size
;
// for video, parse the nalu type, set the IDR flag.
if
(
is_video
)
{
SrsAvcNaluType
nal_unit_type
=
(
SrsAvcNaluType
)(
bytes
[
0
]
&
0x1f
);
if
(
nal_unit_type
==
SrsAvcNaluTypeIDR
)
{
has_idr
=
true
;
}
if
(
first_nalu_type
==
SrsAvcNaluTypeReserved
)
{
first_nalu_type
=
nal_unit_type
;
}
}
return
ret
;
}
...
...
@@ -713,7 +753,8 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream)
return
ret
;
}
// 1 sps
// 1 sps, 7.3.2.1 Sequence parameter set RBSP syntax
// H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
if
(
!
stream
->
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"avc decode sequenc header sps failed. ret=%d"
,
ret
);
...
...
@@ -740,8 +781,7 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream)
if
(
sequenceParameterSetLength
>
0
)
{
srs_freep
(
sequenceParameterSetNALUnit
);
sequenceParameterSetNALUnit
=
new
char
[
sequenceParameterSetLength
];
memcpy
(
sequenceParameterSetNALUnit
,
stream
->
data
()
+
stream
->
pos
(),
sequenceParameterSetLength
);
stream
->
skip
(
sequenceParameterSetLength
);
stream
->
read_bytes
(
sequenceParameterSetNALUnit
,
sequenceParameterSetLength
);
}
// 1 pps
if
(
!
stream
->
require
(
1
))
{
...
...
@@ -770,10 +810,242 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream)
if
(
pictureParameterSetLength
>
0
)
{
srs_freep
(
pictureParameterSetNALUnit
);
pictureParameterSetNALUnit
=
new
char
[
pictureParameterSetLength
];
memcpy
(
pictureParameterSetNALUnit
,
stream
->
data
()
+
stream
->
pos
(),
pictureParameterSetLength
);
stream
->
skip
(
pictureParameterSetLength
);
stream
->
read_bytes
(
pictureParameterSetNALUnit
,
pictureParameterSetLength
);
}
return
avc_demux_sps
();
}
int
SrsAvcAacCodec
::
avc_demux_sps
()
{
int
ret
=
ERROR_SUCCESS
;
if
(
!
sequenceParameterSetLength
)
{
return
ret
;
}
SrsStream
stream
;
if
((
ret
=
stream
.
initialize
(
sequenceParameterSetNALUnit
,
sequenceParameterSetLength
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// for NALU, 7.3.1 NAL unit syntax
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 61.
if
(
!
stream
.
require
(
1
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"avc decode sps failed. ret=%d"
,
ret
);
return
ret
;
}
int8_t
nutv
=
stream
.
read_1bytes
();
// forbidden_zero_bit shall be equal to 0.
int8_t
forbidden_zero_bit
=
(
nutv
>>
7
)
&
0x01
;
if
(
forbidden_zero_bit
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"forbidden_zero_bit shall be equal to 0. ret=%d"
,
ret
);
return
ret
;
}
// nal_ref_idc not equal to 0 specifies that the content of the NAL unit contains a sequence parameter set or a picture
// parameter set or a slice of a reference picture or a slice data partition of a reference picture.
int8_t
nal_ref_idc
=
(
nutv
>>
5
)
&
0x03
;
if
(
!
nal_ref_idc
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"for sps, nal_ref_idc shall be not be equal to 0. ret=%d"
,
ret
);
return
ret
;
}
// 7.4.1 NAL unit semantics
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 61.
// nal_unit_type specifies the type of RBSP data structure contained in the NAL unit as specified in Table 7-1.
SrsAvcNaluType
nal_unit_type
=
(
SrsAvcNaluType
)(
nutv
&
0x1f
);
if
(
nal_unit_type
!=
7
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"for sps, nal_unit_type shall be equal to 7. ret=%d"
,
ret
);
return
ret
;
}
// decode the rbsp from sps.
// rbsp[ i ] a raw byte sequence payload is specified as an ordered sequence of bytes.
int8_t
*
rbsp
=
new
int8_t
[
sequenceParameterSetLength
];
SrsAutoFree
(
int8_t
,
rbsp
);
int
nb_rbsp
=
0
;
while
(
!
stream
.
empty
())
{
rbsp
[
nb_rbsp
]
=
stream
.
read_1bytes
();
// XX 00 00 03 XX, the 03 byte should be drop.
if
(
nb_rbsp
>
2
&&
rbsp
[
nb_rbsp
-
2
]
==
0
&&
rbsp
[
nb_rbsp
-
1
]
==
0
&&
rbsp
[
nb_rbsp
]
==
3
)
{
continue
;
}
nb_rbsp
++
;
}
return
avc_demux_sps_rbsp
((
char
*
)
rbsp
,
nb_rbsp
);
}
int
SrsAvcAacCodec
::
avc_demux_sps_rbsp
(
char
*
rbsp
,
int
nb_rbsp
)
{
int
ret
=
ERROR_SUCCESS
;
// reparse the rbsp.
SrsStream
stream
;
if
((
ret
=
stream
.
initialize
(
rbsp
,
nb_rbsp
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// for SPS, 7.3.2.1.1 Sequence parameter set data syntax
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62.
if
(
!
stream
.
require
(
3
))
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"sps shall atleast 3bytes. ret=%d"
,
ret
);
return
ret
;
}
u_int8_t
profile_idc
=
stream
.
read_1bytes
();
if
(
!
profile_idc
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"sps the profile_idc invalid. ret=%d"
,
ret
);
return
ret
;
}
int8_t
flags
=
stream
.
read_1bytes
();
if
(
flags
&
0x03
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"sps the flags invalid. ret=%d"
,
ret
);
return
ret
;
}
u_int8_t
level_idc
=
stream
.
read_1bytes
();
if
(
!
level_idc
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"sps the level_idc invalid. ret=%d"
,
ret
);
return
ret
;
}
SrsBitStream
bs
;
if
((
ret
=
bs
.
initialize
(
&
stream
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
seq_parameter_set_id
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
seq_parameter_set_id
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
seq_parameter_set_id
<
0
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"sps the seq_parameter_set_id invalid. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"sps parse profile=%d, level=%d, sps_id=%d"
,
profile_idc
,
level_idc
,
seq_parameter_set_id
);
if
(
profile_idc
==
100
||
profile_idc
==
110
||
profile_idc
==
122
||
profile_idc
==
244
||
profile_idc
==
44
||
profile_idc
==
83
||
profile_idc
==
86
||
profile_idc
==
118
||
profile_idc
==
128
)
{
int64_t
chroma_format_idc
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
chroma_format_idc
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
chroma_format_idc
==
3
)
{
int8_t
separate_colour_plane_flag
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_bit
(
&
bs
,
separate_colour_plane_flag
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
int64_t
bit_depth_luma_minus8
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
bit_depth_luma_minus8
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
bit_depth_chroma_minus8
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
bit_depth_chroma_minus8
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int8_t
qpprime_y_zero_transform_bypass_flag
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_bit
(
&
bs
,
qpprime_y_zero_transform_bypass_flag
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int8_t
seq_scaling_matrix_present_flag
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_bit
(
&
bs
,
seq_scaling_matrix_present_flag
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
seq_scaling_matrix_present_flag
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"sps the seq_scaling_matrix_present_flag invalid. ret=%d"
,
ret
);
return
ret
;
}
}
int64_t
log2_max_frame_num_minus4
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
log2_max_frame_num_minus4
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
pic_order_cnt_type
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
pic_order_cnt_type
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
pic_order_cnt_type
==
0
)
{
int64_t
log2_max_pic_order_cnt_lsb_minus4
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
log2_max_pic_order_cnt_lsb_minus4
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
else
if
(
pic_order_cnt_type
==
1
)
{
int8_t
delta_pic_order_always_zero_flag
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_bit
(
&
bs
,
delta_pic_order_always_zero_flag
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
offset_for_non_ref_pic
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
offset_for_non_ref_pic
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
offset_for_top_to_bottom_field
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
offset_for_top_to_bottom_field
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
num_ref_frames_in_pic_order_cnt_cycle
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
num_ref_frames_in_pic_order_cnt_cycle
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
num_ref_frames_in_pic_order_cnt_cycle
)
{
ret
=
ERROR_HLS_DECODE_ERROR
;
srs_error
(
"sps the num_ref_frames_in_pic_order_cnt_cycle invalid. ret=%d"
,
ret
);
return
ret
;
}
}
int64_t
max_num_ref_frames
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
max_num_ref_frames
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int8_t
gaps_in_frame_num_value_allowed_flag
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_bit
(
&
bs
,
gaps_in_frame_num_value_allowed_flag
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
pic_width_in_mbs_minus1
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
pic_width_in_mbs_minus1
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
int64_t
pic_height_in_map_units_minus1
=
-
1
;
if
((
ret
=
srs_avc_nalu_read_uev
(
&
bs
,
pic_height_in_map_units_minus1
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
width
=
(
int
)(
pic_width_in_mbs_minus1
+
1
)
*
16
;
height
=
(
int
)(
pic_height_in_map_units_minus1
+
1
)
*
16
;
return
ret
;
}
...
...
trunk/src/kernel/srs_kernel_codec.hpp
查看文件 @
4f9df4f
...
...
@@ -276,6 +276,52 @@ enum SrsCodecAudioSoundType
};
/**
* Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes
* H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83.
*/
enum
SrsAvcNaluType
{
// Unspecified
SrsAvcNaluTypeReserved
=
0
,
// Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp( )
SrsAvcNaluTypeNonIDR
=
1
,
// Coded slice data partition A slice_data_partition_a_layer_rbsp( )
SrsAvcNaluTypeDataPartitionA
=
2
,
// Coded slice data partition B slice_data_partition_b_layer_rbsp( )
SrsAvcNaluTypeDataPartitionB
=
3
,
// Coded slice data partition C slice_data_partition_c_layer_rbsp( )
SrsAvcNaluTypeDataPartitionC
=
4
,
// Coded slice of an IDR picture slice_layer_without_partitioning_rbsp( )
SrsAvcNaluTypeIDR
=
5
,
// Supplemental enhancement information (SEI) sei_rbsp( )
SrsAvcNaluTypeSEI
=
6
,
// Sequence parameter set seq_parameter_set_rbsp( )
SrsAvcNaluTypeSPS
=
7
,
// Picture parameter set pic_parameter_set_rbsp( )
SrsAvcNaluTypePPS
=
8
,
// Access unit delimiter access_unit_delimiter_rbsp( )
SrsAvcNaluTypeAccessUnitDelimiter
=
9
,
// End of sequence end_of_seq_rbsp( )
SrsAvcNaluTypeEOSequence
=
10
,
// End of stream end_of_stream_rbsp( )
SrsAvcNaluTypeEOStream
=
11
,
// Filler data filler_data_rbsp( )
SrsAvcNaluTypeFilterData
=
12
,
// Sequence parameter set extension seq_parameter_set_extension_rbsp( )
SrsAvcNaluTypeSPSExt
=
13
,
// Prefix NAL unit prefix_nal_unit_rbsp( )
SrsAvcNaluTypePrefixNALU
=
14
,
// Subset sequence parameter set subset_seq_parameter_set_rbsp( )
SrsAvcNaluTypeSubsetSPS
=
15
,
// Coded slice of an auxiliary coded picture without partitioning slice_layer_without_partitioning_rbsp( )
SrsAvcNaluTypeLayerWithoutPartition
=
19
,
// Coded slice extension slice_layer_extension_rbsp( )
SrsAvcNaluTypeCodedSliceExt
=
20
,
};
std
::
string
srs_codec_avc_nalu2str
(
SrsAvcNaluType
nalu_type
);
/**
* the codec sample unit.
* for h.264 video packet, a NALU is a sample unit.
* for aac raw audio packet, a NALU is the entire aac raw data.
...
...
@@ -334,6 +380,9 @@ public:
// video specified
SrsCodecVideoAVCFrame
frame_type
;
SrsCodecVideoAVCType
avc_packet_type
;
// whether sample_units contains IDR frame.
bool
has_idr
;
SrsAvcNaluType
first_nalu_type
;
public
:
// audio specified
SrsCodecAudio
acodec
;
...
...
@@ -581,6 +630,11 @@ private:
*/
virtual
int
avc_demux_sps_pps
(
SrsStream
*
stream
);
/**
* decode the sps rbsp stream.
*/
virtual
int
avc_demux_sps
();
virtual
int
avc_demux_sps_rbsp
(
char
*
rbsp
,
int
nb_rbsp
);
/**
* demux the avc NALU in "AnnexB"
* from H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
*/
...
...
trunk/src/kernel/srs_kernel_error.hpp
查看文件 @
4f9df4f
...
...
@@ -215,7 +215,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_HTTP_DVR_CREATE_REQUEST 3053
#define ERROR_HTTP_DVR_NO_TAEGET 3054
#define ERROR_ADTS_ID_NOT_AAC 3055
// HDS error code
#define ERROR_HDS_OPEN_F4M_FAILED 3056
#define ERROR_HDS_WRITE_F4M_FAILED 3057
...
...
@@ -254,6 +253,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_STREAM_CASTER_FLV_TAG 4024
#define ERROR_HTTP_RESPONSE_EOF 4025
#define ERROR_HTTP_INVALID_CHUNK_HEADER 4026
#define ERROR_AVC_NALU_UEV 4027
///////////////////////////////////////////////////////
// user-define error.
...
...
trunk/src/kernel/srs_kernel_stream.cpp
查看文件 @
4f9df4f
...
...
@@ -252,4 +252,38 @@ void SrsStream::write_bytes(char* data, int size)
p
+=
size
;
}
SrsBitStream
::
SrsBitStream
()
{
cb
=
0
;
cb_left
=
0
;
stream
=
NULL
;
}
SrsBitStream
::~
SrsBitStream
()
{
}
int
SrsBitStream
::
initialize
(
SrsStream
*
s
)
{
stream
=
s
;
return
ERROR_SUCCESS
;
}
bool
SrsBitStream
::
empty
()
{
if
(
cb_left
)
{
return
false
;
}
return
stream
->
empty
();
}
int8_t
SrsBitStream
::
read_bit
()
{
if
(
!
cb_left
)
{
srs_assert
(
!
stream
->
empty
());
cb
=
stream
->
read_1bytes
();
cb_left
=
8
;
}
int8_t
v
=
(
cb
>>
(
cb_left
-
1
))
&
0x01
;
cb_left
--
;
return
v
;
}
...
...
trunk/src/kernel/srs_kernel_stream.hpp
查看文件 @
4f9df4f
...
...
@@ -154,4 +154,22 @@ public:
virtual
void
write_bytes
(
char
*
data
,
int
size
);
};
/**
* the bit stream.
*/
class
SrsBitStream
{
private
:
int8_t
cb
;
u_int8_t
cb_left
;
SrsStream
*
stream
;
public
:
SrsBitStream
();
virtual
~
SrsBitStream
();
public
:
virtual
int
initialize
(
SrsStream
*
s
);
virtual
bool
empty
();
virtual
int8_t
read_bit
();
};
#endif
...
...
trunk/src/kernel/srs_kernel_ts.cpp
查看文件 @
4f9df4f
...
...
@@ -2835,19 +2835,104 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
{
int
ret
=
ERROR_SUCCESS
;
// for type1/5/6, insert aud packet.
u_int8_t
aud_nal
[]
=
{
0x00
,
0x00
,
0x00
,
0x01
,
0x09
,
0xf0
};
bool
sps_pps_sent
=
false
;
bool
aud_sent
=
false
;
// mux the samples in annexb format,
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 324.
/**
* a ts sample is format as:
* 00 00 00 01 // header
* xxxxxxx // data bytes
* 00 00 01 // continue header
* xxxxxxx // data bytes.
* so, for each sample, we append header in aud_nal, then appends the bytes in sample.
*/
* 00 00 00 01 // header
* xxxxxxx // data bytes
* 00 00 01 // continue header
* xxxxxxx // data bytes.
*
* nal_unit_type specifies the type of RBSP data structure contained in the NAL unit as specified in Table 7-1.
* Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes
* H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83.
* 1, Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp( )
* 2, Coded slice data partition A slice_data_partition_a_layer_rbsp( )
* 3, Coded slice data partition B slice_data_partition_b_layer_rbsp( )
* 4, Coded slice data partition C slice_data_partition_c_layer_rbsp( )
* 5, Coded slice of an IDR picture slice_layer_without_partitioning_rbsp( )
* 6, Supplemental enhancement information (SEI) sei_rbsp( )
* 7, Sequence parameter set seq_parameter_set_rbsp( )
* 8, Picture parameter set pic_parameter_set_rbsp( )
* 9, Access unit delimiter access_unit_delimiter_rbsp( )
* 10, End of sequence end_of_seq_rbsp( )
* 11, End of stream end_of_stream_rbsp( )
* 12, Filler data filler_data_rbsp( )
* 13, Sequence parameter set extension seq_parameter_set_extension_rbsp( )
* 14, Prefix NAL unit prefix_nal_unit_rbsp( )
* 15, Subset sequence parameter set subset_seq_parameter_set_rbsp( )
* 19, Coded slice of an auxiliary coded picture without partitioning slice_layer_without_partitioning_rbsp( )
* 20, Coded slice extension slice_layer_extension_rbsp( )
* the first ts message of apple sample:
* annexb 4B header, 2B aud(nal_unit_type:6)(0x09 0xf0)
* annexb 4B header, 19B sps(nal_unit_type:7)
* annexb 3B header, 4B pps(nal_unit_type:8)
* annexb 3B header, 12B nalu(nal_unit_type:6)
* annexb 3B header, 21B nalu(nal_unit_type:6)
* annexb 3B header, 2762B nalu(nal_unit_type:5)
* annexb 3B header, 3535B nalu(nal_unit_type:5)
* the second ts message of apple ts sample:
* annexb 4B header, 2B aud(nal_unit_type:6)(0x09 0xf0)
* annexb 3B header, 21B nalu(nal_unit_type:6)
* annexb 3B header, 379B nalu(nal_unit_type:1)
* annexb 3B header, 406B nalu(nal_unit_type:1)
*/
static
u_int8_t
fresh_nalu_header
[]
=
{
0x00
,
0x00
,
0x00
,
0x01
};
static
u_int8_t
cont_nalu_header
[]
=
{
0x00
,
0x00
,
0x01
};
// the aud(access unit delimiter) before each frame.
// 7.3.2.4 Access unit delimiter RBSP syntax
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 66.
//
// primary_pic_type u(3), the first 3bits, primary_pic_type indicates that the slice_type values
// for all slices of the primary coded picture are members of the set listed in Table 7-5 for
// the given value of primary_pic_type.
// 0, slice_type 2, 7
// 1, slice_type 0, 2, 5, 7
// 2, slice_type 0, 1, 2, 5, 6, 7
// 3, slice_type 4, 9
// 4, slice_type 3, 4, 8, 9
// 5, slice_type 2, 4, 7, 9
// 6, slice_type 0, 2, 3, 4, 5, 7, 8, 9
// 7, slice_type 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
// 7.4.2.4 Access unit delimiter RBSP semantics
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 102.
//
// slice_type specifies the coding type of the slice according to Table 7-6.
// 0, P (P slice)
// 1, B (B slice)
// 2, I (I slice)
// 3, SP (SP slice)
// 4, SI (SI slice)
// 5, P (P slice)
// 6, B (B slice)
// 7, I (I slice)
// 8, SP (SP slice)
// 9, SI (SI slice)
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 105.
static
u_int8_t
aud_nalu_7
[]
=
{
0x09
,
0xf0
};
video
->
payload
->
append
((
const
char
*
)
fresh_nalu_header
,
4
);
video
->
payload
->
append
((
const
char
*
)
aud_nalu_7
,
2
);
// when ts message(samples) contains IDR, insert sps+pps.
if
(
sample
->
has_idr
)
{
// fresh nalu header before sps.
if
(
codec
->
sequenceParameterSetLength
>
0
)
{
// AnnexB prefix, for sps always 4 bytes header
video
->
payload
->
append
((
const
char
*
)
fresh_nalu_header
,
4
);
// sps
video
->
payload
->
append
(
codec
->
sequenceParameterSetNALUnit
,
codec
->
sequenceParameterSetLength
);
}
// cont nalu header before pps.
if
(
codec
->
pictureParameterSetLength
>
0
)
{
// AnnexB prefix, for pps always 3 bytes header
video
->
payload
->
append
((
const
char
*
)
cont_nalu_header
,
3
);
// pps
video
->
payload
->
append
(
codec
->
pictureParameterSetNALUnit
,
codec
->
pictureParameterSetLength
);
}
}
// all sample use cont nalu header, except the sps-pps before IDR frame.
for
(
int
i
=
0
;
i
<
sample
->
nb_sample_units
;
i
++
)
{
SrsCodecSampleUnit
*
sample_unit
=
&
sample
->
sample_units
[
i
];
int32_t
size
=
sample_unit
->
size
;
...
...
@@ -2858,83 +2943,22 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
return
ret
;
}
/**
* step 1:
* first, before each "real" sample,
* we add some packets according to the nal_unit_type,
* for example, when got nal_unit_type=5, insert SPS/PPS before sample.
*/
// 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
u_int8_t
nal_unit_type
;
nal_unit_type
=
*
sample_unit
->
bytes
;
nal_unit_type
&=
0x1f
;
// @see: ngx_rtmp_hls_video
// Table 7-1 NAL unit type codes, page 61
// 1: Coded slice
if
(
nal_unit_type
==
1
)
{
sps_pps_sent
=
false
;
}
// 6: Supplemental enhancement information (SEI) sei_rbsp( ), page 61
// @see: ngx_rtmp_hls_append_aud
if
(
!
aud_sent
)
{
// @remark, when got type 9, we donot send aud_nal, but it will make
// ios unhappy, so we remove it.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/281
/*if (nal_unit_type == 9) {
aud_sent = true;
}*/
if
(
nal_unit_type
==
1
||
nal_unit_type
==
5
||
nal_unit_type
==
6
)
{
// for type 6, append a aud with type 9.
video
->
payload
->
append
((
const
char
*
)
aud_nal
,
sizeof
(
aud_nal
));
aud_sent
=
true
;
}
}
// 5: Coded slice of an IDR picture.
// insert sps/pps before IDR or key frame is ok.
if
(
nal_unit_type
==
5
&&
!
sps_pps_sent
)
{
sps_pps_sent
=
true
;
// @see: ngx_rtmp_hls_append_sps_pps
if
(
codec
->
sequenceParameterSetLength
>
0
)
{
// AnnexB prefix, for sps always 4 bytes header
video
->
payload
->
append
((
const
char
*
)
aud_nal
,
4
);
// sps
video
->
payload
->
append
(
codec
->
sequenceParameterSetNALUnit
,
codec
->
sequenceParameterSetLength
);
}
if
(
codec
->
pictureParameterSetLength
>
0
)
{
// AnnexB prefix, for pps always 4 bytes header
video
->
payload
->
append
((
const
char
*
)
aud_nal
,
4
);
// pps
video
->
payload
->
append
(
codec
->
pictureParameterSetNALUnit
,
codec
->
pictureParameterSetLength
);
}
}
// 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83.
SrsAvcNaluType
nal_unit_type
=
(
SrsAvcNaluType
)(
sample_unit
->
bytes
[
0
]
&
0x1f
);
// 7-9, ignore, @see: ngx_rtmp_hls_video
if
(
nal_unit_type
>=
7
&&
nal_unit_type
<=
9
)
{
continue
;
// ignore SPS/PPS/AUD
switch
(
nal_unit_type
)
{
case
SrsAvcNaluTypeSPS
:
case
SrsAvcNaluTypePPS
:
case
SrsAvcNaluTypeAccessUnitDelimiter
:
continue
;
default
:
break
;
}
/**
* step 2:
* output the "real" sample, in buf.
* when we output some special assist packets according to nal_unit_type
*/
// 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
(
video
->
payload
->
length
()
==
0
)
{
p
=
aud_nal
;
}
video
->
payload
->
append
((
const
char
*
)
p
,
end
-
p
);
// insert cont nalu header before frame.
video
->
payload
->
append
((
const
char
*
)
cont_nalu_header
,
3
);
// sample data
video
->
payload
->
append
(
sample_unit
->
bytes
,
sample_unit
->
size
);
...
...
trunk/src/kernel/srs_kernel_utility.cpp
查看文件 @
4f9df4f
...
...
@@ -46,6 +46,53 @@ using namespace std;
// @see SRS_SYS_TIME_RESOLUTION_MS_TIMES
#define SYS_TIME_RESOLUTION_US 300*1000
int
srs_avc_nalu_read_uev
(
SrsBitStream
*
stream
,
int64_t
&
v
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
stream
->
empty
())
{
return
ERROR_AVC_NALU_UEV
;
}
// ue(v) in 9.1 Parsing process for Exp-Golomb codes
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 227.
// Syntax elements coded as ue(v), me(v), or se(v) are Exp-Golomb-coded.
// leadingZeroBits = -1;
// for( b = 0; !b; leadingZeroBits++ )
// b = read_bits( 1 )
// The variable codeNum is then assigned as follows:
// codeNum = (2<<leadingZeroBits) – 1 + read_bits( leadingZeroBits )
int
leadingZeroBits
=
-
1
;
for
(
int8_t
b
=
0
;
!
b
&&
!
stream
->
empty
();
leadingZeroBits
++
)
{
b
=
stream
->
read_bit
();
}
if
(
leadingZeroBits
>=
64
)
{
return
ERROR_AVC_NALU_UEV
;
}
v
=
(
1
<<
leadingZeroBits
)
-
1
;
for
(
int
i
=
0
;
i
<
leadingZeroBits
;
i
++
)
{
int64_t
b
=
stream
->
read_bit
();
v
+=
b
<<
(
leadingZeroBits
-
1
);
}
return
ret
;
}
int
srs_avc_nalu_read_bit
(
SrsBitStream
*
stream
,
int8_t
&
v
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
stream
->
empty
())
{
return
ERROR_AVC_NALU_UEV
;
}
v
=
stream
->
read_bit
();
return
ret
;
}
static
int64_t
_srs_system_time_us_cache
=
0
;
static
int64_t
_srs_system_time_startup_time
=
0
;
...
...
@@ -294,6 +341,21 @@ bool srs_path_exists(std::string path)
return
false
;
}
string
srs_path_dirname
(
string
path
)
{
std
::
string
dirname
=
path
;
size_t
pos
=
string
::
npos
;
if
((
pos
=
dirname
.
rfind
(
"/"
))
!=
string
::
npos
)
{
if
(
pos
==
0
)
{
return
"/"
;
}
dirname
=
dirname
.
substr
(
0
,
pos
);
}
return
dirname
;
}
bool
srs_avc_startswith_annexb
(
SrsStream
*
stream
,
int
*
pnb_start_code
)
{
char
*
bytes
=
stream
->
data
()
+
stream
->
pos
();
...
...
trunk/src/kernel/srs_kernel_utility.hpp
查看文件 @
4f9df4f
...
...
@@ -33,11 +33,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <string>
class
SrsStream
;
class
SrsBitStream
;
// compare
#define srs_min(a, b) (((a) < (b))? (a) : (b))
#define srs_max(a, b) (((a) < (b))? (b) : (a))
// read nalu uev.
extern
int
srs_avc_nalu_read_uev
(
SrsBitStream
*
stream
,
int64_t
&
v
);
extern
int
srs_avc_nalu_read_bit
(
SrsBitStream
*
stream
,
int8_t
&
v
);
// get current system time in ms, use cache to avoid performance problem
extern
int64_t
srs_get_system_time_ms
();
extern
int64_t
srs_get_system_startup_time_ms
();
...
...
@@ -68,6 +73,8 @@ extern int srs_create_dir_recursively(std::string dir);
// whether path exists.
extern
bool
srs_path_exists
(
std
::
string
path
);
// get the dirname of path
extern
std
::
string
srs_path_dirname
(
std
::
string
path
);
/**
* whether stream starts with the avc NALU in "AnnexB"
...
...
请
注册
或
登录
后发表评论