h265_packet.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. package codecs
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "fmt"
  6. )
  7. //
  8. // Errors
  9. //
  10. var (
  11. errH265CorruptedPacket = errors.New("corrupted h265 packet")
  12. errInvalidH265PacketType = errors.New("invalid h265 packet type")
  13. )
  14. //
  15. // Network Abstraction Unit Header implementation
  16. //
  17. const (
  18. // sizeof(uint16)
  19. h265NaluHeaderSize = 2
  20. // https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
  21. h265NaluAggregationPacketType = 48
  22. // https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3
  23. h265NaluFragmentationUnitType = 49
  24. // https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4
  25. h265NaluPACIPacketType = 50
  26. )
  27. // H265NALUHeader is a H265 NAL Unit Header
  28. // https://datatracker.ietf.org/doc/html/rfc7798#section-1.1.4
  29. // +---------------+---------------+
  30. // |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
  31. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  32. // |F| Type | LayerID | TID |
  33. // +-------------+-----------------+
  34. type H265NALUHeader uint16
  35. func newH265NALUHeader(highByte, lowByte uint8) H265NALUHeader {
  36. return H265NALUHeader((uint16(highByte) << 8) | uint16(lowByte))
  37. }
  38. // F is the forbidden bit, should always be 0.
  39. func (h H265NALUHeader) F() bool {
  40. return (uint16(h) >> 15) != 0
  41. }
  42. // Type of NAL Unit.
  43. func (h H265NALUHeader) Type() uint8 {
  44. // 01111110 00000000
  45. const mask = 0b01111110 << 8
  46. return uint8((uint16(h) & mask) >> (8 + 1))
  47. }
  48. // IsTypeVCLUnit returns whether or not the NAL Unit type is a VCL NAL unit.
  49. func (h H265NALUHeader) IsTypeVCLUnit() bool {
  50. // Type is coded on 6 bits
  51. const msbMask = 0b00100000
  52. return (h.Type() & msbMask) == 0
  53. }
  54. // LayerID should always be 0 in non-3D HEVC context.
  55. func (h H265NALUHeader) LayerID() uint8 {
  56. // 00000001 11111000
  57. const mask = (0b00000001 << 8) | 0b11111000
  58. return uint8((uint16(h) & mask) >> 3)
  59. }
  60. // TID is the temporal identifier of the NAL unit +1.
  61. func (h H265NALUHeader) TID() uint8 {
  62. const mask = 0b00000111
  63. return uint8(uint16(h) & mask)
  64. }
  65. // IsAggregationPacket returns whether or not the packet is an Aggregation packet.
  66. func (h H265NALUHeader) IsAggregationPacket() bool {
  67. return h.Type() == h265NaluAggregationPacketType
  68. }
  69. // IsFragmentationUnit returns whether or not the packet is a Fragmentation Unit packet.
  70. func (h H265NALUHeader) IsFragmentationUnit() bool {
  71. return h.Type() == h265NaluFragmentationUnitType
  72. }
  73. // IsPACIPacket returns whether or not the packet is a PACI packet.
  74. func (h H265NALUHeader) IsPACIPacket() bool {
  75. return h.Type() == h265NaluPACIPacketType
  76. }
  77. //
  78. // Single NAL Unit Packet implementation
  79. //
  80. // H265SingleNALUnitPacket represents a NALU packet, containing exactly one NAL unit.
  81. // 0 1 2 3
  82. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  83. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  84. // | PayloadHdr | DONL (conditional) |
  85. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  86. // | |
  87. // | NAL unit payload data |
  88. // | |
  89. // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  90. // | :...OPTIONAL RTP padding |
  91. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  92. //
  93. // Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.1
  94. type H265SingleNALUnitPacket struct {
  95. // payloadHeader is the header of the H265 packet.
  96. payloadHeader H265NALUHeader
  97. // donl is a 16-bit field, that may or may not be present.
  98. donl *uint16
  99. // payload of the fragmentation unit.
  100. payload []byte
  101. mightNeedDONL bool
  102. }
  103. // WithDONL can be called to specify whether or not DONL might be parsed.
  104. // DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
  105. func (p *H265SingleNALUnitPacket) WithDONL(value bool) {
  106. p.mightNeedDONL = value
  107. }
  108. // Unmarshal parses the passed byte slice and stores the result in the H265SingleNALUnitPacket this method is called upon.
  109. func (p *H265SingleNALUnitPacket) Unmarshal(payload []byte) ([]byte, error) {
  110. // sizeof(headers)
  111. const totalHeaderSize = h265NaluHeaderSize
  112. if payload == nil {
  113. return nil, errNilPacket
  114. } else if len(payload) <= totalHeaderSize {
  115. return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
  116. }
  117. payloadHeader := newH265NALUHeader(payload[0], payload[1])
  118. if payloadHeader.F() {
  119. return nil, errH265CorruptedPacket
  120. }
  121. if payloadHeader.IsFragmentationUnit() || payloadHeader.IsPACIPacket() || payloadHeader.IsAggregationPacket() {
  122. return nil, errInvalidH265PacketType
  123. }
  124. payload = payload[2:]
  125. if p.mightNeedDONL {
  126. // sizeof(uint16)
  127. if len(payload) <= 2 {
  128. return nil, errShortPacket
  129. }
  130. donl := (uint16(payload[0]) << 8) | uint16(payload[1])
  131. p.donl = &donl
  132. payload = payload[2:]
  133. }
  134. p.payloadHeader = payloadHeader
  135. p.payload = payload
  136. return nil, nil
  137. }
  138. // PayloadHeader returns the NALU header of the packet.
  139. func (p *H265SingleNALUnitPacket) PayloadHeader() H265NALUHeader {
  140. return p.payloadHeader
  141. }
  142. // DONL returns the DONL of the packet.
  143. func (p *H265SingleNALUnitPacket) DONL() *uint16 {
  144. return p.donl
  145. }
  146. // Payload returns the Fragmentation Unit packet payload.
  147. func (p *H265SingleNALUnitPacket) Payload() []byte {
  148. return p.payload
  149. }
  150. func (p *H265SingleNALUnitPacket) isH265Packet() {}
  151. //
  152. // Aggregation Packets implementation
  153. //
  154. // H265AggregationUnitFirst represent the First Aggregation Unit in an AP.
  155. //
  156. // 0 1 2 3
  157. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  158. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  159. // : DONL (conditional) | NALU size |
  160. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  161. // | NALU size | |
  162. // +-+-+-+-+-+-+-+-+ NAL unit |
  163. // | |
  164. // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  165. // | :
  166. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  167. //
  168. // Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
  169. type H265AggregationUnitFirst struct {
  170. donl *uint16
  171. nalUnitSize uint16
  172. nalUnit []byte
  173. }
  174. // DONL field, when present, specifies the value of the 16 least
  175. // significant bits of the decoding order number of the aggregated NAL
  176. // unit.
  177. func (u H265AggregationUnitFirst) DONL() *uint16 {
  178. return u.donl
  179. }
  180. // NALUSize represents the size, in bytes, of the NalUnit.
  181. func (u H265AggregationUnitFirst) NALUSize() uint16 {
  182. return u.nalUnitSize
  183. }
  184. // NalUnit payload.
  185. func (u H265AggregationUnitFirst) NalUnit() []byte {
  186. return u.nalUnit
  187. }
  188. // H265AggregationUnit represent the an Aggregation Unit in an AP, which is not the first one.
  189. //
  190. // 0 1 2 3
  191. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  192. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  193. // : DOND (cond) | NALU size |
  194. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  195. // | |
  196. // | NAL unit |
  197. // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  198. // | :
  199. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  200. //
  201. // Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
  202. type H265AggregationUnit struct {
  203. dond *uint8
  204. nalUnitSize uint16
  205. nalUnit []byte
  206. }
  207. // DOND field plus 1 specifies the difference between
  208. // the decoding order number values of the current aggregated NAL unit
  209. // and the preceding aggregated NAL unit in the same AP.
  210. func (u H265AggregationUnit) DOND() *uint8 {
  211. return u.dond
  212. }
  213. // NALUSize represents the size, in bytes, of the NalUnit.
  214. func (u H265AggregationUnit) NALUSize() uint16 {
  215. return u.nalUnitSize
  216. }
  217. // NalUnit payload.
  218. func (u H265AggregationUnit) NalUnit() []byte {
  219. return u.nalUnit
  220. }
  221. // H265AggregationPacket represents an Aggregation packet.
  222. // 0 1 2 3
  223. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  224. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  225. // | PayloadHdr (Type=48) | |
  226. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
  227. // | |
  228. // | two or more aggregation units |
  229. // | |
  230. // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  231. // | :...OPTIONAL RTP padding |
  232. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  233. //
  234. // Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
  235. type H265AggregationPacket struct {
  236. firstUnit *H265AggregationUnitFirst
  237. otherUnits []H265AggregationUnit
  238. mightNeedDONL bool
  239. }
  240. // WithDONL can be called to specify whether or not DONL might be parsed.
  241. // DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
  242. func (p *H265AggregationPacket) WithDONL(value bool) {
  243. p.mightNeedDONL = value
  244. }
  245. // Unmarshal parses the passed byte slice and stores the result in the H265AggregationPacket this method is called upon.
  246. func (p *H265AggregationPacket) Unmarshal(payload []byte) ([]byte, error) {
  247. // sizeof(headers)
  248. const totalHeaderSize = h265NaluHeaderSize
  249. if payload == nil {
  250. return nil, errNilPacket
  251. } else if len(payload) <= totalHeaderSize {
  252. return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
  253. }
  254. payloadHeader := newH265NALUHeader(payload[0], payload[1])
  255. if payloadHeader.F() {
  256. return nil, errH265CorruptedPacket
  257. }
  258. if !payloadHeader.IsAggregationPacket() {
  259. return nil, errInvalidH265PacketType
  260. }
  261. // First parse the first aggregation unit
  262. payload = payload[2:]
  263. firstUnit := &H265AggregationUnitFirst{}
  264. if p.mightNeedDONL {
  265. if len(payload) < 2 {
  266. return nil, errShortPacket
  267. }
  268. donl := (uint16(payload[0]) << 8) | uint16(payload[1])
  269. firstUnit.donl = &donl
  270. payload = payload[2:]
  271. }
  272. if len(payload) < 2 {
  273. return nil, errShortPacket
  274. }
  275. firstUnit.nalUnitSize = (uint16(payload[0]) << 8) | uint16(payload[1])
  276. payload = payload[2:]
  277. if len(payload) < int(firstUnit.nalUnitSize) {
  278. return nil, errShortPacket
  279. }
  280. firstUnit.nalUnit = payload[:firstUnit.nalUnitSize]
  281. payload = payload[firstUnit.nalUnitSize:]
  282. // Parse remaining Aggregation Units
  283. var units []H265AggregationUnit
  284. for {
  285. unit := H265AggregationUnit{}
  286. if p.mightNeedDONL {
  287. if len(payload) < 1 {
  288. break
  289. }
  290. dond := payload[0]
  291. unit.dond = &dond
  292. payload = payload[1:]
  293. }
  294. if len(payload) < 2 {
  295. break
  296. }
  297. unit.nalUnitSize = (uint16(payload[0]) << 8) | uint16(payload[1])
  298. payload = payload[2:]
  299. if len(payload) < int(unit.nalUnitSize) {
  300. break
  301. }
  302. unit.nalUnit = payload[:unit.nalUnitSize]
  303. payload = payload[unit.nalUnitSize:]
  304. units = append(units, unit)
  305. }
  306. // There need to be **at least** two Aggregation Units (first + another one)
  307. if len(units) == 0 {
  308. return nil, errShortPacket
  309. }
  310. p.firstUnit = firstUnit
  311. p.otherUnits = units
  312. return nil, nil
  313. }
  314. // FirstUnit returns the first Aggregated Unit of the packet.
  315. func (p *H265AggregationPacket) FirstUnit() *H265AggregationUnitFirst {
  316. return p.firstUnit
  317. }
  318. // OtherUnits returns the all the other Aggregated Unit of the packet (excluding the first one).
  319. func (p *H265AggregationPacket) OtherUnits() []H265AggregationUnit {
  320. return p.otherUnits
  321. }
  322. func (p *H265AggregationPacket) isH265Packet() {}
  323. //
  324. // Fragmentation Unit implementation
  325. //
  326. const (
  327. // sizeof(uint8)
  328. h265FragmentationUnitHeaderSize = 1
  329. )
  330. // H265FragmentationUnitHeader is a H265 FU Header
  331. // +---------------+
  332. // |0|1|2|3|4|5|6|7|
  333. // +-+-+-+-+-+-+-+-+
  334. // |S|E| FuType |
  335. // +---------------+
  336. type H265FragmentationUnitHeader uint8
  337. // S represents the start of a fragmented NAL unit.
  338. func (h H265FragmentationUnitHeader) S() bool {
  339. const mask = 0b10000000
  340. return ((h & mask) >> 7) != 0
  341. }
  342. // E represents the end of a fragmented NAL unit.
  343. func (h H265FragmentationUnitHeader) E() bool {
  344. const mask = 0b01000000
  345. return ((h & mask) >> 6) != 0
  346. }
  347. // FuType MUST be equal to the field Type of the fragmented NAL unit.
  348. func (h H265FragmentationUnitHeader) FuType() uint8 {
  349. const mask = 0b00111111
  350. return uint8(h) & mask
  351. }
  352. // H265FragmentationUnitPacket represents a single Fragmentation Unit packet.
  353. //
  354. // 0 1 2 3
  355. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  356. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  357. // | PayloadHdr (Type=49) | FU header | DONL (cond) |
  358. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
  359. // | DONL (cond) | |
  360. // |-+-+-+-+-+-+-+-+ |
  361. // | FU payload |
  362. // | |
  363. // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  364. // | :...OPTIONAL RTP padding |
  365. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  366. //
  367. // Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3
  368. type H265FragmentationUnitPacket struct {
  369. // payloadHeader is the header of the H265 packet.
  370. payloadHeader H265NALUHeader
  371. // fuHeader is the header of the fragmentation unit
  372. fuHeader H265FragmentationUnitHeader
  373. // donl is a 16-bit field, that may or may not be present.
  374. donl *uint16
  375. // payload of the fragmentation unit.
  376. payload []byte
  377. mightNeedDONL bool
  378. }
  379. // WithDONL can be called to specify whether or not DONL might be parsed.
  380. // DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
  381. func (p *H265FragmentationUnitPacket) WithDONL(value bool) {
  382. p.mightNeedDONL = value
  383. }
  384. // Unmarshal parses the passed byte slice and stores the result in the H265FragmentationUnitPacket this method is called upon.
  385. func (p *H265FragmentationUnitPacket) Unmarshal(payload []byte) ([]byte, error) {
  386. // sizeof(headers)
  387. const totalHeaderSize = h265NaluHeaderSize + h265FragmentationUnitHeaderSize
  388. if payload == nil {
  389. return nil, errNilPacket
  390. } else if len(payload) <= totalHeaderSize {
  391. return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
  392. }
  393. payloadHeader := newH265NALUHeader(payload[0], payload[1])
  394. if payloadHeader.F() {
  395. return nil, errH265CorruptedPacket
  396. }
  397. if !payloadHeader.IsFragmentationUnit() {
  398. return nil, errInvalidH265PacketType
  399. }
  400. fuHeader := H265FragmentationUnitHeader(payload[2])
  401. payload = payload[3:]
  402. if fuHeader.S() && p.mightNeedDONL {
  403. // sizeof(uint16)
  404. if len(payload) <= 2 {
  405. return nil, errShortPacket
  406. }
  407. donl := (uint16(payload[0]) << 8) | uint16(payload[1])
  408. p.donl = &donl
  409. payload = payload[2:]
  410. }
  411. p.payloadHeader = payloadHeader
  412. p.fuHeader = fuHeader
  413. p.payload = payload
  414. return nil, nil
  415. }
  416. // PayloadHeader returns the NALU header of the packet.
  417. func (p *H265FragmentationUnitPacket) PayloadHeader() H265NALUHeader {
  418. return p.payloadHeader
  419. }
  420. // FuHeader returns the Fragmentation Unit Header of the packet.
  421. func (p *H265FragmentationUnitPacket) FuHeader() H265FragmentationUnitHeader {
  422. return p.fuHeader
  423. }
  424. // DONL returns the DONL of the packet.
  425. func (p *H265FragmentationUnitPacket) DONL() *uint16 {
  426. return p.donl
  427. }
  428. // Payload returns the Fragmentation Unit packet payload.
  429. func (p *H265FragmentationUnitPacket) Payload() []byte {
  430. return p.payload
  431. }
  432. func (p *H265FragmentationUnitPacket) isH265Packet() {}
  433. //
  434. // PACI implementation
  435. //
  436. // H265PACIPacket represents a single H265 PACI packet.
  437. //
  438. // 0 1 2 3
  439. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  440. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  441. // | PayloadHdr (Type=50) |A| cType | PHSsize |F0..2|Y|
  442. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  443. // | Payload Header Extension Structure (PHES) |
  444. // |=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=|
  445. // | |
  446. // | PACI payload: NAL unit |
  447. // | . . . |
  448. // | |
  449. // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  450. // | :...OPTIONAL RTP padding |
  451. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  452. //
  453. // Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4
  454. type H265PACIPacket struct {
  455. // payloadHeader is the header of the H265 packet.
  456. payloadHeader H265NALUHeader
  457. // Field which holds value for `A`, `cType`, `PHSsize`, `F0`, `F1`, `F2` and `Y` fields.
  458. paciHeaderFields uint16
  459. // phes is a header extension, of byte length `PHSsize`
  460. phes []byte
  461. // Payload contains NAL units & optional padding
  462. payload []byte
  463. }
  464. // PayloadHeader returns the NAL Unit Header.
  465. func (p *H265PACIPacket) PayloadHeader() H265NALUHeader {
  466. return p.payloadHeader
  467. }
  468. // A copies the F bit of the PACI payload NALU.
  469. func (p *H265PACIPacket) A() bool {
  470. const mask = 0b10000000 << 8
  471. return (p.paciHeaderFields & mask) != 0
  472. }
  473. // CType copies the Type field of the PACI payload NALU.
  474. func (p *H265PACIPacket) CType() uint8 {
  475. const mask = 0b01111110 << 8
  476. return uint8((p.paciHeaderFields & mask) >> (8 + 1))
  477. }
  478. // PHSsize indicates the size of the PHES field.
  479. func (p *H265PACIPacket) PHSsize() uint8 {
  480. const mask = (0b00000001 << 8) | 0b11110000
  481. return uint8((p.paciHeaderFields & mask) >> 4)
  482. }
  483. // F0 indicates the presence of a Temporal Scalability support extension in the PHES.
  484. func (p *H265PACIPacket) F0() bool {
  485. const mask = 0b00001000
  486. return (p.paciHeaderFields & mask) != 0
  487. }
  488. // F1 must be zero, reserved for future extensions.
  489. func (p *H265PACIPacket) F1() bool {
  490. const mask = 0b00000100
  491. return (p.paciHeaderFields & mask) != 0
  492. }
  493. // F2 must be zero, reserved for future extensions.
  494. func (p *H265PACIPacket) F2() bool {
  495. const mask = 0b00000010
  496. return (p.paciHeaderFields & mask) != 0
  497. }
  498. // Y must be zero, reserved for future extensions.
  499. func (p *H265PACIPacket) Y() bool {
  500. const mask = 0b00000001
  501. return (p.paciHeaderFields & mask) != 0
  502. }
  503. // PHES contains header extensions. Its size is indicated by PHSsize.
  504. func (p *H265PACIPacket) PHES() []byte {
  505. return p.phes
  506. }
  507. // Payload is a single NALU or NALU-like struct, not including the first two octets (header).
  508. func (p *H265PACIPacket) Payload() []byte {
  509. return p.payload
  510. }
  511. // TSCI returns the Temporal Scalability Control Information extension, if present.
  512. func (p *H265PACIPacket) TSCI() *H265TSCI {
  513. if !p.F0() || p.PHSsize() < 3 {
  514. return nil
  515. }
  516. tsci := H265TSCI((uint32(p.phes[0]) << 16) | (uint32(p.phes[1]) << 8) | uint32(p.phes[0]))
  517. return &tsci
  518. }
  519. // Unmarshal parses the passed byte slice and stores the result in the H265PACIPacket this method is called upon.
  520. func (p *H265PACIPacket) Unmarshal(payload []byte) ([]byte, error) {
  521. // sizeof(headers)
  522. const totalHeaderSize = h265NaluHeaderSize + 2
  523. if payload == nil {
  524. return nil, errNilPacket
  525. } else if len(payload) <= totalHeaderSize {
  526. return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
  527. }
  528. payloadHeader := newH265NALUHeader(payload[0], payload[1])
  529. if payloadHeader.F() {
  530. return nil, errH265CorruptedPacket
  531. }
  532. if !payloadHeader.IsPACIPacket() {
  533. return nil, errInvalidH265PacketType
  534. }
  535. paciHeaderFields := (uint16(payload[2]) << 8) | uint16(payload[3])
  536. payload = payload[4:]
  537. p.paciHeaderFields = paciHeaderFields
  538. headerExtensionSize := p.PHSsize()
  539. if len(payload) < int(headerExtensionSize)+1 {
  540. p.paciHeaderFields = 0
  541. return nil, errShortPacket
  542. }
  543. p.payloadHeader = payloadHeader
  544. if headerExtensionSize > 0 {
  545. p.phes = payload[:headerExtensionSize]
  546. }
  547. payload = payload[headerExtensionSize:]
  548. p.payload = payload
  549. return nil, nil
  550. }
  551. func (p *H265PACIPacket) isH265Packet() {}
  552. //
  553. // Temporal Scalability Control Information
  554. //
  555. // H265TSCI is a Temporal Scalability Control Information header extension.
  556. // Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.5
  557. type H265TSCI uint32
  558. // TL0PICIDX see RFC7798 for more details.
  559. func (h H265TSCI) TL0PICIDX() uint8 {
  560. const m1 = 0xFFFF0000
  561. const m2 = 0xFF00
  562. return uint8((((h & m1) >> 16) & m2) >> 8)
  563. }
  564. // IrapPicID see RFC7798 for more details.
  565. func (h H265TSCI) IrapPicID() uint8 {
  566. const m1 = 0xFFFF0000
  567. const m2 = 0x00FF
  568. return uint8(((h & m1) >> 16) & m2)
  569. }
  570. // S see RFC7798 for more details.
  571. func (h H265TSCI) S() bool {
  572. const m1 = 0xFF00
  573. const m2 = 0b10000000
  574. return (uint8((h&m1)>>8) & m2) != 0
  575. }
  576. // E see RFC7798 for more details.
  577. func (h H265TSCI) E() bool {
  578. const m1 = 0xFF00
  579. const m2 = 0b01000000
  580. return (uint8((h&m1)>>8) & m2) != 0
  581. }
  582. // RES see RFC7798 for more details.
  583. func (h H265TSCI) RES() uint8 {
  584. const m1 = 0xFF00
  585. const m2 = 0b00111111
  586. return uint8((h&m1)>>8) & m2
  587. }
  588. //
  589. // H265 Packet interface
  590. //
  591. type isH265Packet interface {
  592. isH265Packet()
  593. }
  594. var (
  595. _ isH265Packet = (*H265FragmentationUnitPacket)(nil)
  596. _ isH265Packet = (*H265PACIPacket)(nil)
  597. _ isH265Packet = (*H265SingleNALUnitPacket)(nil)
  598. _ isH265Packet = (*H265AggregationPacket)(nil)
  599. )
  600. //
  601. // Packet implementation
  602. //
  603. // H265Packet represents a H265 packet, stored in the payload of an RTP packet.
  604. type H265Packet struct {
  605. packet isH265Packet
  606. mightNeedDONL bool
  607. videoDepacketizer
  608. }
  609. // WithDONL can be called to specify whether or not DONL might be parsed.
  610. // DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
  611. func (p *H265Packet) WithDONL(value bool) {
  612. p.mightNeedDONL = value
  613. }
  614. // Unmarshal parses the passed byte slice and stores the result in the H265Packet this method is called upon
  615. func (p *H265Packet) Unmarshal(payload []byte) ([]byte, error) {
  616. if payload == nil {
  617. return nil, errNilPacket
  618. } else if len(payload) <= h265NaluHeaderSize {
  619. return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), h265NaluHeaderSize)
  620. }
  621. payloadHeader := newH265NALUHeader(payload[0], payload[1])
  622. if payloadHeader.F() {
  623. return nil, errH265CorruptedPacket
  624. }
  625. switch {
  626. case payloadHeader.IsPACIPacket():
  627. decoded := &H265PACIPacket{}
  628. if _, err := decoded.Unmarshal(payload); err != nil {
  629. return nil, err
  630. }
  631. p.packet = decoded
  632. case payloadHeader.IsFragmentationUnit():
  633. decoded := &H265FragmentationUnitPacket{}
  634. decoded.WithDONL(p.mightNeedDONL)
  635. if _, err := decoded.Unmarshal(payload); err != nil {
  636. return nil, err
  637. }
  638. p.packet = decoded
  639. case payloadHeader.IsAggregationPacket():
  640. decoded := &H265AggregationPacket{}
  641. decoded.WithDONL(p.mightNeedDONL)
  642. if _, err := decoded.Unmarshal(payload); err != nil {
  643. return nil, err
  644. }
  645. p.packet = decoded
  646. default:
  647. decoded := &H265SingleNALUnitPacket{}
  648. decoded.WithDONL(p.mightNeedDONL)
  649. if _, err := decoded.Unmarshal(payload); err != nil {
  650. return nil, err
  651. }
  652. p.packet = decoded
  653. }
  654. return nil, nil
  655. }
  656. // Packet returns the populated packet.
  657. // Must be casted to one of:
  658. // - *H265SingleNALUnitPacket
  659. // - *H265FragmentationUnitPacket
  660. // - *H265AggregationPacket
  661. // - *H265PACIPacket
  662. // nolint:golint
  663. func (p *H265Packet) Packet() isH265Packet {
  664. return p.packet
  665. }
  666. // IsPartitionHead checks if this is the head of a packetized nalu stream.
  667. func (*H265Packet) IsPartitionHead(payload []byte) bool {
  668. if len(payload) < 3 {
  669. return false
  670. }
  671. if H265NALUHeader(binary.BigEndian.Uint16(payload[0:2])).Type() == h265NaluFragmentationUnitType {
  672. return H265FragmentationUnitHeader(payload[2]).S()
  673. }
  674. return true
  675. }