Files
engine/codec/h264.go
langhuihui b87416b78e feat: add insert sei
feat: add engine init done event
refactor: remove ring_lock
fix: retry connect to console
fix: h265 sps parse error
fix: concurrent publish

desc:
- 增加插入SEI帧的功能
- 增加engine初始化完成事件
- 删除ring_lock,DataTrack和MediaTrack共用一个ring
- 修复console无限重连导致远程服务器崩溃问题
- 修复h265 sps解析错误问题
- 修复并发发布导致的问题
2023-06-16 22:27:34 +08:00

326 lines
9.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package codec
import (
"bytes"
"errors"
"io"
"m7s.live/engine/v4/util"
"m7s.live/engine/v4/util/bits/pio"
)
// Start Code + NAL Unit -> NALU Header + NALU Body
// RTP Packet -> NALU Header + NALU Body
// NALU Body -> Slice Header + Slice data
// Slice data -> flags + Macroblock layer1 + Macroblock layer2 + ...
// Macroblock layer1 -> mb_type + PCM Data
// Macroblock layer2 -> mb_type + Sub_mb_pred or mb_pred + Residual Data
// Residual Data ->
type H264NALUType byte
func (b H264NALUType) Or(b2 byte) byte {
return byte(b) | b2
}
func (b H264NALUType) Offset() int {
switch b {
case NALU_STAPA:
return 1
case NALU_STAPB:
return 3
case NALU_FUA:
return 2
case NALU_FUB:
return 4
}
return 0
}
func (b H264NALUType) Byte() byte {
return byte(b)
}
func ParseH264NALUType(b byte) H264NALUType {
return H264NALUType(b & 0x1F)
}
func (H264NALUType) Parse(b byte) H264NALUType {
return H264NALUType(b & 0x1F)
}
func (H264NALUType) ParseBytes(bs []byte) H264NALUType {
return H264NALUType(bs[0] & 0x1F)
}
const (
// NALU Type
NALU_Unspecified H264NALUType = iota
NALU_Non_IDR_Picture // 1
NALU_Data_Partition_A // 2
NALU_Data_Partition_B // 3
NALU_Data_Partition_C // 4
NALU_IDR_Picture // 5
NALU_SEI // 6
NALU_SPS // 7
NALU_PPS // 8
NALU_Access_Unit_Delimiter // 9
NALU_Sequence_End // 10
NALU_Stream_End // 11
NALU_Filler_Data // 12
NALU_SPS_Extension // 13
NALU_Prefix // 14
NALU_SPS_Subset // 15
NALU_DPS // 16
NALU_Reserved1 // 17
NALU_Reserved2 // 18
NALU_Not_Auxiliary_Coded // 19
NALU_Coded_Slice_Extension // 20
NALU_Reserved3 // 21
NALU_Reserved4 // 22
NALU_Reserved5 // 23
NALU_STAPA // 24
NALU_STAPB
NALU_MTAP16
NALU_MTAP24
NALU_FUA // 28
NALU_FUB
// 24 - 31 NALU_NotReserved
)
var (
NALU_AUD_BYTE = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xF0}
NALU_Delimiter1 = []byte{0x00, 0x00, 0x01}
NALU_Delimiter2 = []byte{0x00, 0x00, 0x00, 0x01}
// 0x17 keyframe 7:AVC
// 0x00 AVC sequence header
// 0x00 0x00 0x00
// 0x01 configurationVersion
// 0x42 AVCProfileIndication
// 0x00 profile_compatibility
// 0x1E AVCLevelIndication
// 0xFF lengthSizeMinusOne
RTMP_AVC_HEAD = []byte{0x17, 0x00, 0x00, 0x00, 0x00, 0x01, 0x42, 0x00, 0x1E, 0xFF}
RTMP_KEYFRAME_HEAD = []byte{0x17, 0x01, 0x00, 0x00, 0x00}
RTMP_NORMALFRAME_HEAD = []byte{0x27, 0x01, 0x00, 0x00, 0x00}
)
// H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)
// NAL - Network Abstract Layer
// raw byte sequence payload (RBSP) 原始字节序列载荷
// SplitH264 以0x00000001分割H264裸数据
func SplitH264(payload []byte) (nalus [][]byte) {
for _, v := range bytes.SplitN(payload, NALU_Delimiter2, -1) {
if len(v) == 0 {
continue
}
nalus = append(nalus, bytes.SplitN(v, NALU_Delimiter1, -1)...)
}
return
}
func BuildH264SeqHeaderFromSpsPps(sps, pps []byte) (seqHeader []byte) {
lenSPS, lenPPS := len(sps), len(pps)
seqHeader = append([]byte{}, RTMP_AVC_HEAD...)
if lenSPS > 3 {
copy(seqHeader[6:], sps[1:4])
}
seqHeader = append(seqHeader, 0xE1, byte(lenSPS>>8), byte(lenSPS))
seqHeader = append(seqHeader, sps...)
seqHeader = append(append(seqHeader, 0x01, byte(lenPPS>>8), byte(lenPPS)), pps...)
return
}
// ISO/IEC 14496-15 11(16)/page
//
// Advanced Video Coding
//
// AVCC
type AVCDecoderConfigurationRecord struct {
ConfigurationVersion byte // 8 bits Version
AVCProfileIndication byte // 8 bits
ProfileCompatibility byte // 8 bits
AVCLevelIndication byte // 8 bits
Reserved1 byte // 6 bits
LengthSizeMinusOne byte // 2 bits 非常重要,每个NALU包前面都(lengthSizeMinusOne & 3)+1个字节的NAL包长度描述
Reserved2 byte // 3 bits
NumOfSequenceParameterSets byte // 5 bits SPS 的个数,计算方法是 numOfSequenceParameterSets & 0x1F
NumOfPictureParameterSets byte // 8 bits PPS 的个数
SequenceParameterSetLength uint16 // 16 byte SPS Length
SequenceParameterSetNALUnit []byte // n byte SPS
PictureParameterSetLength uint16 // 16 byte PPS Length
PictureParameterSetNALUnit []byte // n byte PPS
}
func (p *AVCDecoderConfigurationRecord) Marshal(b []byte) (n int) {
b[0] = 1
b[1] = p.AVCProfileIndication
b[2] = p.ProfileCompatibility
b[3] = p.AVCLevelIndication
b[4] = p.LengthSizeMinusOne | 0xfc
b[5] = uint8(1) | 0xe0
n += 6
pio.PutU16BE(b[n:], p.SequenceParameterSetLength)
n += 2
copy(b[n:], p.SequenceParameterSetNALUnit)
n += len(p.SequenceParameterSetNALUnit)
b[n] = uint8(1)
n++
pio.PutU16BE(b[n:], p.PictureParameterSetLength)
n += 2
copy(b[n:], p.PictureParameterSetNALUnit)
n += len(p.PictureParameterSetNALUnit)
return
}
var ErrDecconfInvalid = errors.New("decode error")
func (p *AVCDecoderConfigurationRecord) Unmarshal(b []byte) (n int, err error) {
if len(b) < 7 {
err = errors.New("not enough len")
return
}
p.AVCProfileIndication = b[1]
p.ProfileCompatibility = b[2]
p.AVCLevelIndication = b[3]
p.LengthSizeMinusOne = b[4] & 0x03
spscount := int(b[5] & 0x1f)
n += 6
var sps, pps [][]byte
for i := 0; i < spscount; i++ {
if len(b) < n+2 {
err = ErrDecconfInvalid
return
}
spslen := util.ReadBE[int](b[n : n+2])
n += 2
if len(b) < n+spslen {
err = ErrDecconfInvalid
return
}
sps = append(sps, b[n:n+spslen])
n += spslen
}
p.SequenceParameterSetLength = uint16(len(sps[0]))
p.SequenceParameterSetNALUnit = sps[0]
if len(b) < n+1 {
err = ErrDecconfInvalid
return
}
ppscount := int(b[n])
n++
for i := 0; i < ppscount; i++ {
if len(b) < n+2 {
err = ErrDecconfInvalid
return
}
ppslen := util.ReadBE[int](b[n : n+2])
n += 2
if len(b) < n+ppslen {
err = ErrDecconfInvalid
return
}
pps = append(pps, b[n:n+ppslen])
n += ppslen
}
if ppscount >= 1 {
p.PictureParameterSetLength = uint16(len(pps[0]))
p.PictureParameterSetNALUnit = pps[0]
} else {
err = ErrDecconfInvalid
}
return
}
type NALUnit struct {
NALUHeader
RBSP
}
type NALUHeader struct {
forbidden_zero_bit byte // 1 bit 0
nal_ref_idc byte // 2 bits nal_unit_type等于6,9,10,11或12的NAL单元其nal_ref_idc都应等于 0
nal_uint_type byte // 5 bits 包含在 NAL 单元中的 RBSP 数据结构的类型
}
type RBSP interface {
}
/*
0 Unspecified non-VCL
1 Coded slice of a non-IDR picture VCL
2 Coded slice data partition A VCL
3 Coded slice data partition B VCL
4 Coded slice data partition C VCL
5 Coded slice of an IDR picture VCL
6 Supplemental enhancement information (SEI) non-VCL
7 Sequence parameter set non-VCL
8 Picture parameter set non-VCL
9 Access unit delimiter non-VCL
10 End of sequence non-VCL
11 End of stream non-VCL
12 Filler data non-VCL
13 Sequence parameter set extension non-VCL
14 Prefix NAL unit non-VCL
15 Subset sequence parameter set non-VCL
16 Depth parameter set non-VCL
17..18 Reserved non-VCL
19 Coded slice of an auxiliary coded picture without partitioning non-VCL
20 Coded slice extension non-VCL
21 Coded slice extension for depth view components non-VCL
22..23 Reserved non-VCL
24..31 Unspecified non-VCL
0:未规定
1:非IDR图像中不采用数据划分的片段
2:非IDR图像中A类数据划分片段
3:非IDR图像中B类数据划分片段
4:非IDR图像中C类数据划分片段
5:IDR图像的片段
6:补充增强信息SEI
7:序列参数集SPS
8:图像参数集PPS
9:分割符
10:序列结束符
11:流结束符
12:填充数据
13:序列参数集扩展
14:带前缀的NAL单元
15:子序列参数集
16 18:保留
19:不采用数据划分的辅助编码图像片段
20:编码片段扩展
21 23:保留
24 31:未规定
nal_unit_type NAL类型 nal_reference_bit
0 未使用 0
1 非IDR的片 此片属于参考帧,则不等于0,不属于参考帧则等与0
2 片数据A分区 同上
3 片数据B分区 同上
4 片数据C分区 同上
5 IDR图像的片 5
6 补充增强信息单元SEI 0
7 序列参数集 非0
8 图像参数集 非0
9 分界符 0
10 序列结束 0
11 码流结束 0
12 填充 0
13..23 保留 0
24..31 不保留 0
*/
func ReadPPS(w io.Writer) {
}