work HEVC in progress next v3
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/deepch/vdk/codec"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/codec/h265parser"
|
||||
"github.com/deepch/vdk/format/rtsp/sdp"
|
||||
)
|
||||
|
||||
@@ -72,12 +73,14 @@ type RTSPClient struct {
|
||||
fuStarted bool
|
||||
options RTSPClientOptions
|
||||
BufferRtpPacket *bytes.Buffer
|
||||
vps []byte
|
||||
sps []byte
|
||||
pps []byte
|
||||
CodecData []av.CodecData
|
||||
AudioTimeLine time.Duration
|
||||
AudioTimeScale int64
|
||||
audioCodec av.CodecType
|
||||
videoCodec av.CodecType
|
||||
PreAudioTS int64
|
||||
PreVideoTS int64
|
||||
PreSequenceNumber int
|
||||
@@ -145,6 +148,16 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) {
|
||||
client.pps = i2.SpropParameterSets[1]
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
client.videoIDX = int8(len(client.CodecData) - 1)
|
||||
client.videoCodec = av.H264
|
||||
}
|
||||
} else if i2.Type == av.H265 && len(i2.SpropVPS) > 1 && len(i2.SpropSPS) > 1 && len(i2.SpropPPS) > 1 {
|
||||
if codecData, err := h265parser.NewCodecDataFromVPSAndSPSAndPPS(i2.SpropVPS, i2.SpropSPS, i2.SpropPPS); err == nil {
|
||||
client.vps = i2.SpropVPS
|
||||
client.sps = i2.SpropSPS
|
||||
client.pps = i2.SpropPPS
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
client.videoIDX = int8(len(client.CodecData) - 1)
|
||||
client.videoCodec = av.H265
|
||||
}
|
||||
} else {
|
||||
client.Println("SDP Video Codec Type Not Supported", i2.Type)
|
||||
@@ -531,70 +544,119 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) {
|
||||
nalRaw, _ := h264parser.SplitNALUs(content[offset:end])
|
||||
var retmap []*av.Packet
|
||||
for _, nal := range nalRaw {
|
||||
naluType := nal[0] & 0x1f
|
||||
switch {
|
||||
case naluType >= 1 && naluType <= 5:
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(len(nal)), nal...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluType == 5,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
case naluType == 7:
|
||||
client.CodecUpdateSPS(nal)
|
||||
case naluType == 8:
|
||||
client.CodecUpdatePPS(nal)
|
||||
case naluType == 24:
|
||||
client.Println("24 Type need add next version report https://github.com/deepch/vdk")
|
||||
case naluType == 28:
|
||||
fuIndicator := content[offset]
|
||||
fuHeader := content[offset+1]
|
||||
isStart := fuHeader&0x80 != 0
|
||||
isEnd := fuHeader&0x40 != 0
|
||||
if isStart {
|
||||
client.fuStarted = true
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write([]byte{fuIndicator&0xe0 | fuHeader&0x1f})
|
||||
}
|
||||
if client.fuStarted {
|
||||
client.BufferRtpPacket.Write(content[offset+2 : end])
|
||||
if isEnd {
|
||||
client.fuStarted = false
|
||||
naluTypef := client.BufferRtpPacket.Bytes()[0] & 0x1f
|
||||
if naluTypef == 7 {
|
||||
bufered, _ := h264parser.SplitNALUs(append([]byte{0, 0, 0, 1}, client.BufferRtpPacket.Bytes()...))
|
||||
for _, v := range bufered {
|
||||
naluTypefs := v[0] & 0x1f
|
||||
switch {
|
||||
case naluTypefs == 5:
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write(v)
|
||||
naluTypef = 5
|
||||
case naluTypefs == 7:
|
||||
client.CodecUpdateSPS(v)
|
||||
case naluTypefs == 8:
|
||||
client.CodecUpdatePPS(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
if client.videoCodec == av.H265 {
|
||||
naluType := (nal[0] >> 1) & 0x3f
|
||||
switch naluType {
|
||||
case h265parser.NAL_UNIT_CODED_SLICE_TRAIL_R:
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(len(nal)), nal...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
case h265parser.NAL_UNIT_VPS:
|
||||
client.CodecUpdateVPS(nal)
|
||||
case h265parser.NAL_UNIT_SPS:
|
||||
client.CodecUpdateSPS(nal)
|
||||
case h265parser.NAL_UNIT_PPS:
|
||||
client.CodecUpdatePPS(nal)
|
||||
case h265parser.NAL_UNIT_UNSPECIFIED_49:
|
||||
se := nal[2] >> 6
|
||||
naluType = nal[2] & 0x3f
|
||||
if se == 2 {
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write([]byte{0, 0, 0, 0, (nal[0] & 0x81) | (naluType << 1), nal[1]})
|
||||
r := make([]byte, 2)
|
||||
r[1] = nal[1]
|
||||
r[0] = (nal[0] & 0x81) | (naluType << 1)
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
} else if se == 1 {
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
binary.BigEndian.PutUint32(client.BufferRtpPacket.Bytes()[:4], uint32(client.BufferRtpPacket.Len())-4)
|
||||
buf := make([]byte, client.BufferRtpPacket.Len())
|
||||
copy(buf, client.BufferRtpPacket.Bytes())
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...),
|
||||
Data: append(binSize(len(nal)), nal...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluTypef == 5,
|
||||
IsKeyFrame: naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
} else {
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
}
|
||||
default:
|
||||
//log.Println("???", naluType)
|
||||
}
|
||||
} else if client.videoCodec == av.H264 {
|
||||
naluType := nal[0] & 0x1f
|
||||
switch {
|
||||
case naluType >= 1 && naluType <= 5:
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(len(nal)), nal...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluType == 5,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
case naluType == 7:
|
||||
client.CodecUpdateSPS(nal)
|
||||
case naluType == 8:
|
||||
client.CodecUpdatePPS(nal)
|
||||
case naluType == 24:
|
||||
client.Println("24 Type need add next version report https://github.com/deepch/vdk")
|
||||
case naluType == 28:
|
||||
fuIndicator := content[offset]
|
||||
fuHeader := content[offset+1]
|
||||
isStart := fuHeader&0x80 != 0
|
||||
isEnd := fuHeader&0x40 != 0
|
||||
if isStart {
|
||||
client.fuStarted = true
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write([]byte{fuIndicator&0xe0 | fuHeader&0x1f})
|
||||
}
|
||||
if client.fuStarted {
|
||||
client.BufferRtpPacket.Write(content[offset+2 : end])
|
||||
if isEnd {
|
||||
client.fuStarted = false
|
||||
naluTypef := client.BufferRtpPacket.Bytes()[0] & 0x1f
|
||||
if naluTypef == 7 {
|
||||
bufered, _ := h264parser.SplitNALUs(append([]byte{0, 0, 0, 1}, client.BufferRtpPacket.Bytes()...))
|
||||
for _, v := range bufered {
|
||||
naluTypefs := v[0] & 0x1f
|
||||
switch {
|
||||
case naluTypefs == 5:
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write(v)
|
||||
naluTypef = 5
|
||||
case naluTypefs == 7:
|
||||
client.CodecUpdateSPS(v)
|
||||
case naluTypefs == 8:
|
||||
client.CodecUpdatePPS(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluTypef == 5,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
}
|
||||
}
|
||||
default:
|
||||
client.Println("Unsupported NAL Type", naluType)
|
||||
}
|
||||
default:
|
||||
client.Println("Unsupported NAL Type", naluType)
|
||||
}
|
||||
}
|
||||
|
||||
if len(retmap) > 0 {
|
||||
client.PreVideoTS = timestamp
|
||||
return retmap, true
|
||||
@@ -680,49 +742,109 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) {
|
||||
}
|
||||
|
||||
func (client *RTSPClient) CodecUpdateSPS(val []byte) {
|
||||
if bytes.Compare(val, client.sps) != 0 {
|
||||
if len(client.sps) > 0 && len(client.pps) > 0 {
|
||||
codecData, err := h264parser.NewCodecDataFromSPSAndPPS(val, client.pps)
|
||||
if err != nil {
|
||||
client.Println("Parse Codec Data Error", err)
|
||||
return
|
||||
}
|
||||
if len(client.CodecData) > 0 {
|
||||
for i, i2 := range client.CodecData {
|
||||
if i2.Type().IsVideo() {
|
||||
client.CodecData[i] = codecData
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
if client.videoCodec != av.H264 && client.videoCodec != av.H265 {
|
||||
return
|
||||
}
|
||||
if bytes.Compare(val, client.sps) == 0 {
|
||||
return
|
||||
}
|
||||
client.sps = val
|
||||
if (client.videoCodec == av.H264 && len(client.pps) == 0) || (client.videoCodec == av.H265 && (len(client.vps) == 0 || len(client.pps) == 0)) {
|
||||
return
|
||||
}
|
||||
var codecData av.VideoCodecData
|
||||
var err error
|
||||
switch client.videoCodec {
|
||||
case av.H264:
|
||||
codecData, err = h264parser.NewCodecDataFromSPSAndPPS(val, client.pps)
|
||||
if err != nil {
|
||||
client.Println("Parse Codec Data Error", err)
|
||||
return
|
||||
}
|
||||
case av.H265:
|
||||
codecData, err = h265parser.NewCodecDataFromVPSAndSPSAndPPS(client.vps, val, client.pps)
|
||||
if err != nil {
|
||||
client.Println("Parse Codec Data Error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(client.CodecData) > 0 {
|
||||
for i, i2 := range client.CodecData {
|
||||
if i2.Type().IsVideo() {
|
||||
client.CodecData[i] = codecData
|
||||
}
|
||||
}
|
||||
client.Signals <- SignalCodecUpdate
|
||||
client.sps = val
|
||||
} else {
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
}
|
||||
client.Signals <- SignalCodecUpdate
|
||||
}
|
||||
|
||||
func (client *RTSPClient) CodecUpdatePPS(val []byte) {
|
||||
if bytes.Compare(val, client.pps) != 0 {
|
||||
if len(client.sps) > 0 && len(client.pps) > 0 {
|
||||
codecData, err := h264parser.NewCodecDataFromSPSAndPPS(client.sps, val)
|
||||
if err != nil {
|
||||
client.Println("Parse Codec Data Error", err)
|
||||
return
|
||||
}
|
||||
if len(client.CodecData) > 0 {
|
||||
for i, i2 := range client.CodecData {
|
||||
if i2.Type().IsVideo() {
|
||||
client.CodecData[i] = codecData
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
if client.videoCodec != av.H264 && client.videoCodec != av.H265 {
|
||||
return
|
||||
}
|
||||
if bytes.Compare(val, client.pps) == 0 {
|
||||
return
|
||||
}
|
||||
client.pps = val
|
||||
if (client.videoCodec == av.H264 && len(client.sps) == 0) || (client.videoCodec == av.H265 && (len(client.vps) == 0 || len(client.sps) == 0)) {
|
||||
return
|
||||
}
|
||||
var codecData av.VideoCodecData
|
||||
var err error
|
||||
switch client.videoCodec {
|
||||
case av.H264:
|
||||
codecData, err = h264parser.NewCodecDataFromSPSAndPPS(client.sps, val)
|
||||
if err != nil {
|
||||
client.Println("Parse Codec Data Error", err)
|
||||
return
|
||||
}
|
||||
case av.H265:
|
||||
codecData, err = h265parser.NewCodecDataFromVPSAndSPSAndPPS(client.vps, client.sps, val)
|
||||
if err != nil {
|
||||
client.Println("Parse Codec Data Error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(client.CodecData) > 0 {
|
||||
for i, i2 := range client.CodecData {
|
||||
if i2.Type().IsVideo() {
|
||||
client.CodecData[i] = codecData
|
||||
}
|
||||
}
|
||||
client.Signals <- SignalCodecUpdate
|
||||
client.pps = val
|
||||
} else {
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
}
|
||||
client.Signals <- SignalCodecUpdate
|
||||
}
|
||||
|
||||
func (client *RTSPClient) CodecUpdateVPS(val []byte) {
|
||||
if client.videoCodec != av.H265 {
|
||||
return
|
||||
}
|
||||
if bytes.Compare(val, client.vps) == 0 {
|
||||
return
|
||||
}
|
||||
client.vps = val
|
||||
if len(client.sps) == 0 || len(client.pps) == 0 {
|
||||
return
|
||||
}
|
||||
codecData, err := h265parser.NewCodecDataFromVPSAndSPSAndPPS(val, client.sps, client.pps)
|
||||
if err != nil {
|
||||
client.Println("Parse Codec Data Error", err)
|
||||
return
|
||||
}
|
||||
if len(client.CodecData) > 0 {
|
||||
for i, i2 := range client.CodecData {
|
||||
if i2.Type().IsVideo() {
|
||||
client.CodecData[i] = codecData
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
}
|
||||
client.Signals <- SignalCodecUpdate
|
||||
}
|
||||
|
||||
//Println mini logging functions
|
||||
|
||||
Reference in New Issue
Block a user