Files

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
}