h264_packet.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package codecs
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. )
  6. // H264Payloader payloads H264 packets
  7. type H264Payloader struct {
  8. spsNalu, ppsNalu []byte
  9. }
  10. const (
  11. stapaNALUType = 24
  12. fuaNALUType = 28
  13. fubNALUType = 29
  14. spsNALUType = 7
  15. ppsNALUType = 8
  16. audNALUType = 9
  17. fillerNALUType = 12
  18. fuaHeaderSize = 2
  19. stapaHeaderSize = 1
  20. stapaNALULengthSize = 2
  21. naluTypeBitmask = 0x1F
  22. naluRefIdcBitmask = 0x60
  23. fuStartBitmask = 0x80
  24. fuEndBitmask = 0x40
  25. outputStapAHeader = 0x78
  26. )
  27. func annexbNALUStartCode() []byte { return []byte{0x00, 0x00, 0x00, 0x01} }
  28. func emitNalus(nals []byte, emit func([]byte)) {
  29. nextInd := func(nalu []byte, start int) (indStart int, indLen int) {
  30. zeroCount := 0
  31. for i, b := range nalu[start:] {
  32. if b == 0 {
  33. zeroCount++
  34. continue
  35. } else if b == 1 {
  36. if zeroCount >= 2 {
  37. return start + i - zeroCount, zeroCount + 1
  38. }
  39. }
  40. zeroCount = 0
  41. }
  42. return -1, -1
  43. }
  44. nextIndStart, nextIndLen := nextInd(nals, 0)
  45. if nextIndStart == -1 {
  46. emit(nals)
  47. } else {
  48. for nextIndStart != -1 {
  49. prevStart := nextIndStart + nextIndLen
  50. nextIndStart, nextIndLen = nextInd(nals, prevStart)
  51. if nextIndStart != -1 {
  52. emit(nals[prevStart:nextIndStart])
  53. } else {
  54. // Emit until end of stream, no end indicator found
  55. emit(nals[prevStart:])
  56. }
  57. }
  58. }
  59. }
  60. // Payload fragments a H264 packet across one or more byte arrays
  61. func (p *H264Payloader) Payload(mtu uint16, payload []byte) [][]byte {
  62. var payloads [][]byte
  63. if len(payload) == 0 {
  64. return payloads
  65. }
  66. emitNalus(payload, func(nalu []byte) {
  67. if len(nalu) == 0 {
  68. return
  69. }
  70. naluType := nalu[0] & naluTypeBitmask
  71. naluRefIdc := nalu[0] & naluRefIdcBitmask
  72. switch {
  73. case naluType == audNALUType || naluType == fillerNALUType:
  74. return
  75. case naluType == spsNALUType:
  76. p.spsNalu = nalu
  77. return
  78. case naluType == ppsNALUType:
  79. p.ppsNalu = nalu
  80. return
  81. case p.spsNalu != nil && p.ppsNalu != nil:
  82. // Pack current NALU with SPS and PPS as STAP-A
  83. spsLen := make([]byte, 2)
  84. binary.BigEndian.PutUint16(spsLen, uint16(len(p.spsNalu)))
  85. ppsLen := make([]byte, 2)
  86. binary.BigEndian.PutUint16(ppsLen, uint16(len(p.ppsNalu)))
  87. stapANalu := []byte{outputStapAHeader}
  88. stapANalu = append(stapANalu, spsLen...)
  89. stapANalu = append(stapANalu, p.spsNalu...)
  90. stapANalu = append(stapANalu, ppsLen...)
  91. stapANalu = append(stapANalu, p.ppsNalu...)
  92. if len(stapANalu) <= int(mtu) {
  93. out := make([]byte, len(stapANalu))
  94. copy(out, stapANalu)
  95. payloads = append(payloads, out)
  96. }
  97. p.spsNalu = nil
  98. p.ppsNalu = nil
  99. }
  100. // Single NALU
  101. if len(nalu) <= int(mtu) {
  102. out := make([]byte, len(nalu))
  103. copy(out, nalu)
  104. payloads = append(payloads, out)
  105. return
  106. }
  107. // FU-A
  108. maxFragmentSize := int(mtu) - fuaHeaderSize
  109. // The FU payload consists of fragments of the payload of the fragmented
  110. // NAL unit so that if the fragmentation unit payloads of consecutive
  111. // FUs are sequentially concatenated, the payload of the fragmented NAL
  112. // unit can be reconstructed. The NAL unit type octet of the fragmented
  113. // NAL unit is not included as such in the fragmentation unit payload,
  114. // but rather the information of the NAL unit type octet of the
  115. // fragmented NAL unit is conveyed in the F and NRI fields of the FU
  116. // indicator octet of the fragmentation unit and in the type field of
  117. // the FU header. An FU payload MAY have any number of octets and MAY
  118. // be empty.
  119. naluData := nalu
  120. // According to the RFC, the first octet is skipped due to redundant information
  121. naluDataIndex := 1
  122. naluDataLength := len(nalu) - naluDataIndex
  123. naluDataRemaining := naluDataLength
  124. if min(maxFragmentSize, naluDataRemaining) <= 0 {
  125. return
  126. }
  127. for naluDataRemaining > 0 {
  128. currentFragmentSize := min(maxFragmentSize, naluDataRemaining)
  129. out := make([]byte, fuaHeaderSize+currentFragmentSize)
  130. // +---------------+
  131. // |0|1|2|3|4|5|6|7|
  132. // +-+-+-+-+-+-+-+-+
  133. // |F|NRI| Type |
  134. // +---------------+
  135. out[0] = fuaNALUType
  136. out[0] |= naluRefIdc
  137. // +---------------+
  138. // |0|1|2|3|4|5|6|7|
  139. // +-+-+-+-+-+-+-+-+
  140. // |S|E|R| Type |
  141. // +---------------+
  142. out[1] = naluType
  143. if naluDataRemaining == naluDataLength {
  144. // Set start bit
  145. out[1] |= 1 << 7
  146. } else if naluDataRemaining-currentFragmentSize == 0 {
  147. // Set end bit
  148. out[1] |= 1 << 6
  149. }
  150. copy(out[fuaHeaderSize:], naluData[naluDataIndex:naluDataIndex+currentFragmentSize])
  151. payloads = append(payloads, out)
  152. naluDataRemaining -= currentFragmentSize
  153. naluDataIndex += currentFragmentSize
  154. }
  155. })
  156. return payloads
  157. }
  158. // H264Packet represents the H264 header that is stored in the payload of an RTP Packet
  159. type H264Packet struct {
  160. IsAVC bool
  161. fuaBuffer []byte
  162. videoDepacketizer
  163. }
  164. func (p *H264Packet) doPackaging(nalu []byte) []byte {
  165. if p.IsAVC {
  166. naluLength := make([]byte, 4)
  167. binary.BigEndian.PutUint32(naluLength, uint32(len(nalu)))
  168. return append(naluLength, nalu...)
  169. }
  170. return append(annexbNALUStartCode(), nalu...)
  171. }
  172. // IsDetectedFinalPacketInSequence returns true of the packet passed in has the
  173. // marker bit set indicated the end of a packet sequence
  174. func (p *H264Packet) IsDetectedFinalPacketInSequence(rtpPacketMarketBit bool) bool {
  175. return rtpPacketMarketBit
  176. }
  177. // Unmarshal parses the passed byte slice and stores the result in the H264Packet this method is called upon
  178. func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) {
  179. if payload == nil {
  180. return nil, errNilPacket
  181. } else if len(payload) <= 2 {
  182. return nil, fmt.Errorf("%w: %d <= 2", errShortPacket, len(payload))
  183. }
  184. // NALU Types
  185. // https://tools.ietf.org/html/rfc6184#section-5.4
  186. naluType := payload[0] & naluTypeBitmask
  187. switch {
  188. case naluType > 0 && naluType < 24:
  189. return p.doPackaging(payload), nil
  190. case naluType == stapaNALUType:
  191. currOffset := int(stapaHeaderSize)
  192. result := []byte{}
  193. for currOffset < len(payload) {
  194. naluSize := int(binary.BigEndian.Uint16(payload[currOffset:]))
  195. currOffset += stapaNALULengthSize
  196. if len(payload) < currOffset+naluSize {
  197. return nil, fmt.Errorf("%w STAP-A declared size(%d) is larger than buffer(%d)", errShortPacket, naluSize, len(payload)-currOffset)
  198. }
  199. result = append(result, p.doPackaging(payload[currOffset:currOffset+naluSize])...)
  200. currOffset += naluSize
  201. }
  202. return result, nil
  203. case naluType == fuaNALUType:
  204. if len(payload) < fuaHeaderSize {
  205. return nil, errShortPacket
  206. }
  207. if p.fuaBuffer == nil {
  208. p.fuaBuffer = []byte{}
  209. }
  210. p.fuaBuffer = append(p.fuaBuffer, payload[fuaHeaderSize:]...)
  211. if payload[1]&fuEndBitmask != 0 {
  212. naluRefIdc := payload[0] & naluRefIdcBitmask
  213. fragmentedNaluType := payload[1] & naluTypeBitmask
  214. nalu := append([]byte{}, naluRefIdc|fragmentedNaluType)
  215. nalu = append(nalu, p.fuaBuffer...)
  216. p.fuaBuffer = nil
  217. return p.doPackaging(nalu), nil
  218. }
  219. return []byte{}, nil
  220. }
  221. return nil, fmt.Errorf("%w: %d", errUnhandledNALUType, naluType)
  222. }
  223. // H264PartitionHeadChecker is obsolete
  224. type H264PartitionHeadChecker struct{}
  225. // IsPartitionHead checks if this is the head of a packetized nalu stream.
  226. func (*H264Packet) IsPartitionHead(payload []byte) bool {
  227. if len(payload) < 2 {
  228. return false
  229. }
  230. if payload[0]&naluTypeBitmask == fuaNALUType ||
  231. payload[0]&naluTypeBitmask == fubNALUType {
  232. return payload[1]&fuStartBitmask != 0
  233. }
  234. return true
  235. }