mirror of
https://github.com/bluenviron/mediamtx
synced 2024-12-13 18:24:58 +00:00
125 lines
2.5 KiB
Go
125 lines
2.5 KiB
Go
package record
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/bluenviron/mediacommon/pkg/formats/fmp4"
|
|
|
|
"github.com/bluenviron/mediamtx/internal/asyncwriter"
|
|
"github.com/bluenviron/mediamtx/internal/conf"
|
|
"github.com/bluenviron/mediamtx/internal/logger"
|
|
"github.com/bluenviron/mediamtx/internal/stream"
|
|
)
|
|
|
|
// OnSegmentFunc is the prototype of the function passed as runOnSegmentStart / runOnSegmentComplete
|
|
type OnSegmentFunc = func(string)
|
|
|
|
type sample struct {
|
|
*fmp4.PartSample
|
|
dts time.Duration
|
|
}
|
|
|
|
// Agent saves streams on disk.
|
|
type Agent struct {
|
|
path string
|
|
partDuration time.Duration
|
|
segmentDuration time.Duration
|
|
stream *stream.Stream
|
|
onSegmentCreate OnSegmentFunc
|
|
onSegmentComplete OnSegmentFunc
|
|
parent logger.Writer
|
|
|
|
ctx context.Context
|
|
ctxCancel func()
|
|
writer *asyncwriter.Writer
|
|
format recFormat
|
|
|
|
done chan struct{}
|
|
}
|
|
|
|
// NewAgent allocates an Agent.
|
|
func NewAgent(
|
|
writeQueueSize int,
|
|
path string,
|
|
format conf.RecordFormat,
|
|
partDuration time.Duration,
|
|
segmentDuration time.Duration,
|
|
pathName string,
|
|
stream *stream.Stream,
|
|
onSegmentCreate OnSegmentFunc,
|
|
onSegmentComplete OnSegmentFunc,
|
|
parent logger.Writer,
|
|
) *Agent {
|
|
path = strings.ReplaceAll(path, "%path", pathName)
|
|
|
|
switch format {
|
|
case conf.RecordFormatMPEGTS:
|
|
path += ".ts"
|
|
|
|
default:
|
|
path += ".mp4"
|
|
}
|
|
|
|
ctx, ctxCancel := context.WithCancel(context.Background())
|
|
|
|
a := &Agent{
|
|
path: path,
|
|
partDuration: partDuration,
|
|
segmentDuration: segmentDuration,
|
|
stream: stream,
|
|
onSegmentCreate: onSegmentCreate,
|
|
onSegmentComplete: onSegmentComplete,
|
|
parent: parent,
|
|
ctx: ctx,
|
|
ctxCancel: ctxCancel,
|
|
done: make(chan struct{}),
|
|
}
|
|
|
|
a.writer = asyncwriter.New(writeQueueSize, a)
|
|
|
|
switch format {
|
|
case conf.RecordFormatMPEGTS:
|
|
a.format = newRecFormatMPEGTS(a)
|
|
|
|
default:
|
|
a.format = newRecFormatFMP4(a)
|
|
}
|
|
|
|
go a.run()
|
|
|
|
return a
|
|
}
|
|
|
|
// Close closes the Agent.
|
|
func (a *Agent) Close() {
|
|
a.Log(logger.Info, "recording stopped")
|
|
|
|
a.ctxCancel()
|
|
<-a.done
|
|
}
|
|
|
|
// Log is the main logging function.
|
|
func (a *Agent) Log(level logger.Level, format string, args ...interface{}) {
|
|
a.parent.Log(level, "[record] "+format, args...)
|
|
}
|
|
|
|
func (a *Agent) run() {
|
|
defer close(a.done)
|
|
|
|
a.writer.Start()
|
|
|
|
select {
|
|
case err := <-a.writer.Error():
|
|
a.Log(logger.Error, err.Error())
|
|
a.stream.RemoveReader(a.writer)
|
|
|
|
case <-a.ctx.Done():
|
|
a.stream.RemoveReader(a.writer)
|
|
a.writer.Stop()
|
|
}
|
|
|
|
a.format.close()
|
|
}
|