diff --git a/README.md b/README.md index f86d3fa..d72d5cf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # RECORD插件 -对流进行录制的功能插件,提供Flv、fmp4、hls格式的录制功能。 +对流进行录制的功能插件,提供Flv、fmp4、hls、裸流格式的录制功能。 ## 插件地址 @@ -43,6 +43,12 @@ record: autorecord: false filter: "" fragment: 0 + raw: + ext: . + path: ./raw + autorecord: false + filter: "" + fragment: 0 ``` ## API @@ -55,7 +61,7 @@ record: ## 点播功能 访问格式: - [http/https]://[host]:[port]/record/[streamPath].[flv/mp4] + [http/https]://[host]:[port]/record/[streamPath].[flv|mp4|m3u8|h264|h265] 例如: - `http://localhost:8080/record/live/test.flv` 将会读取对应的flv文件 diff --git a/go.mod b/go.mod index ddec819..9dfd55a 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,9 @@ go 1.18 require ( github.com/edgeware/mp4ff v0.27.0 - m7s.live/engine/v4 v4.0.0-beta1 + go.uber.org/zap v1.21.0 + m7s.live/engine/v4 v4.2.0 + m7s.live/plugin/hls/v4 v4.0.0-20220526032106-b2c401b1cbb5 ) require ( @@ -18,16 +20,16 @@ require ( github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtp/v2 v2.0.0-20220302185659-b3d10fc096b0 // indirect + github.com/pion/rtp v1.6.2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/q191201771/naza v0.19.1 // indirect + github.com/quangngotan95/go-m3u8 v0.1.0 // indirect github.com/shirou/gopsutil/v3 v3.22.1 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect github.com/tklauser/numcpus v0.3.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.21.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect diff --git a/go.sum b/go.sum index 70b6eba..4887966 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,7 @@ github.com/cnotch/queue v0.0.0-20200326024423-6e88bdbf2ad4/go.mod h1:zOssjAlNusO github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg= github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5/go.mod h1:F4GE3SZkJZ8an1Y0ZCqvSM3jeozNuKzoC67erG1PhIo= github.com/cnotch/xlog v0.0.0-20201208005456-cfda439cd3a0/go.mod h1:RW9oHsR79ffl3sR3yMGgxYupMn2btzdtJUwoxFPUE5E= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -42,6 +43,7 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -51,9 +53,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U= github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= -github.com/pion/rtp/v2 v2.0.0-20220302185659-b3d10fc096b0 h1:zyOGxHutZ6IhksQSMtwf3OFXB29W5R18yFQWOQJYWjU= -github.com/pion/rtp/v2 v2.0.0-20220302185659-b3d10fc096b0/go.mod h1:Vj+rrFbJCT3yxqE/VSwaOo9DQ2pMKGPxuE7hplGOlOs= github.com/pixelbender/go-sdp v1.1.0/go.mod h1:6IBlz9+BrUHoFTea7gcp4S54khtOhjCW/nVDLhmZBAs= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -63,6 +64,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/q191201771/naza v0.19.1 h1:4KLcxT2CHztO+7miPRtBG3FFgadSQYQw1gPPPKN7rnY= github.com/q191201771/naza v0.19.1/go.mod h1:5LeGupZZFtYP1g/S203n9vXoUNVdlRnPIfM6rExjqt0= +github.com/quangngotan95/go-m3u8 v0.1.0 h1:8oseBjJn5IKHQKdRZwSNskkua3NLrRtlvXXtoVgBzMk= +github.com/quangngotan95/go-m3u8 v0.1.0/go.mod h1:smzfWHlYpBATVNu1GapKLYiCtEo5JxridIgvvudZ+Wc= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/shirou/gopsutil/v3 v3.22.1 h1:33y31Q8J32+KstqPfscvFwBlNJ6xLaBy4xqBXzlYV5w= github.com/shirou/gopsutil/v3 v3.22.1/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY= @@ -141,5 +144,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -m7s.live/engine/v4 v4.0.0-beta1 h1:a7uVCoT2zxJGHSLjLWTmzgY/ptyCEjl3o4IAE1rBXy0= -m7s.live/engine/v4 v4.0.0-beta1/go.mod h1:Ez870pCfemZCUQQYP88jIHsgbRCb9ELjtCau14YTl7E= +m7s.live/engine/v4 v4.2.0 h1:8t19PmVHoiLxvfogs6pgh/MeEeYm4EBca8U1wmLFqR8= +m7s.live/engine/v4 v4.2.0/go.mod h1:rliHP5yJnSyr40ha6q8OhUResRn8fo26TxmmBbR2X4M= +m7s.live/plugin/hls/v4 v4.0.0-20220526032106-b2c401b1cbb5 h1:URhjSOLn5QQgVsuCpObtHljNJ5dFPDgD8FzLf5pijyg= +m7s.live/plugin/hls/v4 v4.0.0-20220526032106-b2c401b1cbb5/go.mod h1:Qn4dDz5xlyBJwO+eZ3w8CUQ8Hl6KN1nmv0a3IsOjJvw= diff --git a/main.go b/main.go index 4daa51b..08f9c5c 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ type RecordConfig struct { Flv Record Mp4 Record Hls Record + Raw Record recordings sync.Map } @@ -34,6 +35,10 @@ var recordConfig = &RecordConfig{ Path: "./hls", Ext: ".m3u8", }, + Raw :Record{ + Path: "./raw", + Ext: ".", // 默认h264扩展名为.h264,h265扩展名为.h265 + }, } var plugin = InstallPlugin(recordConfig) @@ -44,6 +49,7 @@ func (conf *RecordConfig) OnEvent(event any) { conf.Flv.Init() conf.Mp4.Init() conf.Hls.Init() + conf.Raw.Init() case SEpublish: if conf.Flv.NeedRecord(v.Stream.Path) { var flv FLVRecorder @@ -60,6 +66,11 @@ func (conf *RecordConfig) OnEvent(event any) { hls.Record = &conf.Hls plugin.Subscribe(v.Stream.Path, &hls) } + if conf.Raw.NeedRecord(v.Stream.Path) { + var raw RawRecorder + raw.Record = &conf.Raw + plugin.Subscribe(v.Stream.Path, &raw) + } } } @@ -74,6 +85,8 @@ func (conf *RecordConfig) API_list(w http.ResponseWriter, r *http.Request) { recorder = &conf.Mp4 case "hls": recorder = &conf.Hls + case "raw": + recorder = &conf.Raw } if recorder != nil { @@ -119,6 +132,11 @@ func (conf *RecordConfig) API_start(w http.ResponseWriter, r *http.Request) { recorder := &HLSRecorder{} recorder.Record = &conf.Hls sub = recorder + case "raw": + recorder := &RawRecorder{} + recorder.Record = &conf.Raw + recorder.append = query.Get("append") != "" && util.Exist(filePath) + sub = recorder default: http.Error(w, "type not supported", http.StatusBadRequest) } diff --git a/raw.go b/raw.go new file mode 100644 index 0000000..7673bb6 --- /dev/null +++ b/raw.go @@ -0,0 +1,46 @@ +package record + +import ( + "path/filepath" + "strconv" + "time" + + . "m7s.live/engine/v4" + "m7s.live/engine/v4/codec" + "m7s.live/engine/v4/track" +) + +type RawRecorder struct { + Recorder +} + +func (r *RawRecorder) OnEvent(event any) { + r.Recorder.OnEvent(event) + switch v := event.(type) { + case *track.Video: + if r.Ext == "." { + if v.CodecID == codec.CodecID_H264 { + r.Ext = ".h264" + } else { + r.Ext = ".h265" + } + } + case VideoDeConf: + annexB := v.GetAnnexB() + annexB.WriteTo(r) + case *VideoFrame: + if r.Fragment != 0 && r.newFile { + r.newFile = false + r.Close() + if file, err := r.CreateFileFn(filepath.Join(r.Stream.Path, strconv.FormatInt(time.Now().Unix(), 10)+r.Ext), false); err == nil { + r.SetIO(file) + if r.Video.Track != nil { + annexB := VideoDeConf(r.Video.Track.DecoderConfiguration).GetAnnexB() + annexB.WriteTo(r) + } + } + } + annexB := v.GetAnnexB() + annexB.WriteTo(r) + } +} diff --git a/vod.go b/vod.go index 693176b..9aa33e0 100644 --- a/vod.go +++ b/vod.go @@ -25,5 +25,7 @@ func (conf *RecordConfig) ServeHTTP(w http.ResponseWriter, r *http.Request) { conf.Mp4.ServeHTTP(w, r) case ".m3u8", ".ts": conf.Hls.ServeHTTP(w, r) + case ".h264", ".h265": + conf.Raw.ServeHTTP(w, r) } }