mediamtx/internal/recorder/recorder_instance.go
2025-11-11 23:57:52 +01:00

109 lines
2.1 KiB
Go

package recorder
import (
"strings"
"time"
"github.com/bluenviron/mediacommon/v2/pkg/formats/fmp4"
"github.com/google/uuid"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/recordstore"
"github.com/bluenviron/mediamtx/internal/stream"
)
type sample struct {
*fmp4.Sample
dts int64
ntp time.Time
}
type recorderInstance struct {
pathFormat string
format conf.RecordFormat
partDuration time.Duration
maxPartSize conf.StringSize
segmentDuration time.Duration
pathName string
stream *stream.Stream
onSegmentCreate OnSegmentCreateFunc
onSegmentComplete OnSegmentCompleteFunc
parent logger.Writer
streamID uuid.UUID
pathFormat2 string
format2 format
skip bool
reader *stream.Reader
terminate chan struct{}
done chan struct{}
}
// Log implements logger.Writer.
func (ri *recorderInstance) Log(level logger.Level, format string, args ...any) {
ri.parent.Log(level, format, args...)
}
func (ri *recorderInstance) initialize() {
ri.streamID = uuid.New()
ri.pathFormat2 = ri.pathFormat
ri.pathFormat2 = recordstore.PathAddExtension(
strings.ReplaceAll(ri.pathFormat2, "%path", ri.pathName),
ri.format,
)
ri.reader = &stream.Reader{
SkipBytesSent: true,
Parent: ri,
}
ri.terminate = make(chan struct{})
ri.done = make(chan struct{})
switch ri.format {
case conf.RecordFormatMPEGTS:
ri.format2 = &formatMPEGTS{
ri: ri,
}
ok := ri.format2.initialize()
ri.skip = !ok
default:
ri.format2 = &formatFMP4{
ri: ri,
}
ok := ri.format2.initialize()
ri.skip = !ok
}
if !ri.skip {
ri.stream.AddReader(ri.reader)
}
go ri.run()
}
func (ri *recorderInstance) close() {
close(ri.terminate)
<-ri.done
}
func (ri *recorderInstance) run() {
defer close(ri.done)
if !ri.skip {
select {
case err := <-ri.reader.Error():
ri.Log(logger.Error, err.Error())
case <-ri.terminate:
}
ri.stream.RemoveReader(ri.reader)
} else {
<-ri.terminate
}
ri.format2.close()
}