mp4.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package record
  2. import (
  3. "net"
  4. //"fmt"
  5. "os"
  6. "time"
  7. "os/exec"
  8. "strconv"
  9. "strings"
  10. //"runtime"
  11. //"runtime/debug"
  12. "github.com/yapingcat/gomedia/go-mp4"
  13. "go.uber.org/zap"
  14. . "m7s.live/engine/v4"
  15. "m7s.live/engine/v4/codec"
  16. "m7s.live/engine/v4/util"
  17. "m7s.live/engine/v4/db"
  18. )
  19. type MP4Recorder struct {
  20. Recorder
  21. *mp4.Movmuxer `json:"-" yaml:"-"`
  22. videoId uint32
  23. audioId uint32
  24. startTime uint32
  25. lastTime uint32
  26. //recognitionId string
  27. }
  28. type RecordVideo struct{
  29. Id int64 `gorm:"primary_key" json:"id"`
  30. ChannelId string `json:"channel_id"`
  31. //VedioAddr string `json:"vedio_addr"`
  32. //VedioName string `json:"vedio_name"`
  33. StartTime int64 `json:"start_time"`
  34. EndTime int64 `json:"end_time"`
  35. Duration float64
  36. CreatedAt int64 `json:"created_at"`
  37. UpdatedAt int64 `json:"updated_at"`
  38. }
  39. func (RecordVideo) TableName() string {
  40. return "t_sdp_record_video"
  41. }
  42. func NewMP4Recorder() *MP4Recorder {
  43. r := &MP4Recorder{}
  44. //EngineConfig
  45. r.Record = RecordPluginConfig.Mp4
  46. return r
  47. }
  48. func (r *MP4Recorder) Start(streamPath string) (err error) {
  49. //fmt.Println("START MP4Recorder111111111111111111111111111111 :",streamPath)
  50. r.ID = streamPath + "/mp4"
  51. //fmt.Println("rrrrrrrrrrrrrr:",*r)
  52. return r.start(r, streamPath, SUBTYPE_RAW)
  53. }
  54. func uploadFile(filePath string,startTimeAbs,endTimeAbs uint32){
  55. filePath = strings.Replace(filePath,`\`,`/`,-1)
  56. inputFile := RecordPluginConfig.Mp4.Path+"/"+filePath
  57. outputFile := strings.Replace(inputFile,".mp4",".ts",-1)
  58. cmd := exec.Command(RecordPluginConfig.Ffmpeg, "-i", inputFile,"-bsf:v", "h264_mp4toannexb", "-c:v", "copy", "-c:a", "copy", outputFile)
  59. cmd.Stdout = os.Stdout
  60. cmd.Stderr = os.Stderr
  61. err := cmd.Run()
  62. if err != nil {
  63. plugin.Error("ffmpeg转换mp4出错",zap.String("inputFile",inputFile),zap.String("error",err.Error()))
  64. return
  65. }
  66. outputList := strings.Split(outputFile,"/")
  67. outputLen := len(outputList)
  68. if outputLen < 2{
  69. plugin.Error("录播文件地址不合规定",zap.String("inputFile",inputFile),zap.String("outputFile",outputFile))
  70. return
  71. }
  72. outPutfileName := outputList[outputLen-1]
  73. channleId := outputList[outputLen-2]
  74. _ ,err = UploadOss(outputFile,channleId+"/"+outPutfileName)
  75. if err==nil{
  76. os.Remove(inputFile)
  77. os.Remove(outputFile)
  78. database := db.DB()
  79. recordVideo := RecordVideo{}
  80. // 从/倒数第二个
  81. recordVideo.ChannelId = channleId
  82. trimmedStr := strings.TrimSuffix(outPutfileName, ".ts")
  83. startTime,_ := strconv.Atoi(trimmedStr)
  84. recordVideo.StartTime = int64(startTime)
  85. recordVideo.Duration = float64(endTimeAbs-startTimeAbs) / 1000
  86. recordVideo.EndTime = recordVideo.StartTime + int64(recordVideo.Duration)
  87. nowTime := time.Now().Unix()
  88. recordVideo.CreatedAt = nowTime
  89. recordVideo.UpdatedAt = nowTime
  90. err = database.Create(&recordVideo).Error
  91. if err != nil{
  92. plugin.Error("插入视频地址文件失败",zap.String("err",err.Error()),zap.Any("recordVideo",recordVideo))
  93. }
  94. }else{
  95. plugin.Error("上传视频文件失败",zap.String("err",err.Error()),zap.Any("outputFile",outputFile))
  96. }
  97. }
  98. func (r *MP4Recorder) Close() (err error) {
  99. //fmt.Println("close :1111111111111111111111111111111111111",*r)
  100. //printCallStack()
  101. if r.File != nil {
  102. err = r.Movmuxer.WriteTrailer()
  103. if err != nil {
  104. r.Error("mp4 write trailer", zap.Error(err))
  105. } else {
  106. // _, err = r.file.Write(r.cache.buf)
  107. r.Info("mp4 write trailer", zap.Error(err))
  108. }
  109. // 转码上传文件
  110. //fmt.Println("fileName:",r.FileName)
  111. go uploadFile(r.filePath,r.startTime,r.lastTime)
  112. r.startTime = 0
  113. err = r.File.Close()
  114. }
  115. return
  116. }
  117. func (r *MP4Recorder) setTracks() {
  118. if r.Audio != nil {
  119. switch r.Audio.CodecID {
  120. case codec.CodecID_AAC:
  121. r.audioId = r.AddAudioTrack(mp4.MP4_CODEC_AAC, mp4.WithExtraData(r.Audio.SequenceHead[2:]))
  122. case codec.CodecID_PCMA:
  123. r.audioId = r.AddAudioTrack(mp4.MP4_CODEC_G711A)
  124. case codec.CodecID_PCMU:
  125. r.audioId = r.AddAudioTrack(mp4.MP4_CODEC_G711U)
  126. }
  127. }
  128. if r.Video != nil {
  129. switch r.Video.CodecID {
  130. case codec.CodecID_H264:
  131. r.videoId = r.AddVideoTrack(mp4.MP4_CODEC_H264, mp4.WithExtraData(r.Video.SequenceHead[5:]))
  132. case codec.CodecID_H265:
  133. r.videoId = r.AddVideoTrack(mp4.MP4_CODEC_H265, mp4.WithExtraData(r.Video.SequenceHead[5:]))
  134. }
  135. }
  136. }
  137. func (r *MP4Recorder) OnEvent(event any) {
  138. var err error
  139. r.Recorder.OnEvent(event)
  140. switch v := event.(type) {
  141. //case IRecorder:
  142. //fmt.Println("MP4 REDORCE IRECORD XDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD:")
  143. case FileWr:
  144. //fmt.Println("CREATE MOVEMUXER00000000000000000000")
  145. r.Movmuxer, err = mp4.CreateMp4Muxer(v)
  146. if err != nil {
  147. r.Error("mp4 create muxer", zap.Error(err))
  148. } else {
  149. r.setTracks()
  150. }
  151. case AudioFrame:
  152. if r.audioId != 0 {
  153. if r.startTime == 0 {
  154. r.startTime = v.AbsTime
  155. }
  156. r.lastTime = v.AbsTime
  157. var audioData []byte
  158. if v.ADTS == nil {
  159. audioData = v.AUList.ToBytes()
  160. } else {
  161. audioData = util.ConcatBuffers(append(net.Buffers{v.ADTS.Value}, v.AUList.ToBuffers()...))
  162. }
  163. if err = r.Write(r.audioId, audioData, uint64(v.AbsTime+(v.PTS-v.DTS)/90), uint64(v.AbsTime)); err != nil {
  164. r.Stop(zap.Error(err))
  165. }
  166. }
  167. case VideoFrame:
  168. if r.videoId != 0 {
  169. if r.startTime == 0 {
  170. r.startTime = v.AbsTime
  171. }
  172. r.lastTime = v.AbsTime
  173. //fmt.Println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",r.videoId)
  174. if err = r.Write(r.videoId, util.ConcatBuffers(v.GetAnnexB()), uint64(v.AbsTime+(v.PTS-v.DTS)/90), uint64(v.AbsTime)); err != nil {
  175. r.Stop(zap.Error(err))
  176. }
  177. }
  178. }
  179. }