下面以“大牛直播SDK 的 RTSP 播放器遇到 RTP 不带 Marker 位(M bit)”为切入点,结合 RTP/RTCP 基础 与 H.264/H.265/AAC 的负载规范,说明发送端如何规范打包,以及接收端如何稳健容错(即使对端未按规范设置 Marker)。
小结:规范的发送端应正确设置 M 位;但健壮的接收端不能只依赖 M 位 来切帧,尤其是面对一些“简化实现”的摄像头/设备。
MTU - IP/UDP/RTP - 负载头
时,整 NALU 进一包;
S=1,E=0
,中片 S=0,E=0
,尾片 S=0,E=1
;
sizeLength/indexLength/indexDeltaLength
生成 AU-headers-section;最简单做法是 “一包一帧(1 AU/包)”;
即使对端未设置 M 位,播放器也应能“稳健切帧”而不积压卡顿:
for each AccessUnit AU:
ts = au_pts_in_seconds * 90000
last_nalu_index = AU.nalus.last_index
for i, nalu in enumerate(AU.nalus):
if nalu.size <= PAYLOAD_BUDGET:
M = (i == last_nalu_index) ? 1 : 0
send_single_nalu(nalu, ts, M)
else:
fragments = fragment(nalu, PAYLOAD_BUDGET)
for j, frag in enumerate(fragments):
S = (j == 0); E = (j == fragments.last_index)
M = (E && i == last_nalu_index) ? 1 : 0
send_fu(frag, ts, S, E, M)
onRtp(pkt):
key = (pkt.ssrc, pkt.timestamp)
au = map[key]
au.add(pkt)
if pkt.marker == 1:
flush(au)
else if timestamp_changed_since_last_packet(key):
flush(previous_au_for_that_ssrc)
else if au_waiting_time_exceeds(dynamic_threshold):
flush(au) // 超时兜底,避免卡住
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。