Files
monibuca/plugin/mp4/pkg/write.go
2024-07-24 09:12:14 +08:00

70 lines
2.1 KiB
Go

package mp4
import (
"m7s.live/m7s/v5"
"m7s.live/m7s/v5/pkg"
"m7s.live/m7s/v5/pkg/codec"
"m7s.live/m7s/v5/plugin/mp4/pkg/box"
"time"
)
type Recorder struct {
*m7s.Subscriber
*box.Movmuxer
videoId uint32
audioId uint32
}
func (r *Recorder) Record(recorder *m7s.Recorder) (err error) {
r.Movmuxer, err = box.CreateMp4Muxer(recorder.File)
if recorder.Publisher.HasAudioTrack() {
audioTrack := recorder.Publisher.AudioTrack
switch ctx := audioTrack.ICodecCtx.GetBase().(type) {
case *codec.AACCtx:
r.audioId = r.AddAudioTrack(box.MP4_CODEC_AAC, box.WithExtraData(ctx.ConfigBytes))
case *codec.PCMACtx:
r.audioId = r.AddAudioTrack(box.MP4_CODEC_G711A, box.WithAudioSampleRate(uint32(ctx.SampleRate)), box.WithAudioChannelCount(uint8(ctx.Channels)), box.WithAudioSampleBits(uint8(ctx.SampleSize)))
case *codec.PCMUCtx:
r.audioId = r.AddAudioTrack(box.MP4_CODEC_G711U, box.WithAudioSampleRate(uint32(ctx.SampleRate)), box.WithAudioChannelCount(uint8(ctx.Channels)), box.WithAudioSampleBits(uint8(ctx.SampleSize)))
}
}
if recorder.Publisher.HasVideoTrack() {
videoTrack := recorder.Publisher.VideoTrack
switch ctx := videoTrack.ICodecCtx.GetBase().(type) {
case *codec.H264Ctx:
r.videoId = r.AddVideoTrack(box.MP4_CODEC_H264, box.WithExtraData(ctx.Record))
case *codec.H265Ctx:
r.videoId = r.AddVideoTrack(box.MP4_CODEC_H265, box.WithExtraData(ctx.Record))
}
}
return m7s.PlayBlock(&recorder.Subscriber, func(audio *pkg.RawAudio) error {
return r.WriteAudio(r.audioId, audio.ToBytes(), uint64(audio.Timestamp/time.Millisecond))
}, func(video *pkg.H26xFrame) error {
var nalus [][]byte
for _, nalu := range video.Nalus {
nalus = append(nalus, nalu.ToBytes())
}
return r.WriteVideo(r.videoId, nalus, uint64(video.Timestamp/time.Millisecond), uint64(video.CTS/time.Millisecond))
})
}
func (r *Recorder) Close() {
defer func() {
if err := recover(); err != nil {
r.Error("close", "err", err)
} else {
r.Info("close")
}
}()
err := r.WriteTrailer()
if err != nil {
r.Error("write trailer", "err", err)
} else {
r.Info("write trailer")
}
}
func NewMP4Recorder() *Recorder {
return &Recorder{}
}