From 8f33e9b802c478abdbe56e2bd962472a84e9846b Mon Sep 17 00:00:00 2001 From: langhuihui <178529795@qq.com> Date: Sun, 13 Aug 2023 14:54:07 +0800 Subject: [PATCH] fix: fmp4 record error --- README.md | 4 ++-- fmp4.go | 24 ++++++++++++------------ hls.go | 7 ++++++- raw.go | 7 ++++++- restful.go | 21 ++++++++++++--------- subscriber.go | 13 +++++-------- 6 files changed, 43 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 8182764..0950bc3 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ import ( - 配置中的path 表示要保存的文件的根路径,可以使用相对路径或者绝对路径 - filter 代表要过滤的StreamPath正则表达式,如果不匹配,则表示不录制。为空代表不进行过滤 -- fragment表示分片大小(秒),0代表不分片 +- fragment表示分片大小(20s代表20秒,1m代表1分钟,可以组合),0代表不分片 ```yaml record: @@ -51,7 +51,7 @@ record: - `/record/api/list/recording` 罗列所有正在录制中的流的信息 - `/record/api/list?type=[flv|mp4|hls|raw]` 罗列所有录制的flv|mp4|m3u8|raw文件 -- `/record/api/start?type=flv&streamPath=live/rtc&fileName=xxx&fragment=10s` 开始录制某个流,返回一个字符串用于停止录制用的id(fileName是可选的,且只用于非切片情况,fragment用于覆盖配置中的切片时间,是可选的) +- `/record/api/start?type=flv&streamPath=live/rtc&fileName=xxx&fragment=10s` 开始录制某个流,返回一个字符串用于停止录制用的id(fileName是可选的,且只用于非切片情况,fragment用于覆盖配置中的切片时间,是可选的,如果fileName和fragment都存在,则忽略fileName) - `/record/api/stop?id=xxx` 停止录制某个流 ## 点播功能 diff --git a/fmp4.go b/fmp4.go index 724c2c3..7c985e7 100644 --- a/fmp4.go +++ b/fmp4.go @@ -15,7 +15,7 @@ type mediaContext struct { func (m *mediaContext) push(recoder *FMP4Recorder, dt uint32, dur uint32, data []byte, flags uint32) { if m.fragment != nil && dt-m.ts > 1000 { - m.fragment.Encode(recoder) + m.fragment.Encode(recoder.File) m.fragment = nil } if m.fragment == nil { @@ -36,11 +36,11 @@ func (m *mediaContext) push(recoder *FMP4Recorder, dt uint32, dur uint32, data [ type FMP4Recorder struct { Recorder - *mp4.InitSegment `json:"-" yaml:"-"` - video mediaContext - audio mediaContext - seqNumber uint32 - ftyp *mp4.FtypBox + initSegment *mp4.InitSegment `json:"-" yaml:"-"` + video mediaContext + audio mediaContext + seqNumber uint32 + ftyp *mp4.FtypBox } func NewFMP4Recorder() *FMP4Recorder { @@ -73,10 +73,10 @@ func (r *FMP4Recorder) OnEvent(event any) { r.Recorder.OnEvent(event) switch v := event.(type) { case FileWr: - r.InitSegment = mp4.CreateEmptyInit() - r.Moov.Mvhd.NextTrackID = 1 + r.initSegment = mp4.CreateEmptyInit() + r.initSegment.Moov.Mvhd.NextTrackID = 1 if r.VideoReader != nil { - moov := r.Moov + moov := r.initSegment.Moov trackID := moov.Mvhd.NextTrackID moov.Mvhd.NextTrackID++ newTrak := mp4.CreateEmptyTrak(trackID, 1000, "video", "chi") @@ -97,7 +97,7 @@ func (r *FMP4Recorder) OnEvent(event any) { } } if r.AudioReader != nil { - moov := r.Moov + moov := r.initSegment.Moov trackID := moov.Mvhd.NextTrackID moov.Mvhd.NextTrackID++ newTrak := mp4.CreateEmptyTrak(trackID, 1000, "audio", "chi") @@ -128,8 +128,8 @@ func (r *FMP4Recorder) OnEvent(event any) { stsd.AddChild(pcmu) } } - r.ftyp.Encode(r) - r.Moov.Encode(r) + r.ftyp.Encode(v) + r.initSegment.Moov.Encode(v) r.seqNumber = 0 case AudioFrame: if r.audio.trackId != 0 { diff --git a/hls.go b/hls.go index d3862ba..2f7fb55 100644 --- a/hls.go +++ b/hls.go @@ -32,7 +32,12 @@ func (h *HLSRecorder) Start(streamPath string) error { h.ID = streamPath + "/hls" return h.start(h, streamPath, SUBTYPE_RAW) } - +func (r *HLSRecorder) Close() (err error) { + if r.File != nil { + err = r.File.Close() + } + return +} func (h *HLSRecorder) OnEvent(event any) { var err error defer func() { diff --git a/raw.go b/raw.go index e97d1d2..322b501 100644 --- a/raw.go +++ b/raw.go @@ -30,7 +30,12 @@ func (r *RawRecorder) Start(streamPath string) error { } return r.start(r, streamPath, SUBTYPE_RAW) } - +func (r *RawRecorder) Close() (err error) { + if r.File != nil { + err = r.File.Close() + } + return +} func (r *RawRecorder) OnEvent(event any) { switch v := event.(type) { case FileWr: diff --git a/restful.go b/restful.go index 7ccdfb9..e74cf01 100644 --- a/restful.go +++ b/restful.go @@ -2,10 +2,10 @@ package record import ( "encoding/json" - "fmt" "net/http" "time" + "go.uber.org/zap" . "m7s.live/engine/v4" "m7s.live/engine/v4/util" ) @@ -74,34 +74,37 @@ func (conf *RecordConfig) API_start(w http.ResponseWriter, r *http.Request) { } recorder := irecorder.GetRecorder() if fragment != "" { - recorder.Fragment, err = time.ParseDuration(fragment) + f, err := time.ParseDuration(fragment) + if err != nil { + recorder.Fragment = f + } } recorder.FileName = fileName recorder.append = query.Get("append") != "" err = irecorder.Start(streamPath) id = recorder.ID if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + util.ReturnError(util.APIErrorInternal, err.Error(), w, r) return } - fmt.Fprintf(w, id) + util.ReturnError(util.APIErrorNone, id, w, r) } func (conf *RecordConfig) API_list_recording(w http.ResponseWriter, r *http.Request) { - util.ReturnJson(func() (recordings []any) { + util.ReturnFetchValue(func() (recordings []any) { conf.recordings.Range(func(key, value any) bool { recordings = append(recordings, value) return true }) return - }, time.Second, w, r) + }, w, r) } func (conf *RecordConfig) API_stop(w http.ResponseWriter, r *http.Request) { if recorder, ok := conf.recordings.Load(r.URL.Query().Get("id")); ok { - recorder.(ISubscriber).Stop() - w.Write([]byte("ok")) + recorder.(ISubscriber).Stop(zap.String("reason", "api")) + util.ReturnOK(w, r) return } - http.Error(w, "no such recorder", http.StatusBadRequest) + util.ReturnError(util.APIErrorNotFound, "no such recorder", w, r) } diff --git a/subscriber.go b/subscriber.go index 2ea292d..29d122c 100644 --- a/subscriber.go +++ b/subscriber.go @@ -35,13 +35,6 @@ func (r *Recorder) CreateFile() (FileWr, error) { return r.createFile() } -func (r *Recorder) Close() error { - if r.File != nil { - return r.File.Close() - } - return nil -} - func (r *Recorder) createFile() (f FileWr, err error) { filePath := r.getFileName(r.Stream.Path) + r.Ext f, err = r.CreateFileFn(filePath, r.append) @@ -77,7 +70,6 @@ func (r *Recorder) start(re IRecorder, streamPath string, subType byte) (err err r.PlayBlock(subType) RecordPluginConfig.recordings.Delete(r.ID) delete(r.recording, streamPath) - re.Close() }() } return @@ -96,6 +88,11 @@ func (r *Recorder) cut(absTime uint32) { } } +// 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: