mirror of
https://github.com/Monibuca/plugin-record.git
synced 2025-10-05 16:56:53 +08:00
增加视频裸流录制功能
This commit is contained in:
10
README.md
10
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文件
|
||||
|
8
go.mod
8
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
|
||||
|
13
go.sum
13
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=
|
||||
|
18
main.go
18
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)
|
||||
}
|
||||
|
46
raw.go
Normal file
46
raw.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user