123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- package record
- import (
- "math"
- "path/filepath"
- "strconv"
- "time"
- "go.uber.org/zap"
- . "m7s.live/engine/v4"
- "m7s.live/engine/v4/codec"
- "m7s.live/engine/v4/codec/mpegts"
- "m7s.live/engine/v4/util"
- "m7s.live/plugin/hls/v4"
- )
- type HLSRecorder struct {
- playlist hls.Playlist
- video_cc, audio_cc byte
- packet mpegts.MpegTsPESPacket
- Recorder
- MemoryTs
- }
- func (h *HLSRecorder) Start(streamPath string) error {
- h.Record = &RecordPluginConfig.Hls
- h.ID = streamPath + "/hls"
- if _, ok := RecordPluginConfig.recordings.Load(h.ID); ok {
- return ErrRecordExist
- }
- h.BytesPool = make(util.BytesPool, 17)
- return plugin.Subscribe(streamPath, h)
- }
- func (h *HLSRecorder) OnEvent(event any) {
- var err error
- defer func() {
- if err != nil {
- h.Error("HLSRecorder Stop", zap.Error(err))
- h.Stop()
- }
- }()
- h.Recorder.OnEvent(event)
- switch v := event.(type) {
- case *HLSRecorder:
- h.playlist = hls.Playlist{
- Writer: h.Writer,
- Version: 3,
- Sequence: 0,
- Targetduration: int(math.Ceil(h.Fragment.Seconds())),
- }
- if err = h.playlist.Init(); err != nil {
- return
- }
- if err = h.createHlsTsSegmentFile(); err != nil {
- h.Stop()
- return
- }
- go h.start()
- case AudioFrame:
- pes := &mpegts.MpegtsPESFrame{
- Pid: mpegts.PID_AUDIO,
- IsKeyFrame: false,
- ContinuityCounter: h.audio_cc,
- ProgramClockReferenceBase: uint64(v.DTS),
- }
- h.WriteAudioFrame(v, pes)
- h.BLL.WriteTo(h)
- h.Recycle()
- h.Clear()
- h.audio_cc = pes.ContinuityCounter
- case VideoFrame:
- if h.Fragment != 0 && h.newFile {
- h.newFile = false
- h.Close()
- if err = h.createHlsTsSegmentFile(); err != nil {
- return
- }
- }
- pes := &mpegts.MpegtsPESFrame{
- Pid: mpegts.PID_VIDEO,
- IsKeyFrame: v.IFrame,
- ContinuityCounter: h.video_cc,
- ProgramClockReferenceBase: uint64(v.DTS),
- }
- if err = h.WriteVideoFrame(v, pes); err != nil {
- return
- }
- h.BLL.WriteTo(h)
- h.Recycle()
- h.Clear()
- h.video_cc = pes.ContinuityCounter
- }
- }
- // 创建一个新的ts文件
- func (h *HLSRecorder) createHlsTsSegmentFile() (err error) {
- tsFilename := strconv.FormatInt(time.Now().Unix(), 10) + ".ts"
- fw, err := h.CreateFileFn(filepath.Join(h.Stream.Path, tsFilename), false)
- if err != nil {
- return err
- }
- h.SetIO(fw)
- inf := hls.PlaylistInf{
- Duration: h.Fragment.Seconds(),
- Title: tsFilename,
- }
- if err = h.playlist.WriteInf(inf); err != nil {
- return
- }
- if err = mpegts.WriteDefaultPATPacket(fw); err != nil {
- return err
- }
- var vcodec codec.VideoCodecID = 0
- var acodec codec.AudioCodecID = 0
- if h.Video != nil {
- vcodec = h.Video.CodecID
- }
- if h.Audio != nil {
- acodec = h.Audio.CodecID
- }
- mpegts.WritePMTPacket(fw, vcodec, acodec)
- return err
- }
|