vp8_packet.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package codecs
  2. // VP8Payloader payloads VP8 packets
  3. type VP8Payloader struct {
  4. EnablePictureID bool
  5. pictureID uint16
  6. }
  7. const (
  8. vp8HeaderSize = 1
  9. )
  10. // Payload fragments a VP8 packet across one or more byte arrays
  11. func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte {
  12. /*
  13. * https://tools.ietf.org/html/rfc7741#section-4.2
  14. *
  15. * 0 1 2 3 4 5 6 7
  16. * +-+-+-+-+-+-+-+-+
  17. * |X|R|N|S|R| PID | (REQUIRED)
  18. * +-+-+-+-+-+-+-+-+
  19. * X: |I|L|T|K| RSV | (OPTIONAL)
  20. * +-+-+-+-+-+-+-+-+
  21. * I: |M| PictureID | (OPTIONAL)
  22. * +-+-+-+-+-+-+-+-+
  23. * L: | TL0PICIDX | (OPTIONAL)
  24. * +-+-+-+-+-+-+-+-+
  25. * T/K: |TID|Y| KEYIDX | (OPTIONAL)
  26. * +-+-+-+-+-+-+-+-+
  27. * S: Start of VP8 partition. SHOULD be set to 1 when the first payload
  28. * octet of the RTP packet is the beginning of a new VP8 partition,
  29. * and MUST NOT be 1 otherwise. The S bit MUST be set to 1 for the
  30. * first packet of each encoded frame.
  31. */
  32. usingHeaderSize := vp8HeaderSize
  33. if p.EnablePictureID {
  34. switch {
  35. case p.pictureID == 0:
  36. case p.pictureID < 128:
  37. usingHeaderSize = vp8HeaderSize + 2
  38. default:
  39. usingHeaderSize = vp8HeaderSize + 3
  40. }
  41. }
  42. maxFragmentSize := int(mtu) - usingHeaderSize
  43. payloadData := payload
  44. payloadDataRemaining := len(payload)
  45. payloadDataIndex := 0
  46. var payloads [][]byte
  47. // Make sure the fragment/payload size is correct
  48. if min(maxFragmentSize, payloadDataRemaining) <= 0 {
  49. return payloads
  50. }
  51. first := true
  52. for payloadDataRemaining > 0 {
  53. currentFragmentSize := min(maxFragmentSize, payloadDataRemaining)
  54. out := make([]byte, usingHeaderSize+currentFragmentSize)
  55. if first {
  56. out[0] = 0x10
  57. first = false
  58. }
  59. if p.EnablePictureID {
  60. switch usingHeaderSize {
  61. case vp8HeaderSize:
  62. case vp8HeaderSize + 2:
  63. out[0] |= 0x80
  64. out[1] |= 0x80
  65. out[2] |= uint8(p.pictureID & 0x7F)
  66. case vp8HeaderSize + 3:
  67. out[0] |= 0x80
  68. out[1] |= 0x80
  69. out[2] |= 0x80 | uint8((p.pictureID>>8)&0x7F)
  70. out[3] |= uint8(p.pictureID & 0xFF)
  71. }
  72. }
  73. copy(out[usingHeaderSize:], payloadData[payloadDataIndex:payloadDataIndex+currentFragmentSize])
  74. payloads = append(payloads, out)
  75. payloadDataRemaining -= currentFragmentSize
  76. payloadDataIndex += currentFragmentSize
  77. }
  78. p.pictureID++
  79. p.pictureID &= 0x7FFF
  80. return payloads
  81. }
  82. // VP8Packet represents the VP8 header that is stored in the payload of an RTP Packet
  83. type VP8Packet struct {
  84. // Required Header
  85. X uint8 /* extended control bits present */
  86. N uint8 /* when set to 1 this frame can be discarded */
  87. S uint8 /* start of VP8 partition */
  88. PID uint8 /* partition index */
  89. // Extended control bits
  90. I uint8 /* 1 if PictureID is present */
  91. L uint8 /* 1 if TL0PICIDX is present */
  92. T uint8 /* 1 if TID is present */
  93. K uint8 /* 1 if KEYIDX is present */
  94. // Optional extension
  95. PictureID uint16 /* 8 or 16 bits, picture ID */
  96. TL0PICIDX uint8 /* 8 bits temporal level zero index */
  97. TID uint8 /* 2 bits temporal layer index */
  98. Y uint8 /* 1 bit layer sync bit */
  99. KEYIDX uint8 /* 5 bits temporal key frame index */
  100. Payload []byte
  101. videoDepacketizer
  102. }
  103. // Unmarshal parses the passed byte slice and stores the result in the VP8Packet this method is called upon
  104. func (p *VP8Packet) Unmarshal(payload []byte) ([]byte, error) {
  105. if payload == nil {
  106. return nil, errNilPacket
  107. }
  108. payloadLen := len(payload)
  109. if payloadLen < 4 {
  110. return nil, errShortPacket
  111. }
  112. payloadIndex := 0
  113. p.X = (payload[payloadIndex] & 0x80) >> 7
  114. p.N = (payload[payloadIndex] & 0x20) >> 5
  115. p.S = (payload[payloadIndex] & 0x10) >> 4
  116. p.PID = payload[payloadIndex] & 0x07
  117. payloadIndex++
  118. if p.X == 1 {
  119. p.I = (payload[payloadIndex] & 0x80) >> 7
  120. p.L = (payload[payloadIndex] & 0x40) >> 6
  121. p.T = (payload[payloadIndex] & 0x20) >> 5
  122. p.K = (payload[payloadIndex] & 0x10) >> 4
  123. payloadIndex++
  124. }
  125. if p.I == 1 { // PID present?
  126. if payload[payloadIndex]&0x80 > 0 { // M == 1, PID is 16bit
  127. p.PictureID = (uint16(payload[payloadIndex]&0x7F) << 8) | uint16(payload[payloadIndex+1])
  128. payloadIndex += 2
  129. } else {
  130. p.PictureID = uint16(payload[payloadIndex])
  131. payloadIndex++
  132. }
  133. }
  134. if payloadIndex >= payloadLen {
  135. return nil, errShortPacket
  136. }
  137. if p.L == 1 {
  138. p.TL0PICIDX = payload[payloadIndex]
  139. payloadIndex++
  140. }
  141. if payloadIndex >= payloadLen {
  142. return nil, errShortPacket
  143. }
  144. if p.T == 1 || p.K == 1 {
  145. if p.T == 1 {
  146. p.TID = payload[payloadIndex] >> 6
  147. p.Y = (payload[payloadIndex] >> 5) & 0x1
  148. }
  149. if p.K == 1 {
  150. p.KEYIDX = payload[payloadIndex] & 0x1F
  151. }
  152. payloadIndex++
  153. }
  154. if payloadIndex >= payloadLen {
  155. return nil, errShortPacket
  156. }
  157. p.Payload = payload[payloadIndex:]
  158. return p.Payload, nil
  159. }
  160. // VP8PartitionHeadChecker is obsolete
  161. type VP8PartitionHeadChecker struct{}
  162. // IsPartitionHead checks whether if this is a head of the VP8 partition
  163. func (*VP8Packet) IsPartitionHead(payload []byte) bool {
  164. if len(payload) < 1 {
  165. return false
  166. }
  167. return (payload[0] & 0x10) != 0
  168. }