producer.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package dvrip
  2. import (
  3. "encoding/base64"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "time"
  8. "github.com/AlexxIT/go2rtc/pkg/core"
  9. "github.com/AlexxIT/go2rtc/pkg/h264"
  10. "github.com/AlexxIT/go2rtc/pkg/h264/annexb"
  11. "github.com/AlexxIT/go2rtc/pkg/h265"
  12. "github.com/pion/rtp"
  13. )
  14. type Producer struct {
  15. core.Connection
  16. client *Client
  17. video, audio *core.Receiver
  18. videoTS uint32
  19. videoDT uint32
  20. audioTS uint32
  21. audioSeq uint16
  22. }
  23. func (c *Producer) Start() error {
  24. for {
  25. pType, b, err := c.client.ReadPacket()
  26. if err != nil {
  27. return err
  28. }
  29. //log.Printf("[DVR] type: %d, len: %d", dataType, len(b))
  30. switch pType {
  31. case 0xFC, 0xFE, 0xFD:
  32. if c.video == nil {
  33. continue
  34. }
  35. var payload []byte
  36. if pType != 0xFD {
  37. payload = b[16:] // iframe
  38. } else {
  39. payload = b[8:] // pframe
  40. }
  41. c.videoTS += c.videoDT
  42. packet := &rtp.Packet{
  43. Header: rtp.Header{Timestamp: c.videoTS},
  44. Payload: annexb.EncodeToAVCC(payload),
  45. }
  46. //log.Printf("[AVC] %v, len: %d, ts: %10d", h265.Types(payload), len(payload), packet.Timestamp)
  47. c.video.WriteRTP(packet)
  48. case 0xFA: // audio
  49. if c.audio == nil {
  50. continue
  51. }
  52. payload := b[8:]
  53. c.audioTS += uint32(len(payload))
  54. c.audioSeq++
  55. packet := &rtp.Packet{
  56. Header: rtp.Header{
  57. Version: 2,
  58. Marker: true,
  59. SequenceNumber: c.audioSeq,
  60. Timestamp: c.audioTS,
  61. },
  62. Payload: payload,
  63. }
  64. //log.Printf("[DVR] len: %d, ts: %10d", len(packet.Payload), packet.Timestamp)
  65. c.audio.WriteRTP(packet)
  66. case 0xF9: // unknown
  67. default:
  68. println(fmt.Sprintf("dvrip: unknown packet type: %d", pType))
  69. }
  70. }
  71. }
  72. func (c *Producer) probe() error {
  73. if err := c.client.Play(); err != nil {
  74. return err
  75. }
  76. rd := core.NewReadBuffer(c.client.rd)
  77. rd.BufferSize = core.ProbeSize
  78. defer func() {
  79. c.client.buf = nil
  80. rd.Reset()
  81. }()
  82. c.client.rd = rd
  83. // some awful cameras has VERY rare keyframes
  84. // so we wait video+audio for default probe time
  85. // and wait anything for 15 seconds
  86. timeoutBoth := time.Now().Add(core.ProbeTimeout)
  87. timeoutAny := time.Now().Add(time.Second * 15)
  88. for {
  89. if now := time.Now(); now.Before(timeoutBoth) {
  90. if c.video != nil && c.audio != nil {
  91. return nil
  92. }
  93. } else if now.Before(timeoutAny) {
  94. if c.video != nil || c.audio != nil {
  95. return nil
  96. }
  97. } else {
  98. return errors.New("dvrip: can't probe medias")
  99. }
  100. tag, b, err := c.client.ReadPacket()
  101. if err != nil {
  102. return err
  103. }
  104. switch tag {
  105. case 0xFC, 0xFE: // video
  106. if c.video != nil {
  107. continue
  108. }
  109. fps := b[5]
  110. //width := uint16(b[6]) * 8
  111. //height := uint16(b[7]) * 8
  112. //println(width, height)
  113. ts := b[8:]
  114. // the exact value of the start TS does not matter
  115. c.videoTS = binary.LittleEndian.Uint32(ts)
  116. c.videoDT = 90000 / uint32(fps)
  117. payload := annexb.EncodeToAVCC(b[16:])
  118. c.addVideoTrack(b[4], payload)
  119. case 0xFA: // audio
  120. if c.audio != nil {
  121. continue
  122. }
  123. // the exact value of the start TS does not matter
  124. c.audioTS = c.videoTS
  125. c.addAudioTrack(b[4], b[5])
  126. }
  127. }
  128. }
  129. func (c *Producer) addVideoTrack(mediaCode byte, payload []byte) {
  130. var codec *core.Codec
  131. switch mediaCode {
  132. case 0x02, 0x12:
  133. codec = &core.Codec{
  134. Name: core.CodecH264,
  135. ClockRate: 90000,
  136. PayloadType: core.PayloadTypeRAW,
  137. FmtpLine: h264.GetFmtpLine(payload),
  138. }
  139. case 0x03, 0x13, 0x43, 0x53:
  140. codec = &core.Codec{
  141. Name: core.CodecH265,
  142. ClockRate: 90000,
  143. PayloadType: core.PayloadTypeRAW,
  144. FmtpLine: "profile-id=1",
  145. }
  146. for {
  147. size := 4 + int(binary.BigEndian.Uint32(payload))
  148. switch h265.NALUType(payload) {
  149. case h265.NALUTypeVPS:
  150. codec.FmtpLine += ";sprop-vps=" + base64.StdEncoding.EncodeToString(payload[4:size])
  151. case h265.NALUTypeSPS:
  152. codec.FmtpLine += ";sprop-sps=" + base64.StdEncoding.EncodeToString(payload[4:size])
  153. case h265.NALUTypePPS:
  154. codec.FmtpLine += ";sprop-pps=" + base64.StdEncoding.EncodeToString(payload[4:size])
  155. }
  156. if size < len(payload) {
  157. payload = payload[size:]
  158. } else {
  159. break
  160. }
  161. }
  162. default:
  163. println("[DVRIP] unsupported video codec:", mediaCode)
  164. return
  165. }
  166. media := &core.Media{
  167. Kind: core.KindVideo,
  168. Direction: core.DirectionRecvonly,
  169. Codecs: []*core.Codec{codec},
  170. }
  171. c.Medias = append(c.Medias, media)
  172. c.video = core.NewReceiver(media, codec)
  173. c.Receivers = append(c.Receivers, c.video)
  174. }
  175. var sampleRates = []uint32{4000, 8000, 11025, 16000, 20000, 22050, 32000, 44100, 48000}
  176. func (c *Producer) addAudioTrack(mediaCode byte, sampleRate byte) {
  177. // https://github.com/vigoss30611/buildroot-ltc/blob/master/system/qm/ipc/ProtocolService/src/ZhiNuo/inc/zn_dh_base_type.h
  178. // PCM8 = 7, G729, IMA_ADPCM, G711U, G721, PCM8_VWIS, MS_ADPCM, G711A, PCM16
  179. var codec *core.Codec
  180. switch mediaCode {
  181. case 10: // G711U
  182. codec = &core.Codec{
  183. Name: core.CodecPCMU,
  184. }
  185. case 14: // G711A
  186. codec = &core.Codec{
  187. Name: core.CodecPCMA,
  188. }
  189. default:
  190. println("[DVRIP] unsupported audio codec:", mediaCode)
  191. return
  192. }
  193. if sampleRate <= byte(len(sampleRates)) {
  194. codec.ClockRate = sampleRates[sampleRate-1]
  195. }
  196. media := &core.Media{
  197. Kind: core.KindAudio,
  198. Direction: core.DirectionRecvonly,
  199. Codecs: []*core.Codec{codec},
  200. }
  201. c.Medias = append(c.Medias, media)
  202. c.audio = core.NewReceiver(media, codec)
  203. c.Receivers = append(c.Receivers, c.audio)
  204. }
  205. //func (c *Client) MarshalJSON() ([]byte, error) {
  206. // info := &core.Info{
  207. // Type: "DVRIP active producer",
  208. // RemoteAddr: c.conn.RemoteAddr().String(),
  209. // Medias: c.Medias,
  210. // Receivers: c.Receivers,
  211. // Recv: c.Recv,
  212. // }
  213. // return json.Marshal(info)
  214. //}