mirror of
https://github.com/Monibuca/plugin-record.git
synced 2025-10-07 09:41:07 +08:00
适配引擎的升级
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"m7s.live/engine/v4"
|
||||
)
|
||||
@@ -29,7 +30,7 @@ type Record struct {
|
||||
Path string //存储文件的目录
|
||||
AutoRecord bool
|
||||
Filter string
|
||||
Fragment int //分片大小(秒)0表示不分片
|
||||
Fragment time.Duration //分片大小(秒)0表示不分片
|
||||
filterReg *regexp.Regexp
|
||||
fs http.Handler
|
||||
CreateFileFn func(filename string, append bool) (FileWr, error) `yaml:"-" json:"-"`
|
||||
|
@@ -1,2 +1,2 @@
|
||||
subscribe:
|
||||
livemode: false
|
||||
submode: 1
|
30
flv.go
30
flv.go
@@ -2,7 +2,6 @@ package record
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -11,6 +10,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
. "m7s.live/engine/v4"
|
||||
"m7s.live/engine/v4/codec"
|
||||
"m7s.live/engine/v4/util"
|
||||
)
|
||||
|
||||
type FLVRecorder struct {
|
||||
@@ -43,10 +43,10 @@ func (r *FLVRecorder) start() {
|
||||
|
||||
func (r *FLVRecorder) writeMetaData(file *os.File, duration int64) {
|
||||
defer file.Close()
|
||||
at, vt := r.Audio.Track, r.Video.Track
|
||||
at, vt := r.Audio, r.Video
|
||||
hasAudio, hasVideo := at != nil, vt != nil
|
||||
var amf codec.AMF
|
||||
metaData := codec.EcmaArray{
|
||||
var amf util.AMF
|
||||
metaData := util.EcmaArray{
|
||||
"MetaDataCreator": "m7s " + Engine.Version,
|
||||
"hasVideo": hasVideo,
|
||||
"hasAudio": hasAudio,
|
||||
@@ -99,7 +99,7 @@ func (r *FLVRecorder) writeMetaData(file *os.File, duration int64) {
|
||||
} else {
|
||||
tempFile.Write([]byte{'F', 'L', 'V', 0x01, flags, 0, 0, 0, 9, 0, 0, 0, 0})
|
||||
amf.Reset()
|
||||
codec.WriteFLVTag(tempFile, codec.FLV_TAG_TYPE_SCRIPT, 0, net.Buffers{amf.Marshals("onMetaData", metaData)})
|
||||
codec.WriteFLVTag(tempFile, codec.FLV_TAG_TYPE_SCRIPT, 0, amf.Marshals("onMetaData", metaData))
|
||||
file.Seek(int64(len(codec.FLVHeader)), io.SeekStart)
|
||||
io.Copy(tempFile, file)
|
||||
tempFile.Seek(0, io.SeekStart)
|
||||
@@ -130,18 +130,18 @@ func (r *FLVRecorder) OnEvent(event any) {
|
||||
case FLVFrame:
|
||||
check := false
|
||||
var absTime uint32
|
||||
if r.Video.Track == nil {
|
||||
if r.VideoReader.Track == nil {
|
||||
check = true
|
||||
absTime = r.Audio.Frame.AbsTime
|
||||
absTime = r.AudioReader.Frame.AbsTime
|
||||
} else {
|
||||
check = r.Video.Frame.IFrame
|
||||
absTime = r.Video.Frame.AbsTime
|
||||
check = r.VideoReader.Frame.IFrame
|
||||
absTime = r.VideoReader.Frame.AbsTime
|
||||
if check {
|
||||
r.filepositions = append(r.filepositions, uint64(r.Offset))
|
||||
r.times = append(r.times, float64(absTime)/1000)
|
||||
}
|
||||
}
|
||||
if r.Fragment > 0 && check && r.duration >= int64(r.Fragment*1000) {
|
||||
if r.Fragment > 0 && check && time.Duration(r.duration)*time.Millisecond >= r.Fragment {
|
||||
r.SkipTS = absTime
|
||||
if file, ok := r.Writer.(*os.File); ok {
|
||||
go r.writeMetaData(file, r.duration)
|
||||
@@ -152,15 +152,15 @@ func (r *FLVRecorder) OnEvent(event any) {
|
||||
if file, err := r.CreateFileFn(filepath.Join(r.Stream.Path, strconv.FormatInt(time.Now().Unix(), 10)+r.Ext), false); err == nil {
|
||||
r.SetIO(file)
|
||||
r.Write(codec.FLVHeader)
|
||||
if r.Video.Track != nil {
|
||||
dcflv := codec.VideoAVCC2FLV(r.Video.Track.DecoderConfiguration.AVCC, 0)
|
||||
if r.VideoReader.Track != nil {
|
||||
dcflv := codec.VideoAVCC2FLV(0, r.VideoReader.Track.SequenceHead)
|
||||
dcflv.WriteTo(r)
|
||||
}
|
||||
if r.Audio.Track != nil && r.Audio.Track.CodecID == codec.CodecID_AAC {
|
||||
dcflv := codec.AudioAVCC2FLV(r.Audio.Track.Value.AVCC, 0)
|
||||
if r.AudioReader.Track != nil && r.Audio.CodecID == codec.CodecID_AAC {
|
||||
dcflv := codec.AudioAVCC2FLV(0, r.AudioReader.Track.Value.AVCC.ToBuffers()...)
|
||||
dcflv.WriteTo(r)
|
||||
}
|
||||
flv := codec.VideoAVCC2FLV(r.Video.Frame.AVCC, 0)
|
||||
flv := codec.VideoAVCC2FLV(0, r.VideoReader.Track.Value.AVCC.ToBuffers()...)
|
||||
flv.WriteTo(r)
|
||||
return
|
||||
}
|
||||
|
24
hls.go
24
hls.go
@@ -2,6 +2,7 @@ package record
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -15,7 +16,6 @@ import (
|
||||
|
||||
type HLSRecorder struct {
|
||||
playlist hls.Playlist
|
||||
asc *codec.AudioSpecificConfig
|
||||
video_cc, audio_cc byte
|
||||
packet mpegts.MpegTsPESPacket
|
||||
Recorder
|
||||
@@ -46,7 +46,7 @@ func (h *HLSRecorder) OnEvent(event any) {
|
||||
Writer: h.Writer,
|
||||
Version: 3,
|
||||
Sequence: 0,
|
||||
Targetduration: h.Fragment * 1000,
|
||||
Targetduration: int(math.Ceil(h.Fragment.Seconds())),
|
||||
}
|
||||
if err = h.playlist.Init(); err != nil {
|
||||
return
|
||||
@@ -55,10 +55,8 @@ func (h *HLSRecorder) OnEvent(event any) {
|
||||
return
|
||||
}
|
||||
go h.start()
|
||||
case AudioDeConf:
|
||||
h.asc, err = hls.DecodeAudioSpecificConfig(v.AVCC[0])
|
||||
case *AudioFrame:
|
||||
if h.packet, err = hls.AudioPacketToPES(v, h.asc); err != nil {
|
||||
case AudioFrame:
|
||||
if h.packet, err = hls.AudioPacketToPES(&v, &h.Audio.AudioSpecificConfig); err != nil {
|
||||
return
|
||||
}
|
||||
pes := &mpegts.MpegtsPESFrame{
|
||||
@@ -72,8 +70,8 @@ func (h *HLSRecorder) OnEvent(event any) {
|
||||
return
|
||||
}
|
||||
h.audio_cc = pes.ContinuityCounter
|
||||
case *VideoFrame:
|
||||
h.packet, err = hls.VideoPacketToPES(v, h.Video.Track.DecoderConfiguration, h.SkipTS)
|
||||
case VideoFrame:
|
||||
h.packet, err = hls.VideoPacketToPES(&v, h.Video)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -107,7 +105,7 @@ func (h *HLSRecorder) createHlsTsSegmentFile() (err error) {
|
||||
}
|
||||
h.tsWriter = fw
|
||||
inf := hls.PlaylistInf{
|
||||
Duration: float64(h.Fragment),
|
||||
Duration: h.Fragment.Seconds(),
|
||||
Title: tsFilename,
|
||||
}
|
||||
if err = h.playlist.WriteInf(inf); err != nil {
|
||||
@@ -118,11 +116,11 @@ func (h *HLSRecorder) createHlsTsSegmentFile() (err error) {
|
||||
}
|
||||
var vcodec codec.VideoCodecID = 0
|
||||
var acodec codec.AudioCodecID = 0
|
||||
if h.Video.Track != nil {
|
||||
vcodec = h.Video.Track.CodecID
|
||||
if h.Video != nil {
|
||||
vcodec = h.Video.CodecID
|
||||
}
|
||||
if h.Audio.Track != nil {
|
||||
acodec = h.Audio.Track.CodecID
|
||||
if h.Audio != nil {
|
||||
acodec = h.Audio.CodecID
|
||||
}
|
||||
mpegts.WritePMTPacket(fw, vcodec, acodec)
|
||||
return err
|
||||
|
31
mp4.go
31
mp4.go
@@ -10,7 +10,6 @@ import (
|
||||
. "m7s.live/engine/v4"
|
||||
"m7s.live/engine/v4/codec"
|
||||
"m7s.live/engine/v4/track"
|
||||
"m7s.live/engine/v4/util"
|
||||
)
|
||||
|
||||
type mediaContext struct {
|
||||
@@ -91,11 +90,11 @@ func (r *MP4Recorder) OnEvent(event any) {
|
||||
r.SetIO(file)
|
||||
r.InitSegment = mp4.CreateEmptyInit()
|
||||
r.Moov.Mvhd.NextTrackID = 1
|
||||
if r.Video.Track != nil {
|
||||
r.OnEvent(r.Video.Track)
|
||||
if r.VideoReader.Track != nil {
|
||||
r.OnEvent(r.VideoReader.Track)
|
||||
}
|
||||
if r.Audio.Track != nil {
|
||||
r.OnEvent(r.Audio.Track)
|
||||
if r.AudioReader.Track != nil {
|
||||
r.OnEvent(r.AudioReader.Track)
|
||||
}
|
||||
r.ftyp.Encode(r)
|
||||
r.Moov.Encode(r)
|
||||
@@ -116,12 +115,12 @@ func (r *MP4Recorder) OnEvent(event any) {
|
||||
r.ftyp = mp4.NewFtyp("isom", 0x200, []string{
|
||||
"isom", "iso2", "avc1", "mp41",
|
||||
})
|
||||
newTrak.SetAVCDescriptor("avc1", v.DecoderConfiguration.Raw[0:1], v.DecoderConfiguration.Raw[1:2], true)
|
||||
newTrak.SetAVCDescriptor("avc1", v.ParamaterSets[0:1], v.ParamaterSets[1:2], true)
|
||||
case codec.CodecID_H265:
|
||||
r.ftyp = mp4.NewFtyp("isom", 0x200, []string{
|
||||
"isom", "iso2", "hvc1", "mp41",
|
||||
})
|
||||
newTrak.SetHEVCDescriptor("hvc1", v.DecoderConfiguration.Raw[0:1], v.DecoderConfiguration.Raw[1:2], v.DecoderConfiguration.Raw[2:3], true)
|
||||
newTrak.SetHEVCDescriptor("hvc1", v.ParamaterSets[0:1], v.ParamaterSets[1:2], v.ParamaterSets[2:3], true)
|
||||
}
|
||||
r.AddTrack(v)
|
||||
case *track.Audio:
|
||||
@@ -134,12 +133,12 @@ func (r *MP4Recorder) OnEvent(event any) {
|
||||
r.audio.trackId = trackID
|
||||
switch v.CodecID {
|
||||
case codec.CodecID_AAC:
|
||||
switch v.Profile {
|
||||
case 0:
|
||||
newTrak.SetAACDescriptor(aac.HEAACv1, int(v.SampleRate))
|
||||
switch v.AudioObjectType {
|
||||
case 1:
|
||||
newTrak.SetAACDescriptor(aac.AAClc, int(v.SampleRate))
|
||||
newTrak.SetAACDescriptor(aac.HEAACv1, int(v.SampleRate))
|
||||
case 2:
|
||||
newTrak.SetAACDescriptor(aac.AAClc, int(v.SampleRate))
|
||||
case 3:
|
||||
newTrak.SetAACDescriptor(aac.HEAACv2, int(v.SampleRate))
|
||||
}
|
||||
case codec.CodecID_PCMA:
|
||||
@@ -162,18 +161,18 @@ func (r *MP4Recorder) OnEvent(event any) {
|
||||
r.Moov.Encode(r)
|
||||
go r.start()
|
||||
}
|
||||
case *AudioFrame:
|
||||
case AudioFrame:
|
||||
if r.audio.trackId != 0 {
|
||||
r.audio.push(r, v.AbsTime-r.SkipTS, v.DeltaTime, util.ConcatBuffers(v.Raw), mp4.SyncSampleFlags)
|
||||
r.audio.push(r, v.AbsTime, v.DeltaTime, v.AUList.ToBytes(), mp4.SyncSampleFlags)
|
||||
}
|
||||
case *VideoFrame:
|
||||
case VideoFrame:
|
||||
if r.video.trackId != 0 {
|
||||
flag := mp4.NonSyncSampleFlags
|
||||
if v.IFrame {
|
||||
flag = mp4.SyncSampleFlags
|
||||
}
|
||||
if data := util.ConcatBuffers(v.AVCC); len(data) > 5 {
|
||||
r.video.push(r, v.AbsTime-r.SkipTS, v.DeltaTime, data[5:], flag)
|
||||
if data := v.AUList.ToBytes(); len(data) > 5 {
|
||||
r.video.push(r, v.AbsTime, v.DeltaTime, data[5:], flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
raw.go
16
raw.go
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
. "m7s.live/engine/v4"
|
||||
"m7s.live/engine/v4/codec"
|
||||
"m7s.live/engine/v4/common"
|
||||
"m7s.live/engine/v4/track"
|
||||
)
|
||||
|
||||
@@ -36,22 +37,19 @@ func (r *RawRecorder) OnEvent(event any) {
|
||||
r.Ext = ".h265"
|
||||
}
|
||||
}
|
||||
case VideoDeConf:
|
||||
annexB := v.GetAnnexB()
|
||||
annexB.WriteTo(r)
|
||||
case *VideoFrame:
|
||||
case common.ParamaterSets:
|
||||
v.WriteAnnexBTo(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)
|
||||
if r.Video != nil {
|
||||
r.Video.ParamaterSets.WriteAnnexBTo(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
annexB := v.GetAnnexB()
|
||||
annexB.WriteTo(r)
|
||||
v.WriteAnnexBTo(r)
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
type Recorder struct {
|
||||
Subscriber
|
||||
SkipTS uint32
|
||||
*Record `json:"-"`
|
||||
newFile bool // 创建了新的文件
|
||||
append bool // 是否追加模式
|
||||
@@ -23,7 +24,7 @@ func (r *Recorder) start() {
|
||||
}
|
||||
|
||||
func (r *Recorder) cut(absTime uint32) {
|
||||
if ts := absTime - r.SkipTS; int64(ts) >= int64(r.Fragment*1000) {
|
||||
if ts := absTime - r.SkipTS; time.Duration(ts)*time.Millisecond >= r.Fragment {
|
||||
r.SkipTS = absTime
|
||||
r.newFile = true
|
||||
}
|
||||
@@ -41,12 +42,12 @@ func (r *Recorder) OnEvent(event any) {
|
||||
if file, err := r.CreateFileFn(filename, r.append); err == nil {
|
||||
r.SetIO(file)
|
||||
}
|
||||
case *AudioFrame:
|
||||
case AudioFrame:
|
||||
// 纯音频流的情况下需要切割文件
|
||||
if r.Fragment > 0 && r.Video.Track == nil {
|
||||
if r.Fragment > 0 && r.VideoReader.Track == nil {
|
||||
r.cut(v.AbsTime)
|
||||
}
|
||||
case *VideoFrame:
|
||||
case VideoFrame:
|
||||
if r.Fragment > 0 && v.IFrame {
|
||||
r.cut(v.AbsTime)
|
||||
}
|
||||
|
Reference in New Issue
Block a user