Merge branch 'master' into revid-audio

This commit is contained in:
Trek H 2019-06-14 00:15:04 +09:30
commit e3ba1e43f3
8 changed files with 570 additions and 125 deletions

View File

@ -111,7 +111,6 @@ func handleFlags() revid.Config {
inputCodecPtr = flag.String("InputCodec", "", "The codec of the input: H264, Mjpeg, PCM, ADPCM")
inputPtr = flag.String("Input", "", "The input type: Raspivid, File, v4l, Audio, RTSP")
rtspURLPtr = flag.String("RTSPURL", "", "The URL for an RTSP server.")
rtmpMethodPtr = flag.String("RtmpMethod", "", "The method used to send over rtmp: Ffmpeg, Librtmp")
quantizePtr = flag.Bool("Quantize", false, "Quantize input (non-variable bitrate)")
verbosityPtr = flag.String("Verbosity", "Info", "Verbosity: Debug, Info, Warning, Error, Fatal")
rtpAddrPtr = flag.String("RtpAddr", "", "Rtp destination address: <IP>:<port> (port is generally 6970-6999)")
@ -121,7 +120,6 @@ func handleFlags() revid.Config {
outputPathPtr = flag.String("OutputPath", "", "The directory of the output file")
inputFilePtr = flag.String("InputPath", "", "The directory of the input file")
httpAddressPtr = flag.String("HttpAddress", "", "Destination address of http posts")
sendRetryPtr = flag.Bool("retry", false, "Specify whether a failed send should be retried.")
verticalFlipPtr = flag.Bool("VerticalFlip", false, "Flip video vertically: Yes, No")
horizontalFlipPtr = flag.Bool("HorizontalFlip", false, "Flip video horizontally: Yes, No")
framesPerClipPtr = flag.Uint("FramesPerClip", 0, "Number of frames per clip sent")
@ -223,27 +221,17 @@ func handleFlags() revid.Config {
case "File":
cfg.Outputs = append(cfg.Outputs, revid.File)
case "Http":
cfg.Outputs = append(cfg.Outputs, revid.Http)
cfg.Outputs = append(cfg.Outputs, revid.HTTP)
case "Rtmp":
cfg.Outputs = append(cfg.Outputs, revid.Rtmp)
cfg.Outputs = append(cfg.Outputs, revid.RTMP)
case "Rtp":
cfg.Outputs = append(cfg.Outputs, revid.Rtp)
cfg.Outputs = append(cfg.Outputs, revid.RTP)
case "":
default:
log.Log(logger.Error, pkg+"bad output argument", "arg", o)
}
}
switch *rtmpMethodPtr {
case "Ffmpeg":
cfg.RtmpMethod = revid.Ffmpeg
case "LibRtmp":
cfg.RtmpMethod = revid.LibRtmp
case "":
default:
log.Log(logger.Error, pkg+"bad rtmp method argument")
}
if *configFilePtr != "" {
netsender.ConfigFile = *configFilePtr
}
@ -254,18 +242,17 @@ func handleFlags() revid.Config {
cfg.FlipHorizontal = *horizontalFlipPtr
cfg.FlipVertical = *verticalFlipPtr
cfg.FramesPerClip = *framesPerClipPtr
cfg.RtmpUrl = *rtmpUrlPtr
cfg.RTMPURL = *rtmpUrlPtr
cfg.Bitrate = *bitratePtr
cfg.OutputPath = *outputPathPtr
cfg.InputPath = *inputFilePtr
cfg.Height = *heightPtr
cfg.Width = *widthPtr
cfg.FrameRate = *frameRatePtr
cfg.HttpAddress = *httpAddressPtr
cfg.HTTPAddress = *httpAddressPtr
cfg.Quantization = *quantizationPtr
cfg.IntraRefreshPeriod = *intraRefreshPeriodPtr
cfg.RtpAddress = *rtpAddrPtr
cfg.SendRetry = *sendRetryPtr
cfg.RTPAddress = *rtpAddrPtr
cfg.Brightness = *brightnessPtr
cfg.Saturation = *saturationPtr
cfg.Exposure = *exposurePtr

217
codec/h264/extract.go Normal file
View File

@ -0,0 +1,217 @@
/*
NAME
extract.go
DESCRIPTION
extract.go provides an extracter to get access units from an RTP stream.
AUTHOR
Saxon Nelson-Milton <saxon@ausocean.org>
LICENSE
Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
package h264
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"time"
"bitbucket.org/ausocean/av/protocol/rtp"
)
// NAL types (from https://tools.ietf.org/html/rfc6184#page-13)
const (
// Single nal units bounds.
typeSingleNALULowBound = 1
typeSingleNALUHighBound = 23
// Single-time aggregation packets.
typeSTAPA = 24
typeSTAPB = 25
// Multi-time aggregation packets.
typeMTAP16 = 26
typeMTAP24 = 27
// Fragmentation packets.
typeFUA = 28
typeFUB = 29
)
// Min NAL lengths.
const (
minSingleNALLen = 1
minSTAPALen = 4
minFUALen = 2
)
// Buffer sizes.
const (
maxAUSize = 100000 // Max access unit size in bytes.
maxRTPSize = 1500 // Max ethernet transmission unit in bytes.
)
// Extracter is an extracter for extracting H264 access units from RTP stream.
type Extracter struct {
buf *bytes.Buffer // Holds the current access unit.
frag bool // Indicates if we're currently dealing with a fragmentation packet.
}
// NewExtracter returns a new Extracter.
func NewExtracter() *Extracter {
return &Extracter{
buf: bytes.NewBuffer(make([]byte, 0, maxAUSize))}
}
// Extract extracts H264 access units from an RTP stream. This function
// expects that each read from src will provide a single RTP packet.
func (e *Extracter) Extract(dst io.Writer, src io.Reader, delay time.Duration) error {
buf := make([]byte, maxRTPSize)
for {
n, err := src.Read(buf)
switch err {
case nil: // Do nothing.
case io.EOF:
return nil
default:
return fmt.Errorf("source read error: %v\n", err)
}
// Get payload from RTP packet.
payload, err := rtp.Payload(buf[:n])
if err != nil {
return fmt.Errorf("could not get RTP payload, failed with err: %v\n", err)
}
nalType := payload[0] & 0x1f
// If not currently fragmented then we ignore current write.
if e.frag && nalType != typeFUA {
e.buf.Reset()
e.frag = false
continue
}
if typeSingleNALULowBound <= nalType && nalType <= typeSingleNALUHighBound {
// If len too small, ignore.
if len(payload) < minSingleNALLen {
continue
}
e.writeWithPrefix(payload)
} else {
switch nalType {
case typeSTAPA:
e.handleSTAPA(payload)
case typeFUA:
e.handleFUA(payload)
case typeSTAPB:
panic("STAP-B type unsupported")
case typeMTAP16:
panic("MTAP16 type unsupported")
case typeMTAP24:
panic("MTAP24 type unsupported")
case typeFUB:
panic("FU-B type unsupported")
default:
panic("unsupported type")
}
}
markerIsSet, err := rtp.Marker(buf[:n])
if err != nil {
return fmt.Errorf("could not get marker bit, failed with err: %v\n", err)
}
if markerIsSet {
e.buf.WriteTo(dst)
e.buf.Reset()
}
}
return nil
}
// handleSTAPA parses NAL units from an aggregation packet and writes
// them to the Extracter's buffer buf.
func (e *Extracter) handleSTAPA(d []byte) {
// If the length is too small, ignore.
if len(d) < minSTAPALen {
return
}
for i := 1; i < len(d); {
size := int(binary.BigEndian.Uint16(d[i:]))
// Skip over NAL unit size.
const sizeOfFieldLen = 2
i += sizeOfFieldLen
// Get the NALU.
nalu := d[i : i+size]
i += size
e.writeWithPrefix(nalu)
}
}
// handleFUA parses NAL units from fragmentation packets and writes
// them to the Extracter's buf.
func (e *Extracter) handleFUA(d []byte) {
// If length is too small, ignore.
if len(d) < minFUALen {
return
}
// Get start and end indiciators from FU header.
const FUHeadIdx = 1
start := d[FUHeadIdx]&0x80 != 0
end := d[FUHeadIdx]&0x40 != 0
// If start, form new header, skip FU indicator only and set first byte to
// new header. Otherwise, skip over both FU indicator and FU header.
if start {
newHead := (d[0] & 0xe0) | (d[1] & 0x1f)
d = d[1:]
d[0] = newHead
if end {
panic("bad fragmentation packet")
}
e.frag = true
e.writeWithPrefix(d)
} else {
d = d[2:]
if end {
e.frag = false
}
e.writeNoPrefix(d)
}
}
// write writes a NAL unit to the Extracter's buf in byte stream format using the
// start code.
func (e *Extracter) writeWithPrefix(d []byte) {
const prefix = "\x00\x00\x00\x01"
e.buf.Write([]byte(prefix))
e.buf.Write(d)
}
// writeNoPrefix writes data to the Extracter's buf. This is used for non start
// fragmentations of a NALU.
func (e *Extracter) writeNoPrefix(d []byte) {
e.buf.Write(d)
}

173
codec/h264/extract_test.go Normal file
View File

@ -0,0 +1,173 @@
/*
NAME
extract_test.go
DESCRIPTION
extract_test.go provides tests for the extracter in extract.go
AUTHOR
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
package h264
import (
"io"
"testing"
)
// rtpReader provides an io.Reader for reading the test RTP stream.
type rtpReader struct {
packets [][]byte
idx int
}
// Read implements io.Reader.
func (r *rtpReader) Read(p []byte) (int, error) {
if r.idx == len(r.packets) {
return 0, io.EOF
}
b := r.packets[r.idx]
n := copy(p, b)
if n < len(r.packets[r.idx]) {
r.packets[r.idx] = r.packets[r.idx][n:]
} else {
r.idx++
}
return n, nil
}
// destination holds the access units extracted during the lexing process.
type destination [][]byte
// Write implements io.Writer.
func (d *destination) Write(p []byte) (int, error) {
tmp := make([]byte, len(p))
copy(tmp, p)
*d = append(*d, tmp)
return len(p), nil
}
// TestLex checks that the Lexer can correctly extract H264 access units from
// h264 RTP stream in RTP payload format.
func TestRTPLex(t *testing.T) {
const rtpVer = 2
tests := []struct {
packets [][]byte
expect [][]byte
}{
{
packets: [][]byte{
{ // Single NAL unit.
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RTP header.
typeSingleNALULowBound, // NAL header.
0x01, 0x02, 0x03, 0x04, // NAL Data.
},
{ // Fragmentation (start packet).
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RTP header.
typeFUA, // FU indicator.
0x80 | typeSingleNALULowBound, // FU header.
0x01, 0x02, 0x03, // FU payload.
},
{ // Fragmentation (middle packet)
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RTP header.
typeFUA, // NAL indicator.
typeSingleNALULowBound, // FU header.
0x04, 0x05, 0x06, // FU payload.
},
{ // Fragmentation (end packet)
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RTP header.
typeFUA, // NAL indicator.
0x40 | typeSingleNALULowBound, // FU header.
0x07, 0x08, 0x09, // FU payload
},
{ // Aggregation. Make last packet of access unit => marker bit true.
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RTP header.
typeSTAPA, // NAL header.
0x00, 0x04, // NAL 1 size.
0x01, 0x02, 0x03, 0x04, // NAL 1 data.
0x00, 0x04, // NAL 2 size.
0x01, 0x02, 0x03, 0x04, // NAL 2 data.
},
// Second access unit.
{ // Single NAL unit.
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RTP header.
typeSingleNALULowBound, // NAL header.
0x01, 0x02, 0x03, 0x04, // NAL Data.
},
{ // Single NAL. Make last packet of access unit => marker bit true.
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RTP header.
typeSingleNALULowBound, // NAL header.
0x01, 0x02, 0x03, 0x04, // NAL data.
},
},
expect: [][]byte{
// First access unit.
{
// NAL 1
0x00, 0x00, 0x00, 0x01, // Start code.
typeSingleNALULowBound, // NAL header.
0x01, 0x02, 0x03, 0x04, // NAL data.
// NAL 2
0x00, 0x00, 0x00, 0x01, // Start code.
typeSingleNALULowBound,
0x01, 0x02, 0x03, // FU payload.
0x04, 0x05, 0x06, // FU payload.
0x07, 0x08, 0x09, // FU payload.
// NAL 3
0x00, 0x00, 0x00, 0x01, // Start code.
0x01, 0x02, 0x03, 0x04, // NAL data.
// NAL 4
0x00, 0x00, 0x00, 0x01, // Start code.
0x01, 0x02, 0x03, 0x04, // NAL 2 data
},
// Second access unit.
{
// NAL 1
0x00, 0x00, 0x00, 0x01, // Start code.
typeSingleNALULowBound, // NAL header.
0x01, 0x02, 0x03, 0x04, // Data.
// NAL 2
0x00, 0x00, 0x00, 0x01, // Start code.
typeSingleNALULowBound, // NAL header.
0x01, 0x02, 0x03, 0x04, // Data.
},
},
},
}
for testNum, test := range tests {
r := &rtpReader{packets: test.packets}
d := &destination{}
err := NewExtracter().Extract(d, r, 0)
if err != nil {
t.Fatalf("error lexing: %v\n", err)
}
for i, accessUnit := range test.expect {
for j, part := range accessUnit {
if part != [][]byte(*d)[i][j] {
t.Fatalf("did not get expected data for test: %v.\nGot: %v\nWant: %v\n", testNum, d, test.expect)
}
}
}
}
}

View File

@ -7,6 +7,7 @@ DESCRIPTION
AUTHOR
Dan Kortschak <dan@ausocean.org>
Saxon Nelson-Milton <saxon@ausocean.org>
LICENSE
lex.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
@ -25,8 +26,8 @@ LICENSE
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
// lex.go provides a lexer to lex h264 bytestream into access units.
// Package h264 provides a h264 bytestream lexer and RTP H264 access unit
// extracter.
package h264
import (
@ -44,9 +45,9 @@ func init() {
var h264Prefix = [...]byte{0x00, 0x00, 0x01, 0x09, 0xf0}
// Lex lexes H.264 NAL units read from src into separate writes to dst with
// successive writes being performed not earlier than the specified delay.
// NAL units are split after type 1 (Coded slice of a non-IDR picture), 5
// Lex lexes H.264 NAL units read from src into separate writes
// to dst with successive writes being performed not earlier than the specified
// delay. NAL units are split after type 1 (Coded slice of a non-IDR picture), 5
// (Coded slice of a IDR picture) and 8 (Picture parameter set).
func Lex(dst io.Writer, src io.Reader, delay time.Duration, n int) error {
var tick <-chan time.Time

View File

@ -7,6 +7,7 @@ DESCRIPTION
AUTHOR
Dan Kortschak <dan@ausocean.org>
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
lex_test.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)

View File

@ -32,56 +32,6 @@ import (
"bitbucket.org/ausocean/utils/logger"
)
// Config provides parameters relevant to a revid instance. A new config must
// be passed to the constructor.
type Config struct {
Logger Logger
LogLevel int8
// IO
Input uint8
InputCodec uint8
Outputs []uint8
RtmpMethod uint8
Packetization uint8
Quantize bool // Determines whether input to revid will have constant or variable bitrate.
RtmpUrl string
RTSPURL string
Bitrate uint
OutputPath string
InputPath string
HttpAddress string
Quantization uint
IntraRefreshPeriod uint
RtpAddress string
SendRetry bool
WriteRate float64 // How many times a second revid encoders will be written to.
// Video
Height uint
Width uint
FrameRate uint
FramesPerClip uint
BurstPeriod uint
// Transformation
FlipHorizontal bool
FlipVertical bool
Rotation uint
// Color correction
Brightness uint
Saturation int
Exposure string
AutoWhiteBalance string
// Audio
SampleRate int // Samples a second (Hz).
RecPeriod float64 // How many seconds to record at a time.
Channels int // Number of audio channels, 1 for mono, 2 for stereo.
BitDepth int // Sample bit depth.
}
// Possible modes for raspivid --exposure parameter.
var ExposureModes = [...]string{
"auto",
@ -112,36 +62,36 @@ var AutoWhiteBalanceModes = [...]string{
"horizon",
}
// Enums for config struct
// Enums to define inputs, outputs and codecs.
const (
// Indicates no option has been set.
NothingDefined = iota
// Input/Output.
File
// Inputs.
Raspivid
V4L
Audio
File
Http
None
Mpegts
Ffmpeg
Flv
LibRtmp
QuantizationOn
QuantizationOff
Yes
No
Rtmp
FfmpegRtmp
Udp
MpegtsRtp
Rtp
RTSP
Audio
// Outputs.
RTMP
RTP
HTTP
MPEGTS
// Codecs.
H264
H265
MJPEG
)
// Default config settings
const (
defaultInput = Raspivid
defaultOutput = Http
defaultPacketization = Flv
defaultOutput = HTTP
defaultFrameRate = 25
defaultWriteRate = 25
defaultWidth = 1280
@ -150,7 +100,6 @@ const (
defaultTimeout = 0
defaultQuantization = 40
defaultBitrate = 400000
defaultQuantizationMode = QuantizationOff
defaultFramesPerClip = 1
httpFramesPerClip = 560
defaultInputCodec = codecutil.H264
@ -169,6 +118,129 @@ const (
defaultRecPeriod = 1.0
)
// Config provides parameters relevant to a revid instance. A new config must
// be passed to the constructor. Default values for these fields are defined
// as consts above.
type Config struct {
// LogLevel is the revid logging verbosity level.
// Valid values are defined by enums from the logger package: logger.Debug,
// logger.Info, logger.Warning logger.Error, logger.Fatal.
LogLevel int8
// Input defines the input data source.
//
// Valid values are defined by enums:
// Raspivid:
// Read data from a Raspberry Pi Camera.
// V4l:
// Read from webcam.
// File:
// Location must be specified in InputPath field.
// RTSP:
// RTSPURL must also be defined.
Input uint8
// InputCodec defines the input codec we wish to use, and therefore defines the
// lexer for use in the pipeline. This defaults to H264, but H265 is also a
// valid option if we expect this from the input.
InputCodec uint8
// Outputs define the outputs we wish to output data too.
//
// Valid outputs are defined by enums:
// File:
// Location must be defined by the OutputPath field. MPEG-TS packetization
// is used.
// HTTP:
// Destination is defined by the sh field located in /etc/netsender.conf.
// MPEGT-TS packetization is used.
// RTMP:
// Destination URL must be defined in the RtmpUrl field. FLV packetization
// is used.
// RTP:
// Destination is defined by RtpAddr field, otherwise it will default to
// localhost:6970. MPEGT-TS packetization is used.
Outputs []uint8
// Quantize specifies whether the input to revid will have constant or variable
// bitrate, if configurable with the chosen input. Raspivid supports quantization.
Quantize bool
// FramesPerClip defines the number of packetization units to pack into a clip
// per HTTP send.
FramesPerClip uint
// RTMPURL specifies the Rtmp output destination URL. This must be defined if
// RTMP is to be used as an output.
RTMPURL string
// RTSPURL specifies the RTSP server URL for RTSP input. This must be defined
// when Input is RTSP.
RTSPURL string
// OutputPath defines the output destination for File output. This must be
// defined if File output is to be used.
OutputPath string
// InputPath defines the input file location for File Input. This must be
// defined if File input is to be used.
InputPath string
// FrameRate defines the input frame rate if configurable by the chosen input.
// Raspivid input supports custom framerate.
FrameRate uint
// WriteRate is how many times a second revid encoders will be written to.
WriteRate float64
// HTTPAddress defines a custom HTTP destination if we do not wish to use that
// defined in /etc/netsender.conf.
HTTPAddress string
// Quantization defines the quantization level, which may be a value between
// 0-40. This will only take effect if the Quantize field is true and if we
// are using Raspivid input.
Quantization uint
// IntraRefreshPeriod defines the frequency of video parameter NAL units for
// Raspivid input.
IntraRefreshPeriod uint
// Logger holds an implementation of the Logger interface as defined in revid.go.
// This must be set for revid to work correctly.
Logger Logger
// Brightness and saturation define the brightness and saturation levels for
// Raspivid input.
Brightness uint
Saturation int
// Exposure defines the exposure mode used by the Raspivid input. Valid modes
// are defined in the exported []string ExposureModes defined at the start
// of the file.
Exposure string
// AutoWhiteBalance defines the auto white balance mode used by Raspivid input.
// Valid modes are defined in the exported []string AutoWhiteBalanceModes
// defined at the start of the file.
AutoWhiteBalance string
// Audio
SampleRate int // Samples a second (Hz).
RecPeriod float64 // How many seconds to record at a time.
Channels int // Number of audio channels, 1 for mono, 2 for stereo.
BitDepth int // Sample bit depth.
RTPAddress string // RTPAddress defines the RTP output destination.
BurstPeriod uint // BurstPeriod defines the revid burst period in seconds.
Rotation uint // Rotation defines the video rotation angle in degrees Raspivid input.
Height uint // Height defines the input video height Raspivid input.
Width uint // Width defines the input video width Raspivid input.
Bitrate uint // Bitrate specifies the input bitrate for Raspivid input.
FlipHorizontal bool // FlipHorizontal flips video horizontally for Raspivid input.
FlipVertical bool // FlipVertial flips video vertically for Raspivid input.
}
// Validate checks for any errors in the config fields and defaults settings
// if particular parameters have not been defined.
func (c *Config) Validate(r *Revid) error {
@ -225,28 +297,23 @@ func (c *Config) Validate(r *Revid) error {
if c.Outputs == nil {
c.Logger.Log(logger.Info, pkg+"no output defined, defaulting", "output", defaultOutput)
c.Outputs = append(c.Outputs, defaultOutput)
c.Packetization = defaultPacketization
} else {
for i, o := range c.Outputs {
switch o {
case File:
case Udp:
case Rtmp, FfmpegRtmp:
if c.RtmpUrl == "" {
case RTMP:
if c.RTMPURL == "" {
c.Logger.Log(logger.Info, pkg+"no RTMP URL: falling back to HTTP")
c.Outputs[i] = Http
c.Outputs[i] = HTTP
// FIXME(kortschak): Does this want the same line as below?
// c.FramesPerClip = httpFramesPerClip
break
}
c.Logger.Log(logger.Info, pkg+"defaulting frames per clip for rtmp out", "framesPerClip", defaultFramesPerClip)
c.FramesPerClip = defaultFramesPerClip
c.Packetization = Flv
c.SendRetry = true
case Http, Rtp:
case HTTP, RTP:
c.Logger.Log(logger.Info, pkg+"defaulting frames per clip for http out", "framesPerClip", httpFramesPerClip)
c.FramesPerClip = httpFramesPerClip
c.Packetization = Mpegts
default:
return errors.New("bad output type defined in config")
}
@ -325,8 +392,8 @@ func (c *Config) Validate(r *Revid) error {
return errors.New("quantisation is over threshold")
}
if c.RtpAddress == "" {
c.RtpAddress = defaultRtpAddr
if c.RTPAddress == "" {
c.RTPAddress = defaultRtpAddr
}
switch {

View File

@ -233,11 +233,11 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
var w io.WriteCloser
for _, out := range r.config.Outputs {
switch out {
case Http:
case HTTP:
w = newMtsSender(newHttpSender(r.ns, r.config.Logger.Log), r.config.Logger.Log, rbSize, rbElementSize, 0)
mtsSenders = append(mtsSenders, w)
case Rtp:
w, err := newRtpSender(r.config.RtpAddress, r.config.Logger.Log, r.config.FrameRate)
case RTP:
w, err := newRtpSender(r.config.RTPAddress, r.config.Logger.Log, r.config.FrameRate)
if err != nil {
r.config.Logger.Log(logger.Warning, pkg+"rtp connect error", "error", err.Error())
}
@ -248,8 +248,8 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
return err
}
mtsSenders = append(mtsSenders, w)
case Rtmp:
w, err := newRtmpSender(r.config.RtmpUrl, rtmpConnectionTimeout, rtmpConnectionMaxTries, r.config.Logger.Log)
case RTMP:
w, err := newRtmpSender(r.config.RTMPURL, rtmpConnectionTimeout, rtmpConnectionMaxTries, r.config.Logger.Log)
if err != nil {
r.config.Logger.Log(logger.Warning, pkg+"rtmp connect error", "error", err.Error())
}
@ -289,7 +289,6 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
r.lexTo = h264.Lex
case File:
r.setupInput = r.setupInputForFile
r.lexTo = h264.Lex
case RTSP:
r.setupInput = r.startRTSPCamera
r.lexTo = h265.NewLexer(false).Lex
@ -388,11 +387,11 @@ func (r *Revid) Update(vars map[string]string) error {
case "File":
r.config.Outputs[i] = File
case "Http":
r.config.Outputs[i] = Http
r.config.Outputs[i] = HTTP
case "Rtmp":
r.config.Outputs[i] = Rtmp
r.config.Outputs[i] = RTMP
case "Rtp":
r.config.Outputs[i] = Rtp
r.config.Outputs[i] = RTP
default:
r.config.Logger.Log(logger.Warning, pkg+"invalid output param", "value", value)
continue
@ -400,9 +399,9 @@ func (r *Revid) Update(vars map[string]string) error {
}
case "RtmpUrl":
r.config.RtmpUrl = value
r.config.RTMPURL = value
case "RtpAddress":
r.config.RtpAddress = value
r.config.RTPAddress = value
case "Bitrate":
v, err := strconv.ParseUint(value, 10, 0)
if err != nil {
@ -443,7 +442,7 @@ func (r *Revid) Update(vars map[string]string) error {
}
r.config.Rotation = uint(v)
case "HttpAddress":
r.config.HttpAddress = value
r.config.HTTPAddress = value
case "Quantization":
q, err := strconv.ParseUint(value, 10, 0)
if err != nil {

View File

@ -148,7 +148,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
encoders []encoder
}{
{
outputs: []uint8{Http},
outputs: []uint8{HTTP},
encoders: []encoder{
{
encoderType: mtsEncoderStr,
@ -157,7 +157,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
},
},
{
outputs: []uint8{Rtmp},
outputs: []uint8{RTMP},
encoders: []encoder{
{
encoderType: flvEncoderStr,
@ -166,7 +166,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
},
},
{
outputs: []uint8{Rtp},
outputs: []uint8{RTP},
encoders: []encoder{
{
encoderType: mtsEncoderStr,
@ -175,7 +175,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
},
},
{
outputs: []uint8{Http, Rtmp},
outputs: []uint8{HTTP, RTMP},
encoders: []encoder{
{
encoderType: mtsEncoderStr,
@ -188,7 +188,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
},
},
{
outputs: []uint8{Http, Rtp, Rtmp},
outputs: []uint8{HTTP, RTP, RTMP},
encoders: []encoder{
{
encoderType: mtsEncoderStr,
@ -201,7 +201,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
},
},
{
outputs: []uint8{Rtp, Rtmp},
outputs: []uint8{RTP, RTMP},
encoders: []encoder{
{
encoderType: mtsEncoderStr,
@ -224,7 +224,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
for testNum, test := range tests {
// Create a new config and reset revid with it.
const dummyURL = "rtmp://dummy"
c := Config{Logger: &testLogger{}, Outputs: test.outputs, RtmpUrl: dummyURL}
c := Config{Logger: &testLogger{}, Outputs: test.outputs, RTMPURL: dummyURL}
err := rv.setConfig(c)
if err != nil {
t.Fatalf("unexpected error: %v for test %v", err, testNum)