avcc.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // Package h264 - AVCC format related functions
  2. package h264
  3. import (
  4. "bytes"
  5. "encoding/base64"
  6. "encoding/binary"
  7. "encoding/hex"
  8. "github.com/AlexxIT/go2rtc/pkg/core"
  9. "github.com/pion/rtp"
  10. )
  11. func RepairAVCC(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
  12. sps, pps := GetParameterSet(codec.FmtpLine)
  13. ps := JoinNALU(sps, pps)
  14. return func(packet *rtp.Packet) {
  15. if NALUType(packet.Payload) == NALUTypeIFrame {
  16. packet.Payload = Join(ps, packet.Payload)
  17. }
  18. handler(packet)
  19. }
  20. }
  21. func JoinNALU(nalus ...[]byte) (avcc []byte) {
  22. var i, n int
  23. for _, nalu := range nalus {
  24. if i = len(nalu); i > 0 {
  25. n += 4 + i
  26. }
  27. }
  28. avcc = make([]byte, n)
  29. n = 0
  30. for _, nal := range nalus {
  31. if i = len(nal); i > 0 {
  32. binary.BigEndian.PutUint32(avcc[n:], uint32(i))
  33. n += 4 + copy(avcc[n+4:], nal)
  34. }
  35. }
  36. return
  37. }
  38. func SplitNALU(avcc []byte) [][]byte {
  39. var nals [][]byte
  40. for {
  41. // get AVC length
  42. size := int(binary.BigEndian.Uint32(avcc)) + 4
  43. // check if multiple items in one packet
  44. if size < len(avcc) {
  45. nals = append(nals, avcc[:size])
  46. avcc = avcc[size:]
  47. } else {
  48. nals = append(nals, avcc)
  49. break
  50. }
  51. }
  52. return nals
  53. }
  54. func NALUTypes(avcc []byte) []byte {
  55. var types []byte
  56. for {
  57. types = append(types, NALUType(avcc))
  58. size := 4 + int(binary.BigEndian.Uint32(avcc))
  59. if size < len(avcc) {
  60. avcc = avcc[size:]
  61. } else {
  62. break
  63. }
  64. }
  65. return types
  66. }
  67. func AVCCToCodec(avcc []byte) *core.Codec {
  68. buf := bytes.NewBufferString("packetization-mode=1")
  69. for {
  70. size := 4 + int(binary.BigEndian.Uint32(avcc))
  71. switch NALUType(avcc) {
  72. case NALUTypeSPS:
  73. buf.WriteString(";profile-level-id=")
  74. buf.WriteString(hex.EncodeToString(avcc[5:8]))
  75. buf.WriteString(";sprop-parameter-sets=")
  76. buf.WriteString(base64.StdEncoding.EncodeToString(avcc[4:size]))
  77. case NALUTypePPS:
  78. buf.WriteString(",")
  79. buf.WriteString(base64.StdEncoding.EncodeToString(avcc[4:size]))
  80. }
  81. if size < len(avcc) {
  82. avcc = avcc[size:]
  83. } else {
  84. break
  85. }
  86. }
  87. return &core.Codec{
  88. Name: core.CodecH264,
  89. ClockRate: 90000,
  90. FmtpLine: buf.String(),
  91. PayloadType: core.PayloadTypeRAW,
  92. }
  93. }