fixed merge conflicts

This commit is contained in:
Saxon 2020-08-14 17:25:02 +09:30
commit e3e81b9a91
11 changed files with 121 additions and 82 deletions

View File

@ -191,7 +191,7 @@ func TestEncodePcm(t *testing.T) {
sampleSize := 2
blockSize := 16000
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 {
t.Fatalf("could not create MTS encoder, failed with error: %v", err)
}

View File

@ -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
// 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.
func Rate(r int) func(*Encoder) error {
func Rate(r float64) func(*Encoder) error {
return func(e *Encoder) error {
if r < 1 || r > 60 {
return ErrInvalidRate
}
e.writePeriod = time.Duration(float64(time.Second) / float64(r))
e.writePeriod = time.Duration(float64(time.Second) / r)
return nil
}
}

View File

@ -49,7 +49,6 @@ const (
rbTimeout = 100 * time.Millisecond
rbNextTimeout = 2000 * time.Millisecond
rbLen = 200
defaultSampleRate = 48000
)
// "running" means the input goroutine is reading from the ALSA device and writing to the ringbuffer.
@ -61,6 +60,23 @@ const (
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.
type ALSA struct {
l Logger // Logger for device's routines to log to.
@ -100,26 +116,31 @@ func (d *ALSA) Name() string {
return "ALSA"
}
// Set will take a Config struct, check the validity of the relevant fields
// and then performs any configuration necessary. If fields are not valid,
// Setup will take a Config struct, check the validity of the relevant fields
// and then perform any configuration necessary. If fields are not valid,
// 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.
func (d *ALSA) Set(c config.Config) error {
func (d *ALSA) Setup(c config.Config) error {
var errs device.MultiError
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 {
errs = append(errs, fmt.Errorf("invalid number of channels: %v", c.Channels))
errs = append(errs, errInvalidChannels)
c.Channels = defaultChannels
}
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 {
errs = append(errs, fmt.Errorf("invalid recording period: %v", c.RecPeriod))
errs = append(errs, errInvalidRecPeriod)
c.RecPeriod = defaultRecPeriod
}
if !codecutil.IsValid(c.InputCodec) {
errs = append(errs, errors.New("invalid codec"))
if c.InputCodec != codecutil.ADPCM && c.InputCodec != codecutil.PCM {
errs = append(errs, errInvalidCodec)
c.InputCodec = defaultCodec
}
d.Config = Config{
SampleRate: c.SampleRate,
@ -164,6 +185,14 @@ func (d *ALSA) Set(c config.Config) error {
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.
// Once an ALSA device has been stopped it cannot be started again. This is likely to change in future.
func (d *ALSA) Start() error {
@ -437,6 +466,12 @@ func (d *ALSA) formatBuffer() pcm.Buffer {
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.
// If the lower and higher power of two are the same distance, it returns the higher power.
// For negative values, 1 is returned.

View File

@ -53,7 +53,7 @@ func TestDevice(t *testing.T) {
// Create a new ALSA device, start, read/lex, and then stop it.
l := logger.New(logger.Debug, os.Stderr, true)
ai := New(l)
err := ai.Set(c)
err := ai.Setup(c)
// If there was an error opening the device, skip this test.
if _, ok := err.(OpenError); ok {
t.Skip(err)
@ -119,7 +119,7 @@ func TestIsRunning(t *testing.T) {
l := logger.New(logger.Debug, &bytes.Buffer{}, true) // Discard logs.
d := New(l)
err := d.Set(config.Config{
err := d.Setup(config.Config{
SampleRate: sampleRate,
Channels: channels,
BitDepth: bitDepth,

View File

@ -29,13 +29,32 @@ import (
"strconv"
"bitbucket.org/ausocean/av/codec/codecutil"
"bitbucket.org/ausocean/av/codec/pcm"
"bitbucket.org/ausocean/av/container/mts"
"bitbucket.org/ausocean/av/device/alsa"
"bitbucket.org/ausocean/utils/logger"
)
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("channels", strconv.Itoa(int(r.cfg.Channels)))
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.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
}

View File

@ -50,7 +50,6 @@ const (
InputAudio
// Outputs.
OutputAudio
OutputRTMP
OutputRTP
OutputHTTP
@ -233,7 +232,6 @@ type Config struct {
VerticalFlip bool // VerticalFlip flips video vertically for 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

View File

@ -51,7 +51,6 @@ func TestValidate(t *testing.T) {
BurstPeriod: defaultBurstPeriod,
MinFrames: defaultMinFrames,
FrameRate: defaultFrameRate,
WriteRate: defaultWriteRate,
ClipDuration: defaultClipDuration,
PSITime: defaultPSITime,
FileFPS: defaultFileFPS,

View File

@ -130,7 +130,6 @@ var params = []Param{
{N: "VBRQuality", BT: "uint8", E: []string{"Standard", "Fair", "Good", "Great", "Excellent"}},
{N: "VerticalFlip", BT: "bool"},
{N: "Width", BT: "uint", Min: 640, Max: 1920},
{N: "WriteRate", BT: "float64"},
}
const fileHeader = `

View File

@ -915,16 +915,3 @@ func (w *Width) Set(val string) error {
*w = Width(_v)
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
}

View File

@ -49,9 +49,7 @@ const (
defaultBurstPeriod = 10 // Seconds
defaultMinFrames = 100
defaultFrameRate = 25
defaultWriteRate = 25
defaultClipDuration = 0
defaultAudioInputCodec = codecutil.ADPCM
defaultPSITime = 2
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",
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) {
switch c.InputCodec {
case codecutil.H264, codecutil.MJPEG, codecutil.PCM, codecutil.ADPCM:
default:
switch c.Input {
case OutputAudio:
c.LogInvalidField("InputCodec", defaultAudioInputCodec)
c.InputCodec = defaultAudioInputCodec
default:
c.LogInvalidField("InputCodec", defaultInputCodec)
c.InputCodec = defaultInputCodec
}
}
},
},
{
@ -449,6 +446,17 @@ var Variables = []struct {
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",
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",
Type_: "int",
@ -522,14 +535,6 @@ var Variables = []struct {
Type_: "uint",
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 {

View File

@ -169,7 +169,7 @@ func (r *Revid) reset(c config.Config) error {
r.cfg.Logger.Log(logger.Debug, "setting up revid pipeline")
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 encOptions []func(*mts.Encoder) error
@ -211,10 +211,12 @@ func (r *Revid) reset(c config.Config) error {
}
case config.InputAudio:
st = mts.EncodeAudio
encOptions = append(encOptions, mts.TimeBasedPSI(time.Duration(r.cfg.PSITime)*time.Second))
rate = 1 / r.cfg.RecPeriod
default:
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...)
},
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.
if len(mtsSenders) != 0 {
mw := multiWriter(mtsSenders...)
e, _ := mtsEnc(mw, r.cfg.WriteRate)
e, _ := mtsEnc(mw, float64(r.cfg.FrameRate))
encoders = append(encoders, e)
}
@ -454,9 +456,12 @@ func (r *Revid) Start() error {
}
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)
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
}