Skip to content

Commit ed9d620

Browse files
committed
新增WriteSPS、WritePPS函数,新增NALU发布者定义
1 parent 8a508e6 commit ed9d620

3 files changed

Lines changed: 164 additions & 24 deletions

File tree

avformat/h264.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,24 @@ const (
3939
NALU_Reserved3 = 21
4040
NALU_Reserved4 = 22
4141
NALU_Reserved5 = 23
42-
NALU_NotReserved = 24
42+
NALU_STAPA = 24
43+
NALU_FUA = 28
4344
// 24 - 31 NALU_NotReserved
45+
4446
)
4547

4648
var (
47-
NALU_AUD_BYTE = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xF0}
48-
NALU_Delimiter1 = []byte{0x00, 0x00, 0x01}
49-
NALU_Delimiter2 = []byte{0x00, 0x00, 0x00, 0x01}
49+
NALU_AUD_BYTE = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xF0}
50+
NALU_Delimiter1 = []byte{0x00, 0x00, 0x01}
51+
NALU_Delimiter2 = []byte{0x00, 0x00, 0x00, 0x01}
52+
// 0x17 keyframe 7:AVC
53+
// 0x00 AVC sequence header
54+
// 0x00 0x00 0x00
55+
// 0x01 configurationVersion
56+
// 0x42 AVCProfileIndication
57+
// 0x00 profile_compatibility
58+
// 0x1E AVCLevelIndication
59+
// 0xFF lengthSizeMinusOne
5060
RTMP_AVC_HEAD = []byte{0x17, 0x00, 0x00, 0x00, 0x00, 0x01, 0x42, 0x00, 0x1E, 0xFF}
5161
RTMP_KEYFRAME_HEAD = []byte{0x17, 0x01, 0x00, 0x00, 0x00}
5262
RTMP_NORMALFRAME_HEAD = []byte{0x27, 0x01, 0x00, 0x00, 0x00}

nalu.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package engine
2+
3+
import (
4+
"bytes"
5+
"encoding/binary"
6+
. "github.com/Monibuca/engine/v2/avformat"
7+
"github.com/Monibuca/engine/v2/pool"
8+
"github.com/Monibuca/engine/v2/util"
9+
)
10+
11+
const (
12+
fuaHeaderSize = 2
13+
stapaHeaderSize = 1
14+
stapaNALULengthSize = 2
15+
16+
naluTypeBitmask = 0x1F
17+
naluRefIdcBitmask = 0x60
18+
fuaStartBitmask = 0x80
19+
fuaEndBitmask = 0x40
20+
)
21+
22+
type NALU struct {
23+
Publisher
24+
fuBuffer []byte //用于fua的解析暂存的缓存
25+
}
26+
27+
func (r *NALU) WriteNALU(ts uint32, payload []byte) {
28+
nalType := payload[0] & naluTypeBitmask
29+
buffer := r.AVRing.Buffer
30+
if buffer == nil {
31+
buffer = bytes.NewBuffer([]byte{})
32+
r.AVRing.Buffer = buffer
33+
}
34+
switch nalType {
35+
case NALU_STAPA:
36+
for currOffset, naluSize := stapaHeaderSize, 0; currOffset < len(payload); currOffset += naluSize {
37+
naluSize = int(binary.BigEndian.Uint16(payload[currOffset:]))
38+
currOffset += stapaNALULengthSize
39+
if currOffset+len(payload) < currOffset+naluSize {
40+
Printf("STAP-A declared size(%d) is larger then buffer(%d)", naluSize, len(payload)-currOffset)
41+
return
42+
}
43+
r.WriteNALU(ts, payload[currOffset:currOffset+naluSize])
44+
}
45+
case NALU_FUA:
46+
if len(payload) < fuaHeaderSize {
47+
Printf("Payload is not large enough to be FU-A")
48+
return
49+
}
50+
if payload[1]&fuaStartBitmask != 0 {
51+
naluRefIdc := payload[0] & naluRefIdcBitmask
52+
fragmentedNaluType := payload[1] & naluTypeBitmask
53+
r.fuBuffer = append([]byte{}, payload...)
54+
r.fuBuffer[fuaHeaderSize-1] = naluRefIdc | fragmentedNaluType
55+
} else {
56+
r.fuBuffer = append(r.fuBuffer, payload[fuaHeaderSize:]...)
57+
}
58+
if payload[1]&fuaEndBitmask != 0 {
59+
r.WriteNALU(ts, r.fuBuffer[fuaHeaderSize-1:])
60+
}
61+
case NALU_SPS:
62+
r.WriteSPS(payload)
63+
case NALU_PPS:
64+
r.WritePPS(payload)
65+
case NALU_Access_Unit_Delimiter:
66+
r.PushVideo(ts, r.AVRing.Bytes())
67+
r.GetBuffer()
68+
case NALU_IDR_Picture:
69+
if r.VideoTag == nil {
70+
break
71+
}
72+
if buffer.Len() == 0 {
73+
buffer.Write(RTMP_KEYFRAME_HEAD)
74+
}
75+
nl := pool.GetSlice(4)
76+
util.BigEndian.PutUint32(nl, uint32(len(payload)))
77+
buffer.Write(nl)
78+
pool.RecycleSlice(nl)
79+
buffer.Write(payload)
80+
case NALU_Non_IDR_Picture:
81+
if r.VideoTag == nil {
82+
break
83+
}
84+
if buffer.Len() == 0 {
85+
buffer.Write(RTMP_NORMALFRAME_HEAD)
86+
}
87+
nl := pool.GetSlice(4)
88+
util.BigEndian.PutUint32(nl, uint32(len(payload)))
89+
buffer.Write(nl)
90+
pool.RecycleSlice(nl)
91+
buffer.Write(payload)
92+
default:
93+
Printf("nalType not support yet:%d", nalType)
94+
}
95+
}

stream.go

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ import (
77
"sync"
88
"time"
99

10-
"github.com/Monibuca/engine/v2/avformat"
10+
. "github.com/Monibuca/engine/v2/avformat"
1111
. "github.com/logrusorgru/aurora"
1212
)
1313

14-
var (
15-
streamCollection = Collection{}
16-
)
14+
var streamCollection Collection
1715

1816
// Collection 对sync.Map的包装
1917
type Collection struct {
@@ -58,8 +56,8 @@ type Stream struct {
5856
Control chan interface{}
5957
Cancel context.CancelFunc
6058
Subscribers map[string]*Subscriber // 订阅者
61-
VideoTag *avformat.AVPacket // 每个视频包都是这样的结构,区别在于Payload的大小.FMS在发送AVC sequence header,需要加上 VideoTags,这个tag 1个字节(8bits)的数据
62-
AudioTag *avformat.AVPacket // 每个音频包都是这样的结构,区别在于Payload的大小.FMS在发送AAC sequence header,需要加上 AudioTags,这个tag 1个字节(8bits)的数据
59+
VideoTag *AVPacket // 每个视频包都是这样的结构,区别在于Payload的大小.FMS在发送AVC sequence header,需要加上 VideoTags,这个tag 1个字节(8bits)的数据
60+
AudioTag *AVPacket // 每个音频包都是这样的结构,区别在于Payload的大小.FMS在发送AAC sequence header,需要加上 AudioTags,这个tag 1个字节(8bits)的数据
6361
FirstScreen *Ring //最近的关键帧位置,首屏渲染
6462
AVRing *Ring //数据环
6563
WaitingMutex *sync.RWMutex //用于订阅和等待发布者
@@ -75,7 +73,7 @@ type StreamInfo struct {
7573
VideoInfo struct {
7674
PacketCount int
7775
CodecID byte
78-
SPSInfo avformat.SPSInfo
76+
SPSInfo SPSInfo
7977
BPS int
8078
lastIndex int
8179
GOP int //关键帧间隔
@@ -187,12 +185,34 @@ func (r *Stream) Run() {
187185
func (r *Stream) GetBuffer() *bytes.Buffer {
188186
return r.AVRing.GetBuffer()
189187
}
188+
func (r *Stream) WriteASC(asc []byte) {
189+
if r.AudioTag == nil {
190+
r.AudioTag = NewAVPacket(FLV_TAG_TYPE_AUDIO)
191+
r.AudioTag.IsSequence = true
192+
r.AudioTag.Payload = append(append(r.AudioTag.Payload, 0xAF, 0), asc...)
193+
} else {
194+
r.AudioTag.Payload = append(r.AudioTag.Payload[:2], asc...)
195+
}
196+
config1 := asc[2]
197+
config2 := asc[3]
198+
r.AudioInfo.SoundFormat = 10
199+
//audioObjectType = (config1 & 0xF8) >> 3
200+
// 1 AAC MAIN ISO/IEC 14496-3 subpart 4
201+
// 2 AAC LC ISO/IEC 14496-3 subpart 4
202+
// 3 AAC SSR ISO/IEC 14496-3 subpart 4
203+
// 4 AAC LTP ISO/IEC 14496-3 subpart 4
204+
r.AudioInfo.SoundRate = SamplingFrequencies[((config1&0x7)<<1)|(config2>>7)]
205+
r.AudioInfo.SoundType = (config2 >> 3) & 0x0F //声道
206+
//frameLengthFlag = (config2 >> 2) & 0x01
207+
//dependsOnCoreCoder = (config2 >> 1) & 0x01
208+
//extensionFlag = config2 & 0x01
209+
}
190210

191211
// PushAudio 来自发布者推送的音频
192212
func (r *Stream) PushAudio(timestamp uint32, payload []byte) {
193213
audio := r.AVRing
194214
payloadLen := len(payload)
195-
audio.Type = avformat.FLV_TAG_TYPE_AUDIO
215+
audio.Type = FLV_TAG_TYPE_AUDIO
196216
audio.Timestamp = timestamp
197217
audio.Payload = payload
198218
audio.IsKeyFrame = false
@@ -204,7 +224,7 @@ func (r *Stream) PushAudio(timestamp uint32, payload []byte) {
204224
if payload[0] == 0xFF && (payload[1]&0xF0) == 0xF0 {
205225
//将ADTS转换成ASC
206226
r.AudioInfo.SoundFormat = 10
207-
r.AudioInfo.SoundRate = avformat.SamplingFrequencies[(payload[2]&0x3c)>>2]
227+
r.AudioInfo.SoundRate = SamplingFrequencies[(payload[2]&0x3c)>>2]
208228
r.AudioInfo.SoundType = ((payload[2] & 0x1) << 2) | ((payload[3] & 0xc0) >> 6)
209229
r.AudioTag = audio.ADTS2ASC()
210230
} else if r.AudioTag == nil {
@@ -224,16 +244,16 @@ func (r *Stream) PushAudio(timestamp uint32, payload []byte) {
224244
// 2 AAC LC ISO/IEC 14496-3 subpart 4
225245
// 3 AAC SSR ISO/IEC 14496-3 subpart 4
226246
// 4 AAC LTP ISO/IEC 14496-3 subpart 4
227-
r.AudioInfo.SoundRate = avformat.SamplingFrequencies[((config1&0x7)<<1)|(config2>>7)]
247+
r.AudioInfo.SoundRate = SamplingFrequencies[((config1&0x7)<<1)|(config2>>7)]
228248
r.AudioInfo.SoundType = (config2 >> 3) & 0x0F //声道
229249
//frameLengthFlag = (config2 >> 2) & 0x01
230250
//dependsOnCoreCoder = (config2 >> 1) & 0x01
231251
//extensionFlag = config2 & 0x01
232252
}
233253
} else {
234-
r.AudioInfo.SoundRate = avformat.SoundRate[(tmp&0x0c)>>2] // 采样率 0 = 5.5 kHz or 1 = 11 kHz or 2 = 22 kHz or 3 = 44 kHz
235-
r.AudioInfo.SoundSize = (tmp & 0x02) >> 1 // 采样精度 0 = 8-bit samples or 1 = 16-bit samples
236-
r.AudioInfo.SoundType = tmp & 0x01 // 0 单声道,1立体声
254+
r.AudioInfo.SoundRate = SoundRate[(tmp&0x0c)>>2] // 采样率 0 = 5.5 kHz or 1 = 11 kHz or 2 = 22 kHz or 3 = 44 kHz
255+
r.AudioInfo.SoundSize = (tmp & 0x02) >> 1 // 采样精度 0 = 8-bit samples or 1 = 16-bit samples
256+
r.AudioInfo.SoundType = tmp & 0x01 // 0 单声道,1立体声
237257
}
238258
return
239259
}
@@ -254,24 +274,39 @@ func (r *Stream) setH264Info(video *Ring) {
254274
if r.VideoInfo.CodecID != 7 {
255275
return
256276
}
257-
info := avformat.AVCDecoderConfigurationRecord{}
277+
var info AVCDecoderConfigurationRecord
258278
//0:codec,1:IsAVCSequence,2~4:compositionTime
259279
if _, err := info.Unmarshal(video.Payload[5:]); err == nil {
260-
r.VideoInfo.SPSInfo, err = avformat.ParseSPS(info.SequenceParameterSetNALUnit)
280+
r.VideoInfo.SPSInfo, err = ParseSPS(info.SequenceParameterSetNALUnit)
261281
}
262282
}
283+
func (r *Stream) WriteSPS(sps []byte) {
284+
lenSPS := len(sps)
285+
if r.VideoTag == nil {
286+
r.VideoTag = NewAVPacket(FLV_TAG_TYPE_VIDEO)
287+
r.VideoTag.IsSequence = true
288+
r.VideoTag.IsKeyFrame = true
289+
r.VideoTag.Payload = append(r.VideoTag.Payload, RTMP_AVC_HEAD...)
290+
}
291+
r.VideoInfo.SPSInfo, _ = ParseSPS(sps)
292+
copy(r.VideoTag.Payload[6:], sps[1:4])
293+
r.VideoTag.Payload = append(append(r.VideoTag.Payload[:10], 0xE1, byte(lenSPS>>8), byte(lenSPS)), sps...)
294+
}
295+
func (r *Stream) WritePPS(pps []byte) {
296+
lenPPS := len(pps)
297+
r.VideoTag.Payload = append(append(r.VideoTag.Payload, 0x01, byte(lenPPS>>8), byte(lenPPS)), pps...)
298+
}
263299

264300
// PushVideo 来自发布者推送的视频
265301
func (r *Stream) PushVideo(timestamp uint32, payload []byte) {
266-
video := r.AVRing
267302
payloadLen := len(payload)
268-
video.Type = avformat.FLV_TAG_TYPE_VIDEO
269-
video.Timestamp = timestamp
270-
video.Payload = payload
271-
272303
if payloadLen < 3 {
273304
return
274305
}
306+
video := r.AVRing
307+
video.Type = FLV_TAG_TYPE_VIDEO
308+
video.Timestamp = timestamp
309+
video.Payload = payload
275310
videoFrameType := payload[0] >> 4 // 帧类型 4Bit, H264一般为1或者2
276311
r.VideoInfo.CodecID = payload[0] & 0x0f // 编码类型ID 4Bit, JPEG, H263, AVC...
277312
video.IsSequence = videoFrameType == 1 && payload[1] == 0

0 commit comments

Comments
 (0)