hls.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package record
  2. import (
  3. "math"
  4. "path/filepath"
  5. "strconv"
  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. video_cc, audio_cc byte
  17. packet mpegts.MpegTsPESPacket
  18. Recorder
  19. MemoryTs
  20. }
  21. func (h *HLSRecorder) Start(streamPath string) error {
  22. h.Record = &RecordPluginConfig.Hls
  23. h.ID = streamPath + "/hls"
  24. if _, ok := RecordPluginConfig.recordings.Load(h.ID); ok {
  25. return ErrRecordExist
  26. }
  27. h.BytesPool = make(util.BytesPool, 17)
  28. return plugin.Subscribe(streamPath, h)
  29. }
  30. func (h *HLSRecorder) OnEvent(event any) {
  31. var err error
  32. defer func() {
  33. if err != nil {
  34. h.Error("HLSRecorder Stop", zap.Error(err))
  35. h.Stop()
  36. }
  37. }()
  38. h.Recorder.OnEvent(event)
  39. switch v := event.(type) {
  40. case *HLSRecorder:
  41. h.playlist = hls.Playlist{
  42. Writer: h.Writer,
  43. Version: 3,
  44. Sequence: 0,
  45. Targetduration: int(math.Ceil(h.Fragment.Seconds())),
  46. }
  47. if err = h.playlist.Init(); err != nil {
  48. return
  49. }
  50. if err = h.createHlsTsSegmentFile(); err != nil {
  51. h.Stop()
  52. return
  53. }
  54. go h.start()
  55. case AudioFrame:
  56. pes := &mpegts.MpegtsPESFrame{
  57. Pid: mpegts.PID_AUDIO,
  58. IsKeyFrame: false,
  59. ContinuityCounter: h.audio_cc,
  60. ProgramClockReferenceBase: uint64(v.DTS),
  61. }
  62. h.WriteAudioFrame(v, pes)
  63. h.BLL.WriteTo(h)
  64. h.Recycle()
  65. h.Clear()
  66. h.audio_cc = pes.ContinuityCounter
  67. case VideoFrame:
  68. if h.Fragment != 0 && h.newFile {
  69. h.newFile = false
  70. h.Close()
  71. if err = h.createHlsTsSegmentFile(); err != nil {
  72. return
  73. }
  74. }
  75. pes := &mpegts.MpegtsPESFrame{
  76. Pid: mpegts.PID_VIDEO,
  77. IsKeyFrame: v.IFrame,
  78. ContinuityCounter: h.video_cc,
  79. ProgramClockReferenceBase: uint64(v.DTS),
  80. }
  81. if err = h.WriteVideoFrame(v, pes); err != nil {
  82. return
  83. }
  84. h.BLL.WriteTo(h)
  85. h.Recycle()
  86. h.Clear()
  87. h.video_cc = pes.ContinuityCounter
  88. }
  89. }
  90. // 创建一个新的ts文件
  91. func (h *HLSRecorder) createHlsTsSegmentFile() (err error) {
  92. tsFilename := strconv.FormatInt(time.Now().Unix(), 10) + ".ts"
  93. fw, err := h.CreateFileFn(filepath.Join(h.Stream.Path, tsFilename), false)
  94. if err != nil {
  95. return err
  96. }
  97. h.SetIO(fw)
  98. inf := hls.PlaylistInf{
  99. Duration: h.Fragment.Seconds(),
  100. Title: tsFilename,
  101. }
  102. if err = h.playlist.WriteInf(inf); err != nil {
  103. return
  104. }
  105. if err = mpegts.WriteDefaultPATPacket(fw); err != nil {
  106. return err
  107. }
  108. var vcodec codec.VideoCodecID = 0
  109. var acodec codec.AudioCodecID = 0
  110. if h.Video != nil {
  111. vcodec = h.Video.CodecID
  112. }
  113. if h.Audio != nil {
  114. acodec = h.Audio.CodecID
  115. }
  116. mpegts.WritePMTPacket(fw, vcodec, acodec)
  117. return err
  118. }