main.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package record
  2. import (
  3. _ "embed"
  4. "errors"
  5. "io"
  6. "sync"
  7. . "m7s.live/engine/v4"
  8. "m7s.live/engine/v4/codec"
  9. "m7s.live/engine/v4/config"
  10. "m7s.live/engine/v4/util"
  11. )
  12. type RecordConfig struct {
  13. DefaultYaml
  14. config.Subscribe
  15. Flv Record
  16. Mp4 Record
  17. Hls Record
  18. Raw Record
  19. RawAudio Record
  20. recordings sync.Map
  21. }
  22. //go:embed default.yaml
  23. var defaultYaml DefaultYaml
  24. var ErrRecordExist = errors.New("recorder exist")
  25. var RecordPluginConfig = &RecordConfig{
  26. DefaultYaml: defaultYaml,
  27. Flv: Record{
  28. Path: "record/flv",
  29. Ext: ".flv",
  30. GetDurationFn: getFLVDuration,
  31. },
  32. Mp4: Record{
  33. Path: "record/mp4",
  34. Ext: ".mp4",
  35. },
  36. Hls: Record{
  37. Path: "record/hls",
  38. Ext: ".m3u8",
  39. },
  40. Raw: Record{
  41. Path: "record/raw",
  42. Ext: ".", // 默认h264扩展名为.h264,h265扩展名为.h265
  43. },
  44. RawAudio: Record{
  45. Path: "record/raw",
  46. Ext: ".", // 默认aac扩展名为.aac,pcma扩展名为.pcma,pcmu扩展名为.pcmu
  47. },
  48. }
  49. var plugin = InstallPlugin(RecordPluginConfig)
  50. func (conf *RecordConfig) OnEvent(event any) {
  51. switch v := event.(type) {
  52. case FirstConfig, config.Config:
  53. conf.Flv.Init()
  54. conf.Mp4.Init()
  55. conf.Hls.Init()
  56. conf.Raw.Init()
  57. conf.RawAudio.Init()
  58. case SEclose:
  59. streamPath := v.Target.Path
  60. delete(conf.Flv.recording, streamPath)
  61. delete(conf.Mp4.recording, streamPath)
  62. delete(conf.Hls.recording, streamPath)
  63. delete(conf.Raw.recording, streamPath)
  64. delete(conf.RawAudio.recording, streamPath)
  65. case SEpublish:
  66. streamPath := v.Target.Path
  67. if conf.Flv.NeedRecord(streamPath) {
  68. var flv FLVRecorder
  69. conf.Flv.recording[streamPath] = &flv
  70. go flv.Start(streamPath)
  71. }
  72. if conf.Mp4.NeedRecord(streamPath) {
  73. recoder := NewMP4Recorder()
  74. conf.Mp4.recording[streamPath] = recoder
  75. go recoder.Start(streamPath)
  76. }
  77. if conf.Hls.NeedRecord(streamPath) {
  78. var hls HLSRecorder
  79. conf.Hls.recording[streamPath] = &hls
  80. go hls.Start(streamPath)
  81. }
  82. if conf.Raw.NeedRecord(streamPath) {
  83. var raw RawRecorder
  84. conf.Raw.recording[streamPath] = &raw
  85. go raw.Start(streamPath)
  86. }
  87. if conf.RawAudio.NeedRecord(streamPath) {
  88. var raw RawRecorder
  89. raw.IsAudio = true
  90. conf.RawAudio.recording[streamPath] = &raw
  91. go raw.Start(streamPath)
  92. }
  93. }
  94. }
  95. func (conf *RecordConfig) getRecorderConfigByType(t string) (recorder *Record) {
  96. switch t {
  97. case "flv":
  98. recorder = &conf.Flv
  99. case "mp4":
  100. recorder = &conf.Mp4
  101. case "hls":
  102. recorder = &conf.Hls
  103. case "raw":
  104. recorder = &conf.Raw
  105. case "raw_audio":
  106. recorder = &conf.RawAudio
  107. }
  108. return
  109. }
  110. func getFLVDuration(file io.ReadSeeker) uint32 {
  111. _, err := file.Seek(-4, io.SeekEnd)
  112. if err == nil {
  113. var tagSize uint32
  114. if tagSize, err = util.ReadByteToUint32(file, true); err == nil {
  115. _, err = file.Seek(-int64(tagSize)-4, io.SeekEnd)
  116. if err == nil {
  117. _, timestamp, _, err := codec.ReadFLVTag(file)
  118. if err == nil {
  119. return timestamp
  120. }
  121. }
  122. }
  123. }
  124. return 0
  125. }