h265.py 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. from .lib import Decoder, RtpData
  2. from .rtp import RTP
  3. __all__ = ["H265Decoder"]
  4. class PayloadHeader:
  5. def __init__(self, header: "bytes"):
  6. self.F = (header[0] & 0x80) > 0
  7. self.Type = (header[0] >> 1) & 0x3F
  8. self.LayerID = ((header[0] & 0x01) << 5) | (header[1] >> 3)
  9. self.TID = header[1] & 0x07
  10. def __str__(self):
  11. return f"<H265PayloadHeader: F:{self.F}, Type:{self.Type}, LayerID:{self.LayerID}, TID:{self.TID}>"
  12. class FuHeader:
  13. def __init__(self, header: "int"):
  14. self.S = (header & 0x80) > 0
  15. self.E = (header & 0x40) > 0
  16. self.Type = header & 0x3F
  17. def __str__(self):
  18. return f"<H265FuHeader: S:{self.S}, E:{self.E}, Type:{self.Type}>"
  19. class H265Decoder(Decoder):
  20. """
  21. Note:
  22. RTP荷载H.265分为:
  23. 1. 单一包(Single NAL unit packet)
  24. 2. 聚合包(Aggregation Packet)
  25. 3. 分片包(Fragmentation Unit)
  26. 每一种封包类型中都有PayloadHdr(载荷头)
  27. Structure:
  28. PayloadHdr:
  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. note:
  35. F: 1b, 通常为0,用于将来的扩展预留。
  36. Type: 重点,指示NAL单元的类型。它用于区分关键帧、非关键帧、补充增强信息等不同类型的NAL单元。不同的类型有不同的编号。
  37. 单一包: 当前所有数据包默认没有DONL、padding
  38. |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
  39. |0 1 2 3 |
  40. |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
  41. |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|
  42. |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
  43. | PayloadHdr | DONL (conditional) |
  44. |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
  45. | |
  46. | NAL unit payload data |
  47. | |
  48. | |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
  49. | :...OPTIONAL RTP padding |
  50. |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
  51. """
  52. def __init__(self):
  53. super(H265Decoder, self).__init__()
  54. def parse(self, rtp: "RTP"):
  55. payloadHeader = PayloadHeader(rtp.payload[0:2])
  56. fuHeader = FuHeader(rtp.payload[2])
  57. rtpData = RtpData(data=rtp.payload[3:], pts=rtp.header.timestamp, seq=rtp.header.SN, isFrameEnd=rtp.header.M)
  58. if payloadHeader.Type == 49:
  59. if fuHeader.S: # 帧的第一包
  60. rtpData.packType, rtpData.naluType = 0, fuHeader.Type << 1
  61. # 加起始码(prefix)、头部信息(nalHeader)
  62. rtpData.data = self.Prefix + bytes([rtpData.naluType, 1]) + rtp.payload[3:]
  63. elif fuHeader.E:
  64. rtpData.packType = 2
  65. else:
  66. rtpData.packType = 1
  67. elif payloadHeader.Type in [1, 32, 33, 34, 19, 20]:
  68. rtpData.data = self.Prefix + rtp.payload
  69. else:
  70. print(payloadHeader)
  71. raise TypeError(f"not support h265 headerType: {payloadHeader.Type}")
  72. self.Manager.lock.acquire()
  73. self.Manager.packs.append(rtpData)
  74. self.Manager.lock.release()
  75. return rtpData