Files
engine/go2/video_track.go2
langhuihui c2ff0bbcae 大改版
2021-02-14 22:56:17 +08:00

142 lines
3.6 KiB
Plaintext
Raw 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 engine
import (
"context"
"encoding/binary"
utils "github.com/Monibuca/utils/v3"
"github.com/Monibuca/utils/v3/codec"
)
const (
fuaHeaderSize = 2
stapaHeaderSize = 1
stapaNALULengthSize = 2
naluTypeBitmask = 0x1F
naluRefIdcBitmask = 0x60
fuaStartBitmask = 0x80 //1000 0000
fuaEndBitmask = 0x40 //0100 0000
)
type VideoPack struct {
Timestamp uint
Payload []byte //NALU
NalType int
SequenceNumber uint16
}
type VideoTrack struct {
FirstScreen byte //最近的关键帧位置,首屏渲染
Track[VideoPack]
SPS []byte
PPS []byte
SPSInfo codec.SPSInfo
GOP int //关键帧间隔
RtmpTag []byte //rtmp需要先发送一个序列帧包含SPS和PPS
WaitIDR chan struct{} //等待首个关键帧
}
// Push 来自发布者推送的视频
func (vt *VideoTrack) Push(timestamp uint32, payload []byte) {
payloadLen := len(payload)
if payloadLen == 0 {
return
}
vbr:=vt.Buffer
video := vbr.Current
video.NalType = payload[0] & naluTypeBitmask
video.Timestamp = timestamp
video.SequenceNumber = vt.PacketCount
switch video.NalType {
case codec.NALU_STAPA:
for currOffset, naluSize := stapaHeaderSize, 0; currOffset < len(payload); currOffset += naluSize {
naluSize = int(binary.BigEndian.Uint16(payload[currOffset:]))
currOffset += stapaNALULengthSize
if currOffset+len(payload) < currOffset+naluSize {
utils.Printf("STAP-A declared size(%d) is larger then buffer(%d)", naluSize, len(payload)-currOffset)
return
}
vt.Push(timestamp, payload[currOffset:currOffset+naluSize])
}
case codec.NALU_FUA:
if len(payload) < fuaHeaderSize {
utils.Printf("Payload is not large enough to be FU-A")
return
}
if payload[1]&fuaStartBitmask != 0 {
naluRefIdc := payload[0] & naluRefIdcBitmask
fragmentedNaluType := payload[1] & naluTypeBitmask
video.Payload = append([]byte{}, payload...)
video.Payload[fuaHeaderSize-1] = naluRefIdc | fragmentedNaluType
} else {
video.Payload = append(video.Payload, payload[fuaHeaderSize:]...)
}
if payload[1]&fuaEndBitmask != 0 {
vt.Push(timestamp, video.Payload[fuaHeaderSize-1:])
}
case codec.NALU_SPS:
vt.SPS = payload
vt.SPSInfo,_ = codec.ParseSPS(payload)
case codec.NALU_PPS:
vt.PPS = payload
case codec.NALU_Access_Unit_Delimiter:
case codec.NALU_IDR_Picture:
if vt.RtmpTag == nil {
vt.setRtmpTag()
defer close(vt.WaitIDR)
} else {
vt.GOP = vbr.Index - vbr.GetAt(vt.FirstScreen).SequenceNumber
}
vt.FirstScreen = vbr.Index
fallthrough
case codec.NALU_Non_IDR_Picture:
video.Payload = payload
vt.Track.GetBPS(payloadLen)
vbr.NextW()
case codec.NALU_SEI:
default:
utils.Printf("nalType not support yet:%d", video.NalType)
}
}
func(vt *VideoTrack) setRtmpTag(){
lenSPS,lenPPS:= len(vt.SPS), len(vt.PPS)
vt.RtmpTag = append([]byte{}, codec.RTMP_AVC_HEAD...)
copy(vt.RtmpTag[6:], vt.SPS[1:4])
vt.RtmpTag = append(vt.RtmpTag, 0xE1, byte(lenSPS>>8), byte(lenSPS))
vt.RtmpTag = append(vt.RtmpTag,vt.SPS...)
vt.RtmpTag = append(append(vt.RtmpTag, 0x01, byte(lenPPS>>8), byte(lenPPS)), vt.PPS...)
}
func (vt *VideoTrack) Play(ctx context.Context,callback func(VideoPack)) {
ring :=vt.Buffer.SubRing(vt.FirstScreen)
ring.Current.Wait()
droped:=0
var action,send func()
drop := func(){
if ring.Current.NalType == codec.NALU_IDR_Picture {
action = send
} else {
droped++
}
}
send = func(){
callback(ring.Current.T)
pIndex := vt.Buffer.Index
//s.BufferLength = pIndex - ring.Index
//s.Delay = s.AVRing.Timestamp - packet.Timestamp
if pIndex - ring.Index > 128 {
action = drop
}
}
for action =send;;ring.NextR() {
select {
case <-ctx.Done():
return
default:
action()
}
}
}