123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package record
- import (
- _ "embed"
- "errors"
- "crypto/md5"
- "encoding/hex"
- "io"
- "sync"
- "time"
- "fmt"
- "strconv"
- "strings"
- "go.uber.org/zap"
- "gorm.io/gorm"
- . "m7s.live/engine/v4"
- "m7s.live/engine/v4/codec"
- "m7s.live/engine/v4/config"
- "m7s.live/engine/v4/util"
- "m7s.live/engine/v4/db"
- )
- type RecordConfig struct {
- config.Subscribe
- Ffmpeg string `json:"ffmpeg"`
- Flv Record `desc:"flv录制配置"`
- Mp4 Record `desc:"mp4录制配置"`
- Fmp4 Record `desc:"fmp4录制配置"`
- Hls Record `desc:"hls录制配置"`
- Raw Record `desc:"视频裸流录制配置"`
- RawAudio Record `desc:"音频裸流录制配置"`
- recordings sync.Map
- }
- func getIsRecordByChannelId(channelId string) int {
- database := db.DB()
- isRecord := 0
- err := database.Raw("select is_record from t_sdp_delivery where channel_id=?",channelId).Find(&isRecord).Error
- if err != nil{
- if err == gorm.ErrRecordNotFound{
- return 0
- }
- return 1
- }
-
- return isRecord
- }
- //go:embed default.yaml
- var defaultYaml DefaultYaml
- var ErrRecordExist = errors.New("recorder exist")
- var RecordPluginConfig = &RecordConfig{
- Ffmpeg:"ffmpeg",
- Flv: Record{
- Path: "record/flv",
- Ext: ".flv",
- GetDurationFn: getFLVDuration,
- },
- Fmp4: Record{
- Path: "record/fmp4",
- Ext: ".mp4",
- },
- Mp4: Record{
- Path: "record/mp4",
- Ext: ".mp4",
- },
- Hls: Record{
- Path: "record/hls",
- Ext: ".m3u8",
- },
- Raw: Record{
- Path: "record/raw",
- Ext: ".", // 默认h264扩展名为.h264,h265扩展名为.h265
- },
- RawAudio: Record{
- Path: "record/raw",
- Ext: ".", // 默认aac扩展名为.aac,pcma扩展名为.pcma,pcmu扩展名为.pcmu
- },
- }
- var plugin = InstallPlugin(RecordPluginConfig, defaultYaml)
- func (conf *RecordConfig) OnEvent(event any) {
- switch v := event.(type) {
- case FirstConfig, config.Config:
- conf.Flv.Init()
- conf.Mp4.Init()
- conf.Fmp4.Init()
- conf.Hls.Init()
- conf.Raw.Init()
- conf.RawAudio.Init()
- case SEpublish:
- streamPath := v.Target.Path
- deviceId := v.Target.AppName
- if deviceId != "record"{
- // 获取的是录像,不录
- isRecord := getIsRecordByChannelId(strings.TrimSuffix(v.Target.StreamName, "/rtsp"))
- // 对steam path自动加上签名
- if EngineConfig.Subscribe.Key != ""{
- nowTime := time.Now().Unix()
- expireTime := nowTime + 315360000
- expireTime16 := strconv.FormatInt(expireTime, 16)
- m := md5.New()
- m.Write([]byte(EngineConfig.Subscribe.Key +streamPath + expireTime16))
- streamPathList := strings.Split(streamPath,"?")
- if len(streamPathList) > 0 {
- streamPath = fmt.Sprintf("%s?%s=%s&%s=%s",streamPathList[0],EngineConfig.Subscribe.SecretArgName,hex.EncodeToString(m.Sum(nil)),EngineConfig.Subscribe.ExpireArgName,expireTime16)
- }
- }
- plugin.Info("是否需要开启录像",zap.String("streamPath",streamPath),zap.Int("是否录像",isRecord))
- //fmt.Println("发布流:",streamPath," 是否需要录像:",isRecord)
- if isRecord == 1 {
- if conf.Flv.NeedRecord(streamPath) {
- go NewFLVRecorder().Start(streamPath)
- }
- //fmt.Println("是否需要mp4录像:",conf.Mp4.NeedRecord(streamPath))
- if conf.Mp4.NeedRecord(streamPath) {
- go NewMP4Recorder().Start(streamPath)
- }
- if conf.Fmp4.NeedRecord(streamPath) {
- go NewFMP4Recorder().Start(streamPath)
- }
- if conf.Hls.NeedRecord(streamPath) {
- go NewHLSRecorder().Start(streamPath)
- }
- if conf.Raw.NeedRecord(streamPath) {
- go NewRawRecorder().Start(streamPath)
- }
- if conf.RawAudio.NeedRecord(streamPath) {
- go NewRawAudioRecorder().Start(streamPath)
- }
- }
- }
- }
- }
- func (conf *RecordConfig) getRecorderConfigByType(t string) (recorder *Record) {
- switch t {
- case "flv":
- recorder = &conf.Flv
- case "mp4":
- recorder = &conf.Mp4
- case "fmp4":
- recorder = &conf.Fmp4
- case "hls":
- recorder = &conf.Hls
- case "raw":
- recorder = &conf.Raw
- case "raw_audio":
- recorder = &conf.RawAudio
- }
- return
- }
- func getFLVDuration(file io.ReadSeeker) uint32 {
- _, err := file.Seek(-4, io.SeekEnd)
- if err == nil {
- var tagSize uint32
- if tagSize, err = util.ReadByteToUint32(file, true); err == nil {
- _, err = file.Seek(-int64(tagSize)-4, io.SeekEnd)
- if err == nil {
- _, timestamp, _, err := codec.ReadFLVTag(file)
- if err == nil {
- return timestamp
- }
- }
- }
- }
- return 0
- }
|