Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions example/default/config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
global:
http:
listenaddr: :8080
location:
"^/hdl/(.*)": "/flv/$1" # 兼容 v4
"^/stress/api/(.*)": "/test/api/stress/$1" # 5.0.x
"^/monitor/(.*)": "/debug/$1" # 5.0.x
loglevel: debug
loglevel: info
admin:
enablelogin: false
# S3存储配置示例(需要时取消注释并填写实际值)
# storage:
# s3:
# endpoint: "s3.amazonaws.com" # S3服务端点
# region: "us-east-1" # AWS区域
# accessKeyID: "your-access-key-id" # 访问密钥ID
# secretAccessKey: "your-secret-access-key" # 秘密访问密钥
# bucket: "your-bucket-name" # 存储桶名称
# pathPrefix: "monibuca/recordings" # 文件路径前缀
# forcePathStyle: false # 强制路径样式(MinIO需要设为true)
# useSSL: true # 是否使用SSL
# timeout: "30s" # 上传超时时间
# pullproxy:
# - id: 1 # 唯一ID标识,必须大于0
# name: "camera-1" # 拉流代理名称
Expand Down Expand Up @@ -57,23 +71,23 @@ gb28181:
- platformservergbid: "34020000002000000002" #上级平台GBID
channeldbid: "34020000001110000003_34020000001320000005" #通道DBID,格式为设备ID_通道ID
mp4:
# enable: false
enable: true
# publish:
# delayclosetimeout: 3s
# onpub:
# record:
# ^live/.+:
# fragment: 10s
# filepath: record/$0
# storage:
# s3:
# endpoint: "storage-dev.xiding.tech"
# accessKeyId: "xidinguser"
# secretAccessKey: "U2FsdGVkX1/7uyvj0trCzSNFsfDZ66dMSAEZjNlvW1c="
# bucket: "vidu-media-bucket"
# pathPrefix: ""
# forcePathStyle: true
# useSSL: true
# ^live/(.+)$:
# filepath: s3rec/$0
# filename: $0.mp4
# storage:
# s3:
# endpoint: "storage-dev.xiding.tech"
# accessKeyId: "xidinguser"
# secretAccessKey: "U2FsdGVkX1/7uyvj0trCzSNFsfDZ66dMSAEZjNlvW1c="
# bucket: "vidu-media-bucket"
# pathPrefix: "recordings"
# forcePathStyle: true
# useSSL: true
# pull:
# live/test: /Users/dexter/Movies/1744963190.mp4
onsub:
Expand All @@ -90,8 +104,16 @@ flv:
# onpub:
# record:
# ^live/.+:
# fragment: 1m
# filepath: record/$0
# storage:
# s3:
# endpoint: "s3.amazonaws.com"
# accessKeyId: "your-access-key-id"
# secretAccessKey: "your-secret-access-key"
# bucket: "your-bucket-name"
# pathPrefix: "flv-recordings"
# forcePathStyle: false
# useSSL: true
publish:
delayclosetimeout: 3s
onsub:
Expand Down
5 changes: 3 additions & 2 deletions pkg/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ type (
}
Record struct {
Mode RecordMode `json:"mode" desc:"事件类型,auto=连续录像模式,event=事件录像模式" gorm:"type:varchar(255);comment:事件类型,auto=连续录像模式,event=事件录像模式;default:'auto'"`
Type string `desc:"录制类型"` // 录制类型 mp4、flv、hls、hlsv7
FilePath string `desc:"录制文件路径"` // 录制文件路径
Type string `desc:"录制类型"` // 录制类型 mp4、flv、hls、hlsv7
FilePath string `desc:"录制文件路径"` // 录制文件路径
FileName string `json:"fileName" desc:"录制文件名" gorm:"-"`
Fragment time.Duration `desc:"分片时长"` // 分片时长
RealTime bool `desc:"是否实时录制"` // 是否实时录制
Append bool `desc:"是否追加录制"` // 是否追加录制
Expand Down
8 changes: 8 additions & 0 deletions plugin/flv/pkg/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"os"
"path/filepath"
"strings"
"time"

task "github.com/langhuihui/gotask"
Expand Down Expand Up @@ -148,6 +149,12 @@ type Recorder struct {
}

var CustomFileName = func(job *m7s.RecordJob) string {
if fn := job.RecConf.FileName; fn != "" {
if !strings.HasSuffix(strings.ToLower(fn), ".flv") {
fn = fn + ".flv"
}
return filepath.Join(job.RecConf.FilePath, fn)
}
if job.RecConf.Fragment == 0 || job.RecConf.Append {
return fmt.Sprintf("%s.flv", job.RecConf.FilePath)
}
Expand All @@ -160,6 +167,7 @@ func (r *Recorder) createStream(start time.Time) (err error) {
if err != nil {
return
}
r.Debug("flv create file", "filePath", r.Event.FilePath)

// 获取存储实例
st := r.RecordJob.GetStorage()
Expand Down
32 changes: 22 additions & 10 deletions plugin/hls/pkg/record.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package hls

import (
"context"
"fmt"
"path/filepath"
"time"
"context"
"fmt"
"strings"
"path/filepath"
"time"

"m7s.live/v5"
"m7s.live/v5/pkg/codec"
Expand All @@ -28,15 +29,26 @@ type Recorder struct {
}

var CustomFileName = func(job *m7s.RecordJob) string {
if job.RecConf.Fragment == 0 || job.RecConf.Append {
return fmt.Sprintf("%s/%s.ts", job.RecConf.FilePath, time.Now().Format("20060102150405"))
}
return filepath.Join(job.RecConf.FilePath, time.Now().Format("20060102150405")+".ts")
if fn := job.RecConf.FileName; fn != "" {
if !strings.HasSuffix(strings.ToLower(fn), ".ts") {
fn = fn + ".ts"
}
return filepath.Join(job.RecConf.FilePath, fn)
}
if job.RecConf.Fragment == 0 || job.RecConf.Append {
return fmt.Sprintf("%s/%s.ts", job.RecConf.FilePath, time.Now().Format("20060102150405"))
}
return filepath.Join(job.RecConf.FilePath, time.Now().Format("20060102150405")+".ts")
}

func (r *Recorder) createStream(start time.Time) (err error) {
r.RecordJob.RecConf.Type = "ts"
return r.CreateStream(start, CustomFileName)
r.RecordJob.RecConf.Type = "ts"
err = r.CreateStream(start, CustomFileName)
if err != nil {
return err
}
r.Debug("ts create file", "filePath", r.Event.FilePath)
return nil
}

func (r *Recorder) writeTailer(end time.Time) {
Expand Down
12 changes: 10 additions & 2 deletions plugin/mp4/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,6 @@ func (p *MP4Plugin) download(w http.ResponseWriter, r *http.Request) {
if err != nil {
return
}
p.Info("read", "file", file.Name())

// 创建解复用器并解析文件
demuxer := mp4.NewDemuxer(file)
Expand Down Expand Up @@ -558,16 +557,22 @@ func (p *MP4Plugin) download(w http.ResponseWriter, r *http.Request) {
func (p *MP4Plugin) StartRecord(ctx context.Context, req *mp4pb.ReqStartRecord) (res *mp4pb.ResponseStartRecord, err error) {
var recordExists bool
var filePath = "."
var fileName = ""
var fragment = time.Minute
if req.Fragment != nil {
fragment = req.Fragment.AsDuration()
}
if req.FilePath != "" {
filePath = req.FilePath
}
if req.FileName != "" {
fileName = req.FileName
}

p.Debug("mp4 plugin start record", "streamPath", req.StreamPath, "filePath", filePath, "fileName", fileName, "fragment", fragment)
res = &mp4pb.ResponseStartRecord{}
_, recordExists = p.Server.Records.Find(func(job *m7s.RecordJob) bool {
return job.StreamPath == req.StreamPath && job.RecConf.FilePath == req.FilePath
return job.StreamPath == req.StreamPath && job.RecConf.FilePath == req.FilePath && job.RecConf.FileName == req.FileName
})
if recordExists {
err = pkg.ErrRecordExists
Expand All @@ -578,7 +583,9 @@ func (p *MP4Plugin) StartRecord(ctx context.Context, req *mp4pb.ReqStartRecord)
Append: false,
Fragment: fragment,
FilePath: filePath,
FileName: fileName,
}

var stream *m7s.Publisher
var ok bool
if stream, ok = p.Server.Streams.SafeGet(req.StreamPath); !ok {
Expand All @@ -595,6 +602,7 @@ func (p *MP4Plugin) StartRecord(ctx context.Context, req *mp4pb.ReqStartRecord)
}
}
job := p.Record(stream, recordConf, nil)
p.Debug("mp4 record job", "taskPtr", uint64(job.GetTaskPointer()))
res.Data = uint64(job.GetTaskPointer())
err = job.WaitStarted()
return
Expand Down
17 changes: 13 additions & 4 deletions plugin/mp4/pb/mp4.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 30 additions & 3 deletions plugin/mp4/pb/mp4.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion plugin/mp4/pb/mp4.proto
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ message ReqStartRecord {
string streamPath = 1;
google.protobuf.Duration fragment = 2;
string filePath = 3;
string fileName = 4;
}

message ResponseStartRecord {
Expand Down Expand Up @@ -171,4 +172,4 @@ message ResponseTagList {
string message = 2;
repeated TagInfo list = 3;
uint32 total = 4;
}
}
2 changes: 1 addition & 1 deletion plugin/mp4/pb/mp4_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading