diff --git a/revid/RevidInstance.go b/revid/RevidInstance.go index 19273593..38341b5d 100644 --- a/revid/RevidInstance.go +++ b/revid/RevidInstance.go @@ -32,6 +32,7 @@ package revid import ( "bufio" "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -41,7 +42,6 @@ import ( "os/exec" "strconv" "time" - "errors" //"bitbucket.org/ausocean/av/h264" //"bitbucket.org/ausocean/av/tsgenerator" @@ -50,25 +50,25 @@ import ( //"bitbucket.org/ausocean/av/ringbuffer" //"bitbucket.org/ausocean/utils/smartLogger" - "../ringbuffer" "../../utils/smartLogger" + "../ringbuffer" ) // Misc constants const ( - clipDuration = 1 // s - mp2tPacketSize = 188 // MPEG-TS packet size - mp2tMaxPackets = 2016 * clipDuration // # first multiple of 7 and 8 greater than 2000 - udpPackets = 7 // # of UDP packets per ethernet frame (8 is the max) - rtpPackets = 7 // # of RTP packets per ethernet frame (7 is the max) - rtpHeaderSize = 12 - rtpSSRC = 1 // any value will do - bufferSize = 100 / clipDuration - httpTimeOut = 5 // s - packetsPerFrame = 7 - h264BufferSize = 500000 - bitrateTime = 60 - mjpegParserInChanLen= 10000 + clipDuration = 1 // s + mp2tPacketSize = 188 // MPEG-TS packet size + mp2tMaxPackets = 2016 * clipDuration // # first multiple of 7 and 8 greater than 2000 + udpPackets = 7 // # of UDP packets per ethernet frame (8 is the max) + rtpPackets = 7 // # of RTP packets per ethernet frame (7 is the max) + rtpHeaderSize = 12 + rtpSSRC = 1 // any value will do + bufferSize = 100 / clipDuration + httpTimeOut = 5 // s + packetsPerFrame = 7 + h264BufferSize = 500000 + bitrateTime = 60 + mjpegParserInChanLen = 10000 ) // Log Types @@ -82,40 +82,41 @@ const ( // Config provides parameters relevant to a revid instance. A new config must // be passed to the constructor. type Config struct { - Input uint8 - InputCodec uint8 - Output uint8 - OutputFileName string - InputFileName string - Height string - Width string - FrameRate string - HttpAddress string - Quantization string - Timeout string - Packetization uint8 + Input uint8 + InputCodec uint8 + Output uint8 + OutputFileName string + InputFileName string + Height string + Width string + FrameRate string + HttpAddress string + Quantization string + Timeout string + Packetization uint8 IntraRefreshPeriod string - Logger smartLogger.LogInstance + Logger smartLogger.LogInstance } // Enums for config struct const ( - raspivid = 1 - rtp = 2 - h264Codec = 3 - file = 4 - httpOut = 5 - h264 = 6 - mjpeg = 7 - none = 8 - mpegts = 9 + NothingDefined = 0 + Raspivid = 1 + Rtp = 2 + H264Codec = 3 + File = 4 + HttpOut = 5 + H264 = 6 + Mjpeg = 7 + None = 8 + Mpegts = 9 ) // Default config settings const ( - defaultFrameRate = "25" - defaultWidth = "1280" - defaultHeight = "720" + defaultFrameRate = "25" + defaultWidth = "1280" + defaultHeight = "720" defaultIntraRefreshPeriod = "100" ) @@ -130,20 +131,19 @@ type RevidInst interface { IsRunning() bool } - // The revidInst struct provides fields to describe the state of a RevidInst. type revidInst struct { - ffmpegPath string - tempDir string - ringBuffer ringbuffer.RingBuffer - config Config - isRunning bool - outputFile *os.File - inputFile *os.File - generator tsgenerator.TsGenerator - parser parser.Parser - cmd *exec.Cmd - inputReader *bufio.Reader + ffmpegPath string + tempDir string + ringBuffer ringbuffer.RingBuffer + config Config + isRunning bool + outputFile *os.File + inputFile *os.File + generator tsgenerator.TsGenerator + parser parser.Parser + cmd *exec.Cmd + inputReader *bufio.Reader mjpegOutputChan chan []byte } @@ -198,50 +198,67 @@ func (r *revidInst) GetConfigRef() *Config { // ChangeState swaps the current config of a revidInst with the passed // configuration; checking validity and returning errors if not valid. func (r *revidInst) ChangeState(config Config) error { + r.config.Logger = config.Logger switch config.Input { - case rtp: - case raspivid: - case file: + case Rtp: + case Raspivid: + case File: + case NothingDefined: + r.Log(Warning, "No input type defined, defaulting to raspivid!") + config.Input = Raspivid default: return errors.New("Bad input type defined in config!") } + switch config.InputCodec { - case h264: - case mjpeg: + case H264: + case Mjpeg: + case NothingDefined: + r.Log(Warning,"No input codec defined, defaulting to h264!") + config.InputCodec = H264 default: - return errors.New("Bad input format defined in config!") + return errors.New("Bad input codec defined in config!") } + switch config.Output { - case httpOut: - case file: + case HttpOut: + case File: + case NothingDefine: + r.Log(Warning, "No output defined, defaulting to httpOut!") + config.Output = HttpOut default: return errors.New("Bad output type defined in config!") } + if integer, err := strconv.Atoi(config.Width); integer < 0 || err != nil { return errors.New("Bad width defined in config!") } if integer, _ := strconv.Atoi(config.Width); integer == 0 { + r.Log(Warning, "No width defined, defaulting to 1280!") config.Width = defaultWidth } if integer, err := strconv.Atoi(config.Height); integer < 0 || err != nil { return errors.New("Bad height defined in config!") } if integer, _ := strconv.Atoi(config.Height); integer == 0 { + r.Log(Warning, "No height defined, defaulting to 720!") config.Height = defaultHeight } if integer, err := strconv.Atoi(config.FrameRate); integer < 0 || err != nil { return errors.New("Bad FrameRate defined in config!") } if integer, _ := strconv.Atoi(config.FrameRate); integer == 0 { + r.Log(Warning, "No FrameRate defined, defaulting to 25!") config.FrameRate = defaultFrameRate } if integer, err := strconv.Atoi(config.Timeout); integer < 0 || err != nil { - return errors.New("Bad timeout define in config!") + return errors.New("Bad timeout defined in config!") } if integer, err := strconv.Atoi(config.IntraRefreshPeriod); integer < 0 || err != nil { return errors.New("Bad intra refresh period defined in config!") } if integer, _ := strconv.Atoi(config.IntraRefreshPeriod); integer == 0 { + r.Log(Warning, "No intra refresh period defined, defaulting to 100!") config.IntraRefreshPeriod = defaultIntraRefreshPeriod } if integer, err := strconv.Atoi(config.Quantization); integer <= 0 || integer > 51 || err != nil { @@ -280,24 +297,24 @@ func (r *revidInst) Start() { case raspivid: r.Log(Info, "Starting raspivid!") var codec string - switch r.config.InputCodec{ + switch r.config.InputCodec { case h264: codec = "H264" case mjpeg: codec = "MJPEG" } r.cmd = exec.Command("raspivid", - "-cd", codec, - "-o", "-", + "-cd", codec, + "-o", "-", "-n", - "-t", r.config.Timeout, - "-b", "0", - "-qp", r.config.Quantization, - "-w", r.config.Width, - "-h", r.config.Height, + "-t", r.config.Timeout, + "-b", "0", + "-qp", r.config.Quantization, + "-w", r.config.Width, + "-h", r.config.Height, "-fps", r.config.FrameRate, "-ih", - "-g", r.config.IntraRefreshPeriod, + "-g", r.config.IntraRefreshPeriod, ) stdout, _ := r.cmd.StdoutPipe() err := r.cmd.Start() @@ -330,7 +347,7 @@ func (r *revidInst) Start() { } // readCamera reads data from the defined camera while the revidInst is running. -func (r *revidInst)readCamera() { +func (r *revidInst) readCamera() { r.Log(Info, "Reading camera data!") for r.isRunning { data := make([]byte, 1) @@ -342,7 +359,7 @@ func (r *revidInst)readCamera() { case err != nil && r.isRunning: r.Log(Error, err.Error()) default: - r.parser.GetInputChan()<-data[0] + r.parser.GetInputChan() <- data[0] } } r.Log(Info, "Out of reading routine!") @@ -391,7 +408,7 @@ func (r *revidInst) packClips() { frame := <-r.mjpegOutputChan upperBound := clipSize + len(frame) copy(clip[clipSize:upperBound], frame) - packetCount ++ + packetCount++ clipSize += len(frame) case mpegts: tsPacket := <-(r.generator.GetTsOutputChan()) @@ -467,7 +484,7 @@ func (r *revidInst) outputClips() { } } -// sendClipToHTTP takes a clip and an output url and posts through http. +// sendClipToHTTP takes a clip and an output url and posts through http. func (r *revidInst) sendClipToHTTP(clip []byte, output string) error { timeout := time.Duration(httpTimeOut * time.Second) client := http.Client{ diff --git a/revid/revid_test.go b/revid/revid_test.go index cd5d8d6f..52c3783e 100644 --- a/revid/revid_test.go +++ b/revid/revid_test.go @@ -33,16 +33,12 @@ import ( "time" ) -/* - * Testing with file input - * - */ - /* +// Test revidInst with a file input func TestFileInput(t *testing.T){ config := Config{ - Input: file, + Input: file, InputFileName: "testInput.h264", - Output: file, + Output: file, OutputFileName: "output/TestFileAsInput.ts", } revidInst, err := NewRevidInstance(config) @@ -53,13 +49,9 @@ func TestFileInput(t *testing.T){ time.Sleep(100*time.Second) revidInst.Stop() } -* */ - -/* - Testing use with raspivid -*/ -func TestRaspividInput(t *testing.T){ +// Test revidInst with a Raspivid h264 input +func TestRaspividH264Input(t *testing.T){ config := Config{ Input: Raspivid, Output: File, @@ -78,6 +70,24 @@ func TestRaspividInput(t *testing.T){ revidInst.Stop() } - - - +// Test revidInst with a raspivid mjpeg input +func TestRaspividMJPEGInput(t *testing.T){ + config := Config{ + Input: Raspivid, + InputCodec: mjpeg, + Output: File, + OutputFileName: "output/TestRaspividMjpegOutput.mjpeg", + Width: "1280", + Height: "720", + Bitrate: "0", + Quantization: "35", + FrameRate: "25", + } + revidInst, err := NewRevidInstance(config) + if err != nil { + t.Errorf("Should not of have got an error!") + } + revidInst.Start() + time.Sleep(100*time.Second) + revidInst.Stop() +}