hls.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package record
  2. import (
  3. "fmt"
  4. "math"
  5. "path/filepath"
  6. "time"
  7. "go.uber.org/zap"
  8. . "m7s.live/engine/v4"
  9. "m7s.live/engine/v4/codec"
  10. "m7s.live/engine/v4/codec/mpegts"
  11. "m7s.live/engine/v4/util"
  12. "m7s.live/plugin/hls/v4"
  13. )
  14. type HLSRecorder struct {
  15. playlist hls.Playlist
  16. tsStartTime uint32
  17. tsLastTime uint32
  18. tsTitle string
  19. video_cc, audio_cc byte
  20. Recorder
  21. MemoryTs
  22. }
  23. func NewHLSRecorder() (r *HLSRecorder) {
  24. r = &HLSRecorder{}
  25. r.Record = RecordPluginConfig.Hls
  26. return r
  27. }
  28. func (h *HLSRecorder) Start(streamPath string) error {
  29. fmt.Println("start hls record:",streamPath + "/hls")
  30. h.ID = streamPath + "/hls"
  31. return h.start(h, streamPath, SUBTYPE_RAW)
  32. }
  33. func (r *HLSRecorder) Close() (err error) {
  34. if r.File != nil {
  35. inf := hls.PlaylistInf{
  36. Duration: float64(r.tsLastTime-r.tsStartTime) / 1000,
  37. Title: r.tsTitle,
  38. }
  39. r.playlist.WriteInf(inf)
  40. r.tsStartTime = 0
  41. err = r.File.Close()
  42. }
  43. return
  44. }
  45. func (h *HLSRecorder) OnEvent(event any) {
  46. var err error
  47. defer func() {
  48. if err != nil {
  49. h.Stop(zap.Error(err))
  50. }
  51. }()
  52. switch v := event.(type) {
  53. case *HLSRecorder:
  54. h.BytesPool = make(util.BytesPool, 17)
  55. if h.Writer, err = h.Recorder.CreateFile(); err != nil {
  56. return
  57. }
  58. h.SetIO(h.Writer)
  59. h.playlist = hls.Playlist{
  60. Writer: h.Writer,
  61. Version: 3,
  62. Sequence: 0,
  63. Targetduration: int(math.Ceil(h.Fragment.Seconds())),
  64. }
  65. if err = h.playlist.Init(); err != nil {
  66. return
  67. }
  68. if h.File, err = h.CreateFile(); err != nil {
  69. return
  70. }
  71. case AudioFrame:
  72. if h.tsStartTime == 0 {
  73. h.tsStartTime = v.AbsTime
  74. }
  75. h.tsLastTime = v.AbsTime
  76. h.Recorder.OnEvent(event)
  77. pes := &mpegts.MpegtsPESFrame{
  78. Pid: mpegts.PID_AUDIO,
  79. IsKeyFrame: false,
  80. ContinuityCounter: h.audio_cc,
  81. ProgramClockReferenceBase: uint64(v.DTS),
  82. }
  83. h.WriteAudioFrame(v, pes)
  84. _, err = h.BLL.WriteTo(h.File)
  85. h.Recycle()
  86. h.Clear()
  87. h.audio_cc = pes.ContinuityCounter
  88. case VideoFrame:
  89. if h.tsStartTime == 0 {
  90. h.tsStartTime = v.AbsTime
  91. }
  92. h.tsLastTime = v.AbsTime
  93. h.Recorder.OnEvent(event)
  94. pes := &mpegts.MpegtsPESFrame{
  95. Pid: mpegts.PID_VIDEO,
  96. IsKeyFrame: v.IFrame,
  97. ContinuityCounter: h.video_cc,
  98. ProgramClockReferenceBase: uint64(v.DTS),
  99. }
  100. if err = h.WriteVideoFrame(v, pes); err != nil {
  101. return
  102. }
  103. _, err = h.BLL.WriteTo(h.File)
  104. h.Recycle()
  105. h.Clear()
  106. h.video_cc = pes.ContinuityCounter
  107. default:
  108. h.Recorder.OnEvent(v)
  109. }
  110. }
  111. // 创建一个新的ts文件
  112. func (h *HLSRecorder) CreateFile() (fw FileWr, err error) {
  113. h.tsTitle = fmt.Sprintf("%d.ts", time.Now().Unix())
  114. filePath := filepath.Join(h.Stream.Path, h.tsTitle)
  115. fw, err = h.CreateFileFn(filePath, false)
  116. if err != nil {
  117. h.Error("create file", zap.String("path", filePath), zap.Error(err))
  118. return
  119. }
  120. h.Info("create file", zap.String("path", filePath))
  121. /*if err = mpegts.WriteDefaultPATPacket(fw); err != nil {
  122. return
  123. }*/
  124. var vcodec codec.VideoCodecID = 0
  125. var acodec codec.AudioCodecID = 0
  126. if h.Video != nil {
  127. vcodec = h.Video.CodecID
  128. }
  129. if h.Audio != nil {
  130. acodec = h.Audio.CodecID
  131. }
  132. mpegts.WritePMTPacket(fw, vcodec, acodec)
  133. return
  134. }