payloader.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package h264
  2. import "encoding/binary"
  3. // Payloader payloads H264 packets
  4. type Payloader struct {
  5. IsAVC bool
  6. stapANalu []byte
  7. }
  8. const (
  9. stapaNALUType = 24
  10. fuaNALUType = 28
  11. fubNALUType = 29
  12. spsNALUType = 7
  13. ppsNALUType = 8
  14. audNALUType = 9
  15. fillerNALUType = 12
  16. fuaHeaderSize = 2
  17. //stapaHeaderSize = 1
  18. //stapaNALULengthSize = 2
  19. naluTypeBitmask = 0x1F
  20. naluRefIdcBitmask = 0x60
  21. //fuStartBitmask = 0x80
  22. //fuEndBitmask = 0x40
  23. outputStapAHeader = 0x78
  24. )
  25. //func annexbNALUStartCode() []byte { return []byte{0x00, 0x00, 0x00, 0x01} }
  26. func EmitNalus(nals []byte, isAVC bool, emit func([]byte)) {
  27. if !isAVC {
  28. nextInd := func(nalu []byte, start int) (indStart int, indLen int) {
  29. zeroCount := 0
  30. for i, b := range nalu[start:] {
  31. if b == 0 {
  32. zeroCount++
  33. continue
  34. } else if b == 1 {
  35. if zeroCount >= 2 {
  36. return start + i - zeroCount, zeroCount + 1
  37. }
  38. }
  39. zeroCount = 0
  40. }
  41. return -1, -1
  42. }
  43. nextIndStart, nextIndLen := nextInd(nals, 0)
  44. if nextIndStart == -1 {
  45. emit(nals)
  46. } else {
  47. for nextIndStart != -1 {
  48. prevStart := nextIndStart + nextIndLen
  49. nextIndStart, nextIndLen = nextInd(nals, prevStart)
  50. if nextIndStart != -1 {
  51. emit(nals[prevStart:nextIndStart])
  52. } else {
  53. // Emit until end of stream, no end indicator found
  54. emit(nals[prevStart:])
  55. }
  56. }
  57. }
  58. } else {
  59. for {
  60. n := uint32(len(nals))
  61. if n < 4 {
  62. break
  63. }
  64. end := 4 + binary.BigEndian.Uint32(nals)
  65. if n < end {
  66. break
  67. }
  68. emit(nals[4:end])
  69. nals = nals[end:]
  70. }
  71. }
  72. }
  73. // Payload fragments a H264 packet across one or more byte arrays
  74. func (p *Payloader) Payload(mtu uint16, payload []byte) [][]byte {
  75. var payloads [][]byte
  76. if len(payload) == 0 {
  77. return payloads
  78. }
  79. EmitNalus(payload, p.IsAVC, func(nalu []byte) {
  80. if len(nalu) == 0 {
  81. return
  82. }
  83. naluType := nalu[0] & naluTypeBitmask
  84. naluRefIdc := nalu[0] & naluRefIdcBitmask
  85. switch naluType {
  86. case audNALUType, fillerNALUType:
  87. return
  88. case spsNALUType, ppsNALUType:
  89. if p.stapANalu == nil {
  90. p.stapANalu = []byte{outputStapAHeader}
  91. }
  92. p.stapANalu = append(p.stapANalu, byte(len(nalu)>>8), byte(len(nalu)))
  93. p.stapANalu = append(p.stapANalu, nalu...)
  94. return
  95. }
  96. if p.stapANalu != nil {
  97. // Pack current NALU with SPS and PPS as STAP-A
  98. // Supports multiple PPS in a row
  99. if len(p.stapANalu) <= int(mtu) {
  100. payloads = append(payloads, p.stapANalu)
  101. }
  102. p.stapANalu = nil
  103. }
  104. // Single NALU
  105. if len(nalu) <= int(mtu) {
  106. out := make([]byte, len(nalu))
  107. copy(out, nalu)
  108. payloads = append(payloads, out)
  109. return
  110. }
  111. // FU-A
  112. maxFragmentSize := int(mtu) - fuaHeaderSize
  113. // The FU payload consists of fragments of the payload of the fragmented
  114. // NAL unit so that if the fragmentation unit payloads of consecutive
  115. // FUs are sequentially concatenated, the payload of the fragmented NAL
  116. // unit can be reconstructed. The NAL unit type octet of the fragmented
  117. // NAL unit is not included as such in the fragmentation unit payload,
  118. // but rather the information of the NAL unit type octet of the
  119. // fragmented NAL unit is conveyed in the F and NRI fields of the FU
  120. // indicator octet of the fragmentation unit and in the type field of
  121. // the FU header. An FU payload MAY have any number of octets and MAY
  122. // be empty.
  123. naluData := nalu
  124. // According to the RFC, the first octet is skipped due to redundant information
  125. naluDataIndex := 1
  126. naluDataLength := len(nalu) - naluDataIndex
  127. naluDataRemaining := naluDataLength
  128. if min(maxFragmentSize, naluDataRemaining) <= 0 {
  129. return
  130. }
  131. for naluDataRemaining > 0 {
  132. currentFragmentSize := min(maxFragmentSize, naluDataRemaining)
  133. out := make([]byte, fuaHeaderSize+currentFragmentSize)
  134. // +---------------+
  135. // |0|1|2|3|4|5|6|7|
  136. // +-+-+-+-+-+-+-+-+
  137. // |F|NRI| Type |
  138. // +---------------+
  139. out[0] = fuaNALUType
  140. out[0] |= naluRefIdc
  141. // +---------------+
  142. // |0|1|2|3|4|5|6|7|
  143. // +-+-+-+-+-+-+-+-+
  144. // |S|E|R| Type |
  145. // +---------------+
  146. out[1] = naluType
  147. if naluDataRemaining == naluDataLength {
  148. // Set start bit
  149. out[1] |= 1 << 7
  150. } else if naluDataRemaining-currentFragmentSize == 0 {
  151. // Set end bit
  152. out[1] |= 1 << 6
  153. }
  154. copy(out[fuaHeaderSize:], naluData[naluDataIndex:naluDataIndex+currentFragmentSize])
  155. payloads = append(payloads, out)
  156. naluDataRemaining -= currentFragmentSize
  157. naluDataIndex += currentFragmentSize
  158. }
  159. })
  160. return payloads
  161. }
  162. func min(a, b int) int {
  163. if a < b {
  164. return a
  165. }
  166. return b
  167. }