package record import ( "bufio" "io" "path/filepath" "strconv" "time" //"fmt" "go.uber.org/zap" . "m7s.live/engine/v4" ) type IRecorder interface { ISubscriber GetRecorder() *Recorder Start(streamPath string) error io.Closer CreateFile() (FileWr, error) } type Recorder struct { Subscriber SkipTS uint32 Record `json:"-" yaml:"-"` File FileWr `json:"-" yaml:"-"` FileName string // 自定义文件名,分段录像无效 filePath string // 文件路径 append bool // 是否追加模式 } func (r *Recorder) GetRecorder() *Recorder { return r } func (r *Recorder) CreateFile() (f FileWr, err error) { //fmt.Println("00000000000000000000 CREATE FILE:",r.Stream.Path) r.filePath = r.getFileName(r.Stream.Path) + r.Ext f, err = r.CreateFileFn(r.filePath, r.append) logFields := []zap.Field{zap.String("path", r.filePath)} if fw, ok := f.(*FileWriter); ok && r.Config != nil { if r.Config.WriteBufferSize > 0 { logFields = append(logFields, zap.Int("bufferSize", r.Config.WriteBufferSize)) fw.bufw = bufio.NewWriterSize(fw.Writer, r.Config.WriteBufferSize) fw.Writer = fw.bufw } } if err == nil { r.Info("create file", logFields...) } else { logFields = append(logFields, zap.Error(err)) r.Error("create file", logFields...) } return } func (r *Recorder) getFileName(streamPath string) (filename string) { filename = streamPath if r.Fragment == 0 { if r.FileName != "" { filename = filepath.Join(filename, r.FileName) } } else { filename = filepath.Join(filename, strconv.FormatInt(time.Now().Unix(), 10)) } return } func (r *Recorder) start(re IRecorder, streamPath string, subType byte) (err error) { //fmt.Println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSS") err = plugin.Subscribe(streamPath, re) //fmt.Println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSS:",err) if err == nil { if _, loaded := RecordPluginConfig.recordings.LoadOrStore(r.ID, re); loaded { //fmt.Println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSS:",ErrRecordExist) return ErrRecordExist } r.Closer = re go func() { //fmt.Println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSS play block:") r.PlayBlock(subType) RecordPluginConfig.recordings.Delete(r.ID) }() } return } func (r *Recorder) cut(absTime uint32) { if ts := absTime - r.SkipTS; time.Duration(ts)*time.Millisecond >= r.Fragment { //fmt.Println("111111111111111111 cut new file:",absTime,r.Fragment) r.SkipTS = absTime r.Close() if file, err := r.Spesific.(IRecorder).CreateFile(); err == nil { r.File = file r.Spesific.OnEvent(file) } else { r.Stop(zap.Error(err)) } } } // func (r *Recorder) Stop(reason ...zap.Field) { // r.Close() // r.Subscriber.Stop(reason...) // } func (r *Recorder) OnEvent(event any) { switch v := event.(type) { case IRecorder: //fmt.Println("ONENVET IRecorder 111111111111111111111111111:", *r) if file, err := r.Spesific.(IRecorder).CreateFile(); err == nil { r.File = file r.Spesific.OnEvent(file) } else { r.Stop(zap.Error(err)) } case AudioFrame: // 纯音频流的情况下需要切割文件 if r.Fragment > 0 && r.VideoReader == nil { r.cut(v.AbsTime) } case VideoFrame: //.Println("record on video frame aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:") if r.Fragment > 0 && v.IFrame { //fmt.Println("ONENVET CUT 111111111111111111111111111:",r.Fragment,v.IFrame,"rrrrrrrrrrr:",*r ) r.cut(v.AbsTime) } default: r.Subscriber.OnEvent(event) } }