68 lines
1.6 KiB
Go
68 lines
1.6 KiB
Go
package rdpgfx
|
|
|
|
import "bytes"
|
|
|
|
// ScanResult holds the IDR-presence flag and SPS/PPS NAL boundaries (offsets
|
|
// into the original packet, including Annex B start code) discovered during a
|
|
// single linear walk of an Annex B H.264 packet.
|
|
type ScanResult struct {
|
|
HasKeyFrame bool
|
|
SPSStart, SPSEnd int
|
|
PPSStart, PPSEnd int
|
|
}
|
|
|
|
// ScanH264Packet walks an Annex B H.264 packet exactly once, returning
|
|
// whether it contains any IDR slice (NAL type 5) or SPS (NAL type 7) NAL
|
|
// unit and recording the byte ranges for the most recent SPS/PPS NALs found.
|
|
func ScanH264Packet(data []byte) ScanResult {
|
|
var r ScanResult
|
|
startCode := []byte{0, 0, 1}
|
|
pos := 0
|
|
for pos < len(data) {
|
|
off := bytes.Index(data[pos:], startCode)
|
|
if off < 0 {
|
|
break
|
|
}
|
|
i := pos + off
|
|
scLen := 3
|
|
if i > 0 && data[i-1] == 0 {
|
|
i--
|
|
scLen = 4
|
|
}
|
|
if i+scLen >= len(data) {
|
|
break
|
|
}
|
|
nalType := data[i+scLen] & 0x1F
|
|
if nalType == 5 || nalType == 7 {
|
|
r.HasKeyFrame = true
|
|
}
|
|
if nalType == 7 || nalType == 8 {
|
|
searchFrom := i + scLen + 1
|
|
j := len(data)
|
|
if searchFrom < len(data) {
|
|
if next := bytes.Index(data[searchFrom:], startCode); next >= 0 {
|
|
j = searchFrom + next
|
|
if j > 0 && data[j-1] == 0 {
|
|
j--
|
|
}
|
|
}
|
|
}
|
|
if nalType == 7 {
|
|
r.SPSStart, r.SPSEnd = i, j
|
|
} else {
|
|
r.PPSStart, r.PPSEnd = i, j
|
|
}
|
|
pos = j
|
|
continue
|
|
}
|
|
pos = i + scLen + 1
|
|
}
|
|
return r
|
|
}
|
|
|
|
// h264PacketHasIDR reports whether an Annex B H.264 packet contains an IDR
|
|
// (keyframe) NAL unit.
|
|
func h264PacketHasIDR(data []byte) bool {
|
|
return ScanH264Packet(data).HasKeyFrame
|
|
}
|