123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- package record
- import (
- "net"
- //"fmt"
- "os"
- "time"
- "os/exec"
- "strconv"
- "strings"
- //"runtime"
- //"runtime/debug"
- "github.com/yapingcat/gomedia/go-mp4"
- "go.uber.org/zap"
- . "m7s.live/engine/v4"
- "m7s.live/engine/v4/codec"
- "m7s.live/engine/v4/util"
- "m7s.live/engine/v4/db"
- )
- type MP4Recorder struct {
- Recorder
- *mp4.Movmuxer `json:"-" yaml:"-"`
- videoId uint32
- audioId uint32
- startTime uint32
- lastTime uint32
- //recognitionId string
- }
- type RecordVideo struct{
- Id int64 `gorm:"primary_key" json:"id"`
- ChannelId string `json:"channel_id"`
- //VedioAddr string `json:"vedio_addr"`
- //VedioName string `json:"vedio_name"`
- StartTime int64 `json:"start_time"`
- EndTime int64 `json:"end_time"`
- Duration float64
- CreatedAt int64 `json:"created_at"`
- UpdatedAt int64 `json:"updated_at"`
- }
- func (RecordVideo) TableName() string {
- return "t_sdp_record_video"
- }
- func NewMP4Recorder() *MP4Recorder {
- r := &MP4Recorder{}
- //EngineConfig
- r.Record = RecordPluginConfig.Mp4
- return r
- }
- func (r *MP4Recorder) Start(streamPath string) (err error) {
- //fmt.Println("START MP4Recorder111111111111111111111111111111 :",streamPath)
- r.ID = streamPath + "/mp4"
- //fmt.Println("rrrrrrrrrrrrrr:",*r)
- return r.start(r, streamPath, SUBTYPE_RAW)
- }
- func uploadFile(filePath string,startTimeAbs,endTimeAbs uint32){
- filePath = strings.Replace(filePath,`\`,`/`,-1)
- inputFile := RecordPluginConfig.Mp4.Path+"/"+filePath
- outputFile := strings.Replace(inputFile,".mp4",".ts",-1)
- cmd := exec.Command(RecordPluginConfig.Ffmpeg, "-i", inputFile,"-bsf:v", "h264_mp4toannexb", "-c:v", "copy", "-c:a", "copy", outputFile)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- err := cmd.Run()
- if err != nil {
- plugin.Error("ffmpeg转换mp4出错",zap.String("inputFile",inputFile),zap.String("error",err.Error()))
- return
- }
- outputList := strings.Split(outputFile,"/")
- outputLen := len(outputList)
- if outputLen < 2{
- plugin.Error("录播文件地址不合规定",zap.String("inputFile",inputFile),zap.String("outputFile",outputFile))
- return
- }
- outPutfileName := outputList[outputLen-1]
- channleId := outputList[outputLen-2]
- _ ,err = UploadOss(outputFile,channleId+"/"+outPutfileName)
- if err==nil{
- os.Remove(inputFile)
- os.Remove(outputFile)
- database := db.DB()
- recordVideo := RecordVideo{}
- // 从/倒数第二个
- recordVideo.ChannelId = channleId
- trimmedStr := strings.TrimSuffix(outPutfileName, ".ts")
- startTime,_ := strconv.Atoi(trimmedStr)
- recordVideo.StartTime = int64(startTime)
- recordVideo.Duration = float64(endTimeAbs-startTimeAbs) / 1000
- recordVideo.EndTime = recordVideo.StartTime + int64(recordVideo.Duration)
- nowTime := time.Now().Unix()
- recordVideo.CreatedAt = nowTime
- recordVideo.UpdatedAt = nowTime
- err = database.Create(&recordVideo).Error
- if err != nil{
- plugin.Error("插入视频地址文件失败",zap.String("err",err.Error()),zap.Any("recordVideo",recordVideo))
- }
- }else{
- plugin.Error("上传视频文件失败",zap.String("err",err.Error()),zap.Any("outputFile",outputFile))
- }
- }
- func (r *MP4Recorder) Close() (err error) {
- //fmt.Println("close :1111111111111111111111111111111111111",*r)
- //printCallStack()
- if r.File != nil {
- err = r.Movmuxer.WriteTrailer()
- if err != nil {
- r.Error("mp4 write trailer", zap.Error(err))
- } else {
- // _, err = r.file.Write(r.cache.buf)
- r.Info("mp4 write trailer", zap.Error(err))
- }
- // 转码上传文件
- //fmt.Println("fileName:",r.FileName)
- go uploadFile(r.filePath,r.startTime,r.lastTime)
- r.startTime = 0
- err = r.File.Close()
- }
- return
- }
- func (r *MP4Recorder) setTracks() {
- if r.Audio != nil {
- switch r.Audio.CodecID {
- case codec.CodecID_AAC:
- r.audioId = r.AddAudioTrack(mp4.MP4_CODEC_AAC, mp4.WithExtraData(r.Audio.SequenceHead[2:]))
- case codec.CodecID_PCMA:
- r.audioId = r.AddAudioTrack(mp4.MP4_CODEC_G711A)
- case codec.CodecID_PCMU:
- r.audioId = r.AddAudioTrack(mp4.MP4_CODEC_G711U)
- }
- }
- if r.Video != nil {
- switch r.Video.CodecID {
- case codec.CodecID_H264:
- r.videoId = r.AddVideoTrack(mp4.MP4_CODEC_H264, mp4.WithExtraData(r.Video.SequenceHead[5:]))
- case codec.CodecID_H265:
- r.videoId = r.AddVideoTrack(mp4.MP4_CODEC_H265, mp4.WithExtraData(r.Video.SequenceHead[5:]))
- }
- }
- }
- func (r *MP4Recorder) OnEvent(event any) {
- var err error
- r.Recorder.OnEvent(event)
- switch v := event.(type) {
- //case IRecorder:
- //fmt.Println("MP4 REDORCE IRECORD XDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD:")
- case FileWr:
- //fmt.Println("CREATE MOVEMUXER00000000000000000000")
- r.Movmuxer, err = mp4.CreateMp4Muxer(v)
- if err != nil {
- r.Error("mp4 create muxer", zap.Error(err))
- } else {
- r.setTracks()
- }
- case AudioFrame:
- if r.audioId != 0 {
- if r.startTime == 0 {
- r.startTime = v.AbsTime
- }
- r.lastTime = v.AbsTime
- var audioData []byte
- if v.ADTS == nil {
- audioData = v.AUList.ToBytes()
- } else {
- audioData = util.ConcatBuffers(append(net.Buffers{v.ADTS.Value}, v.AUList.ToBuffers()...))
- }
- if err = r.Write(r.audioId, audioData, uint64(v.AbsTime+(v.PTS-v.DTS)/90), uint64(v.AbsTime)); err != nil {
- r.Stop(zap.Error(err))
- }
- }
- case VideoFrame:
- if r.videoId != 0 {
- if r.startTime == 0 {
- r.startTime = v.AbsTime
- }
- r.lastTime = v.AbsTime
- //fmt.Println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",r.videoId)
- if err = r.Write(r.videoId, util.ConcatBuffers(v.GetAnnexB()), uint64(v.AbsTime+(v.PTS-v.DTS)/90), uint64(v.AbsTime)); err != nil {
- r.Stop(zap.Error(err))
- }
- }
- }
- }
|