Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Z
ZLMediaKit
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
张翔宇
ZLMediaKit
Commits
291caf53
Commit
291caf53
authored
Jan 23, 2021
by
xiongziliang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
H265 rtp支持聚合包
parent
fc8462be
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
175 行增加
和
92 行删除
+175
-92
src/Extension/H265Rtp.cpp
+167
-88
src/Extension/H265Rtp.h
+8
-4
没有找到文件。
src/Extension/H265Rtp.cpp
查看文件 @
291caf53
...
@@ -12,42 +12,21 @@
...
@@ -12,42 +12,21 @@
namespace
mediakit
{
namespace
mediakit
{
//41
//H265 nalu 头两个字节的定义
//42 0 1
/*
//43 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 1
//44 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
//45 |F| Type | LayerId | TID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//46 +-------------+-----------------+
|F| Type | LayerId | TID |
//48 F = 0, 1bit
+-------------+-----------------+
//49 Type = 49 (fragmentation unit (FU)), 6bit
Forbidden zero(F) : 1 bit
//50 LayerId = 0, 6bit
NAL unit type(Type) : 6 bits
//51 TID = 1, 3bit
NUH layer ID(LayerId) : 6 bits
//56 /*
NUH temporal ID plus 1 (TID) : 3 bits
//57 create the FU header
*/
//58
//59 0 1 2 3 4 5 6 7
//60 +-+-+-+-+-+-+-+-+
//61 |S|E| FuType |
//62 +---------------+
//64 S = variable
//65 E = variable
//66 FuType = NAL unit type
//67
typedef
struct
{
unsigned
S
:
1
;
unsigned
E
:
1
;
unsigned
type
:
6
;
}
FU
;
static
void
MakeFU
(
uint8_t
in
,
FU
&
fu
)
{
fu
.
S
=
in
>>
7
;
fu
.
E
=
(
in
>>
6
)
&
0x01
;
fu
.
type
=
in
&
0x3f
;
}
H265RtpDecoder
::
H265RtpDecoder
()
{
H265RtpDecoder
::
H265RtpDecoder
()
{
_
h265
frame
=
obtainFrame
();
_frame
=
obtainFrame
();
}
}
H265Frame
::
Ptr
H265RtpDecoder
::
obtainFrame
()
{
H265Frame
::
Ptr
H265RtpDecoder
::
obtainFrame
()
{
...
@@ -58,82 +37,182 @@ H265Frame::Ptr H265RtpDecoder::obtainFrame() {
...
@@ -58,82 +37,182 @@ H265Frame::Ptr H265RtpDecoder::obtainFrame() {
return
frame
;
return
frame
;
}
}
bool
H265RtpDecoder
::
inputRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
key_pos
)
{
#define AV_RB16(x) \
return
decodeRtp
(
rtp
);
((((const uint8_t*)(x))[0] << 8) | \
((const uint8_t*)(x))[1])
#define CHECK_SIZE(total, size, ret) \
if (total < size) { \
WarnL << "数据不够:" << total << " " << size; return ret; \
}
// 4.4.2. Aggregation Packets (APs) (p25)
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RTP Header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PayloadHdr (Type=48) | NALU 1 DONL |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 1 Size | NALU 1 HDR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| NALU 1 Data . . . |
| |
+ . . . +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | NALU 2 DOND | NALU 2 Size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 2 HDR | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ NALU 2 Data |
| |
| . . . +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| : ...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
bool
H265RtpDecoder
::
unpackAp
(
const
uint8_t
*
ptr
,
ssize_t
size
,
uint32_t
stamp
){
bool
have_key_frame
=
false
;
//忽略PayloadHdr
CHECK_SIZE
(
size
,
2
,
have_key_frame
);
ptr
+=
2
;
size
-=
2
;
while
(
size
)
{
if
(
_using_donl_field
)
{
CHECK_SIZE
(
size
,
2
,
have_key_frame
);
uint16_t
donl
=
AV_RB16
(
ptr
);
size
-=
2
;
ptr
+=
2
;
}
CHECK_SIZE
(
size
,
2
,
have_key_frame
);
uint16_t
nalu_size
=
AV_RB16
(
ptr
);
size
-=
2
;
ptr
+=
2
;
CHECK_SIZE
(
size
,
nalu_size
,
have_key_frame
)
if
(
singleFrame
(
ptr
,
nalu_size
,
stamp
))
{
have_key_frame
=
true
;
}
size
-=
nalu_size
;
ptr
+=
nalu_size
;
}
return
have_key_frame
;
}
// 4.4.3. Fragmentation Units (p29)
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PayloadHdr (Type=49) | FU header | DONL (cond) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
| DONL (cond) | |
|-+-+-+-+-+-+-+-+ |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| : ...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E| FuType |
+---------------+
*/
bool
H265RtpDecoder
::
mergeFu
(
const
uint8_t
*
ptr
,
ssize_t
size
,
uint16_t
seq
,
uint32_t
stamp
){
CHECK_SIZE
(
size
,
4
,
false
);
auto
s_bit
=
ptr
[
2
]
>>
7
;
auto
e_bit
=
(
ptr
[
2
]
>>
6
)
&
0x01
;
auto
type
=
ptr
[
2
]
&
0x3f
;
if
(
s_bit
)
{
//该帧的第一个rtp包
_frame
->
_buffer
.
assign
(
"
\x00\x00\x00\x01
"
,
4
);
//恢复nalu头两个字节
_frame
->
_buffer
.
push_back
((
type
<<
1
)
|
(
ptr
[
0
]
&
0x81
));
_frame
->
_buffer
.
push_back
(
ptr
[
1
]);
}
if
(
!
s_bit
&&
seq
!=
(
uint16_t
)
(
_last_seq
+
1
)
&&
seq
!=
0
)
{
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
_frame
->
_buffer
.
clear
();
WarnL
<<
"rtp丢包: "
<<
seq
<<
" != "
<<
_last_seq
<<
" + 1,该帧被废弃"
;
return
false
;
}
//跳过PayloadHdr + FU header
ptr
+=
3
;
size
-=
3
;
if
(
_using_donl_field
)
{
//DONL确保不少于2个字节
CHECK_SIZE
(
size
,
2
,
false
);
uint16_t
donl
=
AV_RB16
(
ptr
);
size
-=
2
;
ptr
+=
2
;
}
CHECK_SIZE
(
size
,
1
,
false
);
if
(
!
e_bit
)
{
//非末尾包
_last_seq
=
seq
;
_frame
->
_buffer
.
append
((
char
*
)
ptr
,
size
);
return
s_bit
?
_frame
->
keyFrame
()
:
false
;
}
//该帧最后一个rtp包
_frame
->
_pts
=
stamp
;
_frame
->
_buffer
.
append
((
char
*
)
ptr
,
size
);
outputFrame
(
_frame
);
return
false
;
}
}
bool
H265RtpDecoder
::
decodeRtp
(
const
RtpPacket
::
Ptr
&
rtppack
)
{
bool
H265RtpDecoder
::
inputRtp
(
const
RtpPacket
::
Ptr
&
rtppack
,
bool
)
{
const
uint8_t
*
frame
=
(
uint8_t
*
)
rtppack
->
data
()
+
rtppack
->
offset
;
const
uint8_t
*
frame
=
(
uint8_t
*
)
rtppack
->
data
()
+
rtppack
->
offset
;
auto
length
=
rtppack
->
size
()
-
rtppack
->
offset
;
auto
length
=
rtppack
->
size
()
-
rtppack
->
offset
;
int
nal
=
H265_TYPE
(
frame
[
0
]);
int
nal
=
H265_TYPE
(
frame
[
0
]);
if
(
nal
>
50
){
if
(
nal
>
50
){
// packet discard, Unsupported (HEVC) NAL type
WarnL
<<
"不支持该类型的265 RTP包"
<<
nal
;
WarnL
<<
"不支持该类型的265 RTP包"
<<
nal
;
return
false
;
// packet discard, Unsupported (HEVC) NAL type
return
false
;
}
}
switch
(
nal
)
{
switch
(
nal
)
{
case
50
:
case
50
:
case
48
:
// aggregated packet (AP) - with two or more NAL units
//4.4.4. PACI Packets (p32)
WarnL
<<
"不支持该类型的265 RTP包"
<<
nal
;
WarnL
<<
"不支持该类型的265 RTP包"
<<
nal
;
return
false
;
return
false
;
case
49
:
{
case
48
:
// aggregated packet (AP) - with two or more NAL units
return
unpackAp
(
frame
,
length
,
rtppack
->
timeStamp
);
case
49
:
// fragmentation unit (FU)
// fragmentation unit (FU)
FU
fu
;
return
mergeFu
(
frame
,
length
,
rtppack
->
sequence
,
rtppack
->
timeStamp
);
MakeFU
(
frame
[
2
],
fu
);
default
:
if
(
fu
.
S
)
{
// 4.4.1. Single NAL Unit Packets (p24)
//该帧的第一个rtp包
return
singleFrame
(
frame
,
length
,
rtppack
->
timeStamp
);
_h265frame
->
_buffer
.
assign
(
"\x0\x0\x0\x1"
,
4
);
_h265frame
->
_buffer
.
push_back
(
fu
.
type
<<
1
);
_h265frame
->
_buffer
.
push_back
(
0x01
);
_h265frame
->
_buffer
.
append
((
char
*
)
frame
+
3
,
length
-
3
);
_h265frame
->
_pts
=
rtppack
->
timeStamp
;
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
_lastSeq
=
rtppack
->
sequence
;
return
(
_h265frame
->
keyFrame
());
//i frame
}
if
(
rtppack
->
sequence
!=
(
uint16_t
)(
_lastSeq
+
1
)
&&
rtppack
->
sequence
!=
0
)
{
//中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃
_h265frame
->
_buffer
.
clear
();
WarnL
<<
"rtp丢包: "
<<
rtppack
->
sequence
<<
" != "
<<
_lastSeq
<<
" + 1,该帧被废弃"
;
return
false
;
}
if
(
!
fu
.
E
)
{
//该帧的中间rtp包
_h265frame
->
_buffer
.
append
((
char
*
)
frame
+
3
,
length
-
3
);
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
_lastSeq
=
rtppack
->
sequence
;
return
false
;
}
//该帧最后一个rtp包
_h265frame
->
_buffer
.
append
((
char
*
)
frame
+
3
,
length
-
3
);
_h265frame
->
_pts
=
rtppack
->
timeStamp
;
onGetH265
(
_h265frame
);
return
false
;
}
default
:
// 4.4.1. Single NAL Unit Packets (p24)
//a full frame
_h265frame
->
_buffer
.
assign
(
"\x0\x0\x0\x1"
,
4
);
_h265frame
->
_buffer
.
append
((
char
*
)
frame
,
length
);
_h265frame
->
_pts
=
rtppack
->
timeStamp
;
auto
key
=
_h265frame
->
keyFrame
();
onGetH265
(
_h265frame
);
return
key
;
}
}
}
}
void
H265RtpDecoder
::
onGetH265
(
const
H265Frame
::
Ptr
&
frame
)
{
bool
H265RtpDecoder
::
singleFrame
(
const
uint8_t
*
ptr
,
ssize_t
size
,
uint32_t
stamp
){
//a full frame
_frame
->
_buffer
.
assign
(
"
\x00\x00\x00\x01
"
,
4
);
_frame
->
_buffer
.
append
((
char
*
)
ptr
,
size
);
_frame
->
_pts
=
stamp
;
auto
key
=
_frame
->
keyFrame
();
outputFrame
(
_frame
);
return
key
;
}
void
H265RtpDecoder
::
outputFrame
(
const
H265Frame
::
Ptr
&
frame
)
{
//rtsp没有dts,那么根据pts排序算法生成dts
//rtsp没有dts,那么根据pts排序算法生成dts
_dts_generator
.
getDts
(
frame
->
_pts
,
frame
->
_dts
);
_dts_generator
.
getDts
(
frame
->
_pts
,
frame
->
_dts
);
//
写入环形缓存
//
输出frame
RtpCodec
::
inputFrame
(
frame
);
RtpCodec
::
inputFrame
(
frame
);
_
h265
frame
=
obtainFrame
();
_frame
=
obtainFrame
();
}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
H265RtpEncoder
::
H265RtpEncoder
(
uint32_t
ui32Ssrc
,
H265RtpEncoder
::
H265RtpEncoder
(
uint32_t
ui32Ssrc
,
...
...
src/Extension/H265Rtp.h
查看文件 @
291caf53
...
@@ -44,13 +44,17 @@ public:
...
@@ -44,13 +44,17 @@ public:
}
}
private
:
private
:
bool
decodeRtp
(
const
RtpPacket
::
Ptr
&
rtp
);
bool
unpackAp
(
const
uint8_t
*
ptr
,
ssize_t
size
,
uint32_t
stamp
);
void
onGetH265
(
const
H265Frame
::
Ptr
&
frame
);
bool
mergeFu
(
const
uint8_t
*
ptr
,
ssize_t
size
,
uint16_t
seq
,
uint32_t
stamp
);
bool
singleFrame
(
const
uint8_t
*
ptr
,
ssize_t
size
,
uint32_t
stamp
);
H265Frame
::
Ptr
obtainFrame
();
H265Frame
::
Ptr
obtainFrame
();
void
outputFrame
(
const
H265Frame
::
Ptr
&
frame
);
private
:
private
:
uint16_t
_lastSeq
=
0
;
bool
_using_donl_field
=
false
;
H265Frame
::
Ptr
_h265frame
;
uint16_t
_last_seq
=
0
;
H265Frame
::
Ptr
_frame
;
DtsGenerator
_dts_generator
;
DtsGenerator
_dts_generator
;
};
};
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论