mirror of https://bitbucket.org/ausocean/av.git
fixed merge conflicts
This commit is contained in:
commit
e3e81b9a91
|
@ -191,7 +191,7 @@ func TestEncodePcm(t *testing.T) {
|
||||||
sampleSize := 2
|
sampleSize := 2
|
||||||
blockSize := 16000
|
blockSize := 16000
|
||||||
writeFreq := float64(sampleRate*sampleSize) / float64(blockSize)
|
writeFreq := float64(sampleRate*sampleSize) / float64(blockSize)
|
||||||
e, err := NewEncoder(nopCloser{&buf}, (*testLogger)(t), PacketBasedPSI(10), Rate(int(writeFreq)), MediaType(EncodeAudio))
|
e, err := NewEncoder(nopCloser{&buf}, (*testLogger)(t), PacketBasedPSI(10), Rate(writeFreq), MediaType(EncodeAudio))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create MTS encoder, failed with error: %v", err)
|
t.Fatalf("could not create MTS encoder, failed with error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,12 +97,12 @@ func MediaType(mt int) func(*Encoder) error {
|
||||||
// Rate is an option that can be passed to NewEncoder. It is used to specifiy
|
// Rate is an option that can be passed to NewEncoder. It is used to specifiy
|
||||||
// the rate at which the access units should be played in playback. This will
|
// the rate at which the access units should be played in playback. This will
|
||||||
// be used to create timestamps and counts such as PTS and PCR.
|
// be used to create timestamps and counts such as PTS and PCR.
|
||||||
func Rate(r int) func(*Encoder) error {
|
func Rate(r float64) func(*Encoder) error {
|
||||||
return func(e *Encoder) error {
|
return func(e *Encoder) error {
|
||||||
if r < 1 || r > 60 {
|
if r < 1 || r > 60 {
|
||||||
return ErrInvalidRate
|
return ErrInvalidRate
|
||||||
}
|
}
|
||||||
e.writePeriod = time.Duration(float64(time.Second) / float64(r))
|
e.writePeriod = time.Duration(float64(time.Second) / r)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,6 @@ const (
|
||||||
rbTimeout = 100 * time.Millisecond
|
rbTimeout = 100 * time.Millisecond
|
||||||
rbNextTimeout = 2000 * time.Millisecond
|
rbNextTimeout = 2000 * time.Millisecond
|
||||||
rbLen = 200
|
rbLen = 200
|
||||||
defaultSampleRate = 48000
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// "running" means the input goroutine is reading from the ALSA device and writing to the ringbuffer.
|
// "running" means the input goroutine is reading from the ALSA device and writing to the ringbuffer.
|
||||||
|
@ -61,6 +60,23 @@ const (
|
||||||
stopped
|
stopped
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultSampleRate = 48000
|
||||||
|
defaultBitDepth = 16
|
||||||
|
defaultChannels = 1
|
||||||
|
defaultRecPeriod = 1.0
|
||||||
|
defaultCodec = codecutil.PCM
|
||||||
|
)
|
||||||
|
|
||||||
|
// Configuration field errors.
|
||||||
|
var (
|
||||||
|
errInvalidSampleRate = errors.New("invalid sample rate, defaulting")
|
||||||
|
errInvalidChannels = errors.New("invalid number of channels, defaulting")
|
||||||
|
errInvalidBitDepth = errors.New("invalid bitdepth, defaulting")
|
||||||
|
errInvalidRecPeriod = errors.New("invalid record period, defaulting")
|
||||||
|
errInvalidCodec = errors.New("invalid audio codec, defaulting")
|
||||||
|
)
|
||||||
|
|
||||||
// An ALSA device holds everything we need to know about the audio input stream and implements io.Reader and device.AVDevice.
|
// An ALSA device holds everything we need to know about the audio input stream and implements io.Reader and device.AVDevice.
|
||||||
type ALSA struct {
|
type ALSA struct {
|
||||||
l Logger // Logger for device's routines to log to.
|
l Logger // Logger for device's routines to log to.
|
||||||
|
@ -100,26 +116,31 @@ func (d *ALSA) Name() string {
|
||||||
return "ALSA"
|
return "ALSA"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set will take a Config struct, check the validity of the relevant fields
|
// Setup will take a Config struct, check the validity of the relevant fields
|
||||||
// and then performs any configuration necessary. If fields are not valid,
|
// and then perform any configuration necessary. If fields are not valid,
|
||||||
// an error is added to the multiError and a default value is used.
|
// an error is added to the multiError and a default value is used.
|
||||||
// It then initialises the ALSA device which can then be started, read from, and stopped.
|
// It then initialises the ALSA device which can then be started, read from, and stopped.
|
||||||
func (d *ALSA) Set(c config.Config) error {
|
func (d *ALSA) Setup(c config.Config) error {
|
||||||
var errs device.MultiError
|
var errs device.MultiError
|
||||||
if c.SampleRate <= 0 {
|
if c.SampleRate <= 0 {
|
||||||
errs = append(errs, fmt.Errorf("invalid sample rate: %v", c.SampleRate))
|
errs = append(errs, errInvalidSampleRate)
|
||||||
|
c.SampleRate = defaultSampleRate
|
||||||
}
|
}
|
||||||
if c.Channels <= 0 {
|
if c.Channels <= 0 {
|
||||||
errs = append(errs, fmt.Errorf("invalid number of channels: %v", c.Channels))
|
errs = append(errs, errInvalidChannels)
|
||||||
|
c.Channels = defaultChannels
|
||||||
}
|
}
|
||||||
if c.BitDepth <= 0 {
|
if c.BitDepth <= 0 {
|
||||||
errs = append(errs, fmt.Errorf("invalid bitdepth: %v", c.BitDepth))
|
errs = append(errs, errInvalidBitDepth)
|
||||||
|
c.BitDepth = defaultBitDepth
|
||||||
}
|
}
|
||||||
if c.RecPeriod <= 0 {
|
if c.RecPeriod <= 0 {
|
||||||
errs = append(errs, fmt.Errorf("invalid recording period: %v", c.RecPeriod))
|
errs = append(errs, errInvalidRecPeriod)
|
||||||
|
c.RecPeriod = defaultRecPeriod
|
||||||
}
|
}
|
||||||
if !codecutil.IsValid(c.InputCodec) {
|
if c.InputCodec != codecutil.ADPCM && c.InputCodec != codecutil.PCM {
|
||||||
errs = append(errs, errors.New("invalid codec"))
|
errs = append(errs, errInvalidCodec)
|
||||||
|
c.InputCodec = defaultCodec
|
||||||
}
|
}
|
||||||
d.Config = Config{
|
d.Config = Config{
|
||||||
SampleRate: c.SampleRate,
|
SampleRate: c.SampleRate,
|
||||||
|
@ -164,6 +185,14 @@ func (d *ALSA) Set(c config.Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set exists to satisfy the implementation of the Device interface that revid uses.
|
||||||
|
// Everything that would usually be in Set is in the Setup function.
|
||||||
|
// This is because an ALSA device is different to other devices in that it
|
||||||
|
// outputs binary non-packetised data and it requires a different configuration procedure.
|
||||||
|
func (d *ALSA) Set(c config.Config) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Start will start recording audio and writing to the ringbuffer.
|
// Start will start recording audio and writing to the ringbuffer.
|
||||||
// Once an ALSA device has been stopped it cannot be started again. This is likely to change in future.
|
// Once an ALSA device has been stopped it cannot be started again. This is likely to change in future.
|
||||||
func (d *ALSA) Start() error {
|
func (d *ALSA) Start() error {
|
||||||
|
@ -437,6 +466,12 @@ func (d *ALSA) formatBuffer() pcm.Buffer {
|
||||||
return formatted
|
return formatted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DataSize returns the size in bytes of the data ALSA device d will
|
||||||
|
// output in the duration of a single recording period.
|
||||||
|
func (d *ALSA) DataSize() int {
|
||||||
|
return pcm.DataSize(d.SampleRate, d.Channels, d.BitDepth, d.RecPeriod, d.Codec)
|
||||||
|
}
|
||||||
|
|
||||||
// nearestPowerOfTwo finds and returns the nearest power of two to the given integer.
|
// nearestPowerOfTwo finds and returns the nearest power of two to the given integer.
|
||||||
// If the lower and higher power of two are the same distance, it returns the higher power.
|
// If the lower and higher power of two are the same distance, it returns the higher power.
|
||||||
// For negative values, 1 is returned.
|
// For negative values, 1 is returned.
|
||||||
|
|
|
@ -53,7 +53,7 @@ func TestDevice(t *testing.T) {
|
||||||
// Create a new ALSA device, start, read/lex, and then stop it.
|
// Create a new ALSA device, start, read/lex, and then stop it.
|
||||||
l := logger.New(logger.Debug, os.Stderr, true)
|
l := logger.New(logger.Debug, os.Stderr, true)
|
||||||
ai := New(l)
|
ai := New(l)
|
||||||
err := ai.Set(c)
|
err := ai.Setup(c)
|
||||||
// If there was an error opening the device, skip this test.
|
// If there was an error opening the device, skip this test.
|
||||||
if _, ok := err.(OpenError); ok {
|
if _, ok := err.(OpenError); ok {
|
||||||
t.Skip(err)
|
t.Skip(err)
|
||||||
|
@ -119,7 +119,7 @@ func TestIsRunning(t *testing.T) {
|
||||||
l := logger.New(logger.Debug, &bytes.Buffer{}, true) // Discard logs.
|
l := logger.New(logger.Debug, &bytes.Buffer{}, true) // Discard logs.
|
||||||
d := New(l)
|
d := New(l)
|
||||||
|
|
||||||
err := d.Set(config.Config{
|
err := d.Setup(config.Config{
|
||||||
SampleRate: sampleRate,
|
SampleRate: sampleRate,
|
||||||
Channels: channels,
|
Channels: channels,
|
||||||
BitDepth: bitDepth,
|
BitDepth: bitDepth,
|
||||||
|
|
|
@ -29,13 +29,32 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"bitbucket.org/ausocean/av/codec/codecutil"
|
"bitbucket.org/ausocean/av/codec/codecutil"
|
||||||
"bitbucket.org/ausocean/av/codec/pcm"
|
|
||||||
"bitbucket.org/ausocean/av/container/mts"
|
"bitbucket.org/ausocean/av/container/mts"
|
||||||
"bitbucket.org/ausocean/av/device/alsa"
|
"bitbucket.org/ausocean/av/device/alsa"
|
||||||
"bitbucket.org/ausocean/utils/logger"
|
"bitbucket.org/ausocean/utils/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Revid) setupAudio() error {
|
func (r *Revid) setupAudio() error {
|
||||||
|
// Create new ALSA device.
|
||||||
|
d := alsa.New(r.cfg.Logger)
|
||||||
|
r.input = d
|
||||||
|
|
||||||
|
// Configure ALSA device.
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "configuring input device")
|
||||||
|
err := d.Setup(r.cfg)
|
||||||
|
if err != nil {
|
||||||
|
r.cfg.Logger.Log(logger.Warning, "errors from configuring input device", "errors", err)
|
||||||
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "input device configured")
|
||||||
|
|
||||||
|
// Set revid's lexer.
|
||||||
|
l, err := codecutil.NewByteLexer(d.DataSize())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.lexTo = l.Lex
|
||||||
|
|
||||||
|
// Add metadata.
|
||||||
mts.Meta.Add("sampleRate", strconv.Itoa(int(r.cfg.SampleRate)))
|
mts.Meta.Add("sampleRate", strconv.Itoa(int(r.cfg.SampleRate)))
|
||||||
mts.Meta.Add("channels", strconv.Itoa(int(r.cfg.Channels)))
|
mts.Meta.Add("channels", strconv.Itoa(int(r.cfg.Channels)))
|
||||||
mts.Meta.Add("period", fmt.Sprintf("%.6f", r.cfg.RecPeriod))
|
mts.Meta.Add("period", fmt.Sprintf("%.6f", r.cfg.RecPeriod))
|
||||||
|
@ -50,13 +69,5 @@ func (r *Revid) setupAudio() error {
|
||||||
r.cfg.Logger.Log(logger.Fatal, "no audio codec set in config")
|
r.cfg.Logger.Log(logger.Fatal, "no audio codec set in config")
|
||||||
}
|
}
|
||||||
|
|
||||||
r.input = alsa.New(r.cfg.Logger)
|
|
||||||
|
|
||||||
l, err := codecutil.NewByteLexer(pcm.DataSize(r.cfg.SampleRate, r.cfg.Channels, r.cfg.BitDepth, r.cfg.RecPeriod, r.cfg.InputCodec))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.lexTo = l.Lex
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@ const (
|
||||||
InputAudio
|
InputAudio
|
||||||
|
|
||||||
// Outputs.
|
// Outputs.
|
||||||
OutputAudio
|
|
||||||
OutputRTMP
|
OutputRTMP
|
||||||
OutputRTP
|
OutputRTP
|
||||||
OutputHTTP
|
OutputHTTP
|
||||||
|
@ -233,7 +232,6 @@ type Config struct {
|
||||||
|
|
||||||
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
||||||
Width uint // Width defines the input video width Raspivid input.
|
Width uint // Width defines the input video width Raspivid input.
|
||||||
WriteRate float64 // WriteRate is how many times a second revid encoders will be written to.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks for any errors in the config fields and defaults settings
|
// Validate checks for any errors in the config fields and defaults settings
|
||||||
|
|
|
@ -51,7 +51,6 @@ func TestValidate(t *testing.T) {
|
||||||
BurstPeriod: defaultBurstPeriod,
|
BurstPeriod: defaultBurstPeriod,
|
||||||
MinFrames: defaultMinFrames,
|
MinFrames: defaultMinFrames,
|
||||||
FrameRate: defaultFrameRate,
|
FrameRate: defaultFrameRate,
|
||||||
WriteRate: defaultWriteRate,
|
|
||||||
ClipDuration: defaultClipDuration,
|
ClipDuration: defaultClipDuration,
|
||||||
PSITime: defaultPSITime,
|
PSITime: defaultPSITime,
|
||||||
FileFPS: defaultFileFPS,
|
FileFPS: defaultFileFPS,
|
||||||
|
|
|
@ -130,7 +130,6 @@ var params = []Param{
|
||||||
{N: "VBRQuality", BT: "uint8", E: []string{"Standard", "Fair", "Good", "Great", "Excellent"}},
|
{N: "VBRQuality", BT: "uint8", E: []string{"Standard", "Fair", "Good", "Great", "Excellent"}},
|
||||||
{N: "VerticalFlip", BT: "bool"},
|
{N: "VerticalFlip", BT: "bool"},
|
||||||
{N: "Width", BT: "uint", Min: 640, Max: 1920},
|
{N: "Width", BT: "uint", Min: 640, Max: 1920},
|
||||||
{N: "WriteRate", BT: "float64"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileHeader = `
|
const fileHeader = `
|
||||||
|
|
|
@ -915,16 +915,3 @@ func (w *Width) Set(val string) error {
|
||||||
*w = Width(_v)
|
*w = Width(_v)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type WriteRate float64
|
|
||||||
|
|
||||||
func (w *WriteRate) Type() string { return "float64" }
|
|
||||||
func (w *WriteRate) Set(val string) error {
|
|
||||||
_v, err := strconv.ParseFloat(val, 64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not convert set string to float: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
*w = WriteRate(_v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,9 +49,7 @@ const (
|
||||||
defaultBurstPeriod = 10 // Seconds
|
defaultBurstPeriod = 10 // Seconds
|
||||||
defaultMinFrames = 100
|
defaultMinFrames = 100
|
||||||
defaultFrameRate = 25
|
defaultFrameRate = 25
|
||||||
defaultWriteRate = 25
|
|
||||||
defaultClipDuration = 0
|
defaultClipDuration = 0
|
||||||
defaultAudioInputCodec = codecutil.ADPCM
|
|
||||||
defaultPSITime = 2
|
defaultPSITime = 2
|
||||||
defaultFileFPS = 0
|
defaultFileFPS = 0
|
||||||
|
|
||||||
|
@ -138,6 +136,11 @@ var Variables = []struct {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "Channels",
|
||||||
|
Type_: "uint",
|
||||||
|
Update: func(c *Config, v string) { c.Channels = parseUint("Channels", v, c) },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "Exposure",
|
Name: "Exposure",
|
||||||
Type_: "enum:auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,antishake,fireworks",
|
Type_: "enum:auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,antishake,fireworks",
|
||||||
|
@ -242,16 +245,10 @@ var Variables = []struct {
|
||||||
Validate: func(c *Config) {
|
Validate: func(c *Config) {
|
||||||
switch c.InputCodec {
|
switch c.InputCodec {
|
||||||
case codecutil.H264, codecutil.MJPEG, codecutil.PCM, codecutil.ADPCM:
|
case codecutil.H264, codecutil.MJPEG, codecutil.PCM, codecutil.ADPCM:
|
||||||
default:
|
|
||||||
switch c.Input {
|
|
||||||
case OutputAudio:
|
|
||||||
c.LogInvalidField("InputCodec", defaultAudioInputCodec)
|
|
||||||
c.InputCodec = defaultAudioInputCodec
|
|
||||||
default:
|
default:
|
||||||
c.LogInvalidField("InputCodec", defaultInputCodec)
|
c.LogInvalidField("InputCodec", defaultInputCodec)
|
||||||
c.InputCodec = defaultInputCodec
|
c.InputCodec = defaultInputCodec
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -449,6 +446,17 @@ var Variables = []struct {
|
||||||
c.RBWriteTimeout = lessThanOrEqual("RBWriteTimeout", c.RBWriteTimeout, 0, c, defaultRBWriteTimeout)
|
c.RBWriteTimeout = lessThanOrEqual("RBWriteTimeout", c.RBWriteTimeout, 0, c, defaultRBWriteTimeout)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "RecPeriod",
|
||||||
|
Type_: "float",
|
||||||
|
Update: func(c *Config, v string) {
|
||||||
|
_v, err := strconv.ParseFloat(v, 64)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Log(logger.Warning, fmt.Sprintf("invalid %s param", "RecPeriod"), "value", v)
|
||||||
|
}
|
||||||
|
c.RecPeriod = _v
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "Rotation",
|
Name: "Rotation",
|
||||||
Type_: "uint",
|
Type_: "uint",
|
||||||
|
@ -470,6 +478,11 @@ var Variables = []struct {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "SampleRate",
|
||||||
|
Type_: "uint",
|
||||||
|
Update: func(c *Config, v string) { c.SampleRate = parseUint("SampleRate", v, c) },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "Saturation",
|
Name: "Saturation",
|
||||||
Type_: "int",
|
Type_: "int",
|
||||||
|
@ -522,14 +535,6 @@ var Variables = []struct {
|
||||||
Type_: "uint",
|
Type_: "uint",
|
||||||
Update: func(c *Config, v string) { c.Width = parseUint("Width", v, c) },
|
Update: func(c *Config, v string) { c.Width = parseUint("Width", v, c) },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "WriteRate",
|
|
||||||
Type_: "uint",
|
|
||||||
Update: func(c *Config, v string) { c.WriteRate = float64(parseUint("WriteRate", v, c)) },
|
|
||||||
Validate: func(c *Config) {
|
|
||||||
c.WriteRate = float64(lessThanOrEqual("WriteRate", uint(c.WriteRate), 0, c, defaultWriteRate))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseUint(n, v string, c *Config) uint {
|
func parseUint(n, v string, c *Config) uint {
|
||||||
|
|
|
@ -169,7 +169,7 @@ func (r *Revid) reset(c config.Config) error {
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Debug, "setting up revid pipeline")
|
r.cfg.Logger.Log(logger.Debug, "setting up revid pipeline")
|
||||||
err = r.setupPipeline(
|
err = r.setupPipeline(
|
||||||
func(dst io.WriteCloser, fps float64) (io.WriteCloser, error) {
|
func(dst io.WriteCloser, rate float64) (io.WriteCloser, error) {
|
||||||
var st int
|
var st int
|
||||||
var encOptions []func(*mts.Encoder) error
|
var encOptions []func(*mts.Encoder) error
|
||||||
|
|
||||||
|
@ -211,10 +211,12 @@ func (r *Revid) reset(c config.Config) error {
|
||||||
}
|
}
|
||||||
case config.InputAudio:
|
case config.InputAudio:
|
||||||
st = mts.EncodeAudio
|
st = mts.EncodeAudio
|
||||||
|
encOptions = append(encOptions, mts.TimeBasedPSI(time.Duration(r.cfg.PSITime)*time.Second))
|
||||||
|
rate = 1 / r.cfg.RecPeriod
|
||||||
default:
|
default:
|
||||||
panic("unknown input type")
|
panic("unknown input type")
|
||||||
}
|
}
|
||||||
encOptions = append(encOptions, mts.MediaType(st), mts.Rate(int(fps)))
|
encOptions = append(encOptions, mts.MediaType(st), mts.Rate(rate))
|
||||||
return mts.NewEncoder(dst, &encLog{r.cfg.Logger}, encOptions...)
|
return mts.NewEncoder(dst, &encLog{r.cfg.Logger}, encOptions...)
|
||||||
},
|
},
|
||||||
func(dst io.WriteCloser, fps int) (io.WriteCloser, error) {
|
func(dst io.WriteCloser, fps int) (io.WriteCloser, error) {
|
||||||
|
@ -310,7 +312,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
|
||||||
// as a destination.
|
// as a destination.
|
||||||
if len(mtsSenders) != 0 {
|
if len(mtsSenders) != 0 {
|
||||||
mw := multiWriter(mtsSenders...)
|
mw := multiWriter(mtsSenders...)
|
||||||
e, _ := mtsEnc(mw, r.cfg.WriteRate)
|
e, _ := mtsEnc(mw, float64(r.cfg.FrameRate))
|
||||||
encoders = append(encoders, e)
|
encoders = append(encoders, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,9 +456,12 @@ func (r *Revid) Start() error {
|
||||||
}
|
}
|
||||||
r.cfg.Logger.Log(logger.Info, "revid reset")
|
r.cfg.Logger.Log(logger.Info, "revid reset")
|
||||||
|
|
||||||
// Calculate delay between frames based on FileFPS.
|
// Calculate delay between frames based on FileFPS for video or
|
||||||
|
// between recording periods for audio.
|
||||||
d := time.Duration(0)
|
d := time.Duration(0)
|
||||||
if r.cfg.FileFPS != 0 {
|
if r.cfg.Input == config.InputAudio {
|
||||||
|
d = time.Duration(r.cfg.RecPeriod * float64(time.Second))
|
||||||
|
} else if r.cfg.FileFPS != 0 {
|
||||||
d = time.Duration(1000/r.cfg.FileFPS) * time.Millisecond
|
d = time.Duration(1000/r.cfg.FileFPS) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue