mirror of https://bitbucket.org/ausocean/av.git
Working on cleaning up code and comments
This commit is contained in:
parent
7b50a4e95c
commit
92a2b033c9
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
NAME
|
||||
BitrateCalculator.go - is a simple struct with methods to allow for easy
|
||||
calculation of bitrate.
|
||||
|
||||
DESCRIPTION
|
||||
See Readme.md
|
||||
|
||||
AUTHOR
|
||||
Saxon Nelson-Milton <saxon.milton@gmail.com>
|
||||
|
||||
LICENSE
|
||||
BitrateCalculator.go is 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 [GNU licenses](http://www.gnu.org/licenses).
|
||||
*/
|
||||
|
||||
package bitrate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BitrateCalculator provides fields and methods to allow calculation of bitrate
|
||||
type BitrateCalculator struct {
|
||||
outputDelay int // sec
|
||||
now time.Time
|
||||
prev time.Time
|
||||
startedBefore bool
|
||||
elapsedTime time.Duration
|
||||
lastDisplayTime time.Time
|
||||
}
|
||||
|
||||
// Place this at the start of the code segment that you would like to time
|
||||
func (bc *BitrateCalculator) Start(outputDelay int) {
|
||||
if outputDelay >= 0 {
|
||||
bc.outputDelay = outputDelay
|
||||
} else {
|
||||
bc.outputDelay = 0
|
||||
}
|
||||
bc.prev = time.Now()
|
||||
if !bc.startedBefore {
|
||||
bc.startedBefore = true
|
||||
bc.elapsedTime = time.Duration(0)
|
||||
bc.lastDisplayTime = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
// Place this at the end of the code segment that you would like to time
|
||||
func (bc *BitrateCalculator) Stop(noOfKB float64) (bitrate int64) {
|
||||
bc.now = time.Now()
|
||||
deltaTime := bc.now.Sub(bc.prev)
|
||||
if bc.now.Sub(bc.lastDisplayTime) > time.Duration(bc.outputDelay)*time.Second {
|
||||
bitrate = int64(noOfKB / float64(deltaTime/1e9))
|
||||
fmt.Printf("Bitrate: %d kbps\n", bitrate)
|
||||
bc.elapsedTime = time.Duration(0)
|
||||
bc.lastDisplayTime = bc.now
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
NAME
|
||||
BitrateCalculator_test.go - is a file that may be used to test the
|
||||
BitrateCalculator.go file using the golang testing utilities
|
||||
|
||||
DESCRIPTION
|
||||
See Readme.md
|
||||
|
||||
AUTHOR
|
||||
Saxon Nelson-Milton <saxon.milton@gmail.com>
|
||||
|
||||
LICENSE
|
||||
BitrateCalculator_test.go is 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 [GNU licenses](http://www.gnu.org/licenses).
|
||||
*/
|
||||
|
||||
package bitrate
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Some consts used over duration of testing
|
||||
const (
|
||||
bitrateDelay1 = 0 // s
|
||||
bitrateDelay2 = 5 // s
|
||||
amountOfData = 100000.0
|
||||
testTime = 2500.0 // ms
|
||||
)
|
||||
|
||||
// This will be the BitrateCalculator object we use over testing
|
||||
var bitrateCalc BitrateCalculator
|
||||
|
||||
// Simple test to check that the calculator can calc bitrate over a given
|
||||
// duration of time
|
||||
func Test1(t *testing.T) {
|
||||
bitrateCalc = BitrateCalculator{}
|
||||
bitrateCalc.Start(bitrateDelay1)
|
||||
time.Sleep(testTime * time.Millisecond)
|
||||
currentBitrate := int64(bitrateCalc.Stop(amountOfData))
|
||||
actualBitrate := int64(amountOfData / ((testTime * time.Millisecond) / 1e9))
|
||||
if currentBitrate != actualBitrate {
|
||||
t.Errorf("Bitrate is wrong! Calculated: %v Actual %v", currentBitrate, actualBitrate)
|
||||
}
|
||||
}
|
||||
|
||||
// Now let's check that the output delay feature works
|
||||
func Test2(t *testing.T) {
|
||||
bitrateCalc = BitrateCalculator{}
|
||||
var currentBitrate int64
|
||||
for i := 0; i < 2; i++ {
|
||||
bitrateCalc.Start(bitrateDelay2)
|
||||
time.Sleep(testTime * time.Millisecond)
|
||||
currentBitrate = int64(bitrateCalc.Stop(amountOfData))
|
||||
if i == 0 && currentBitrate != 0 {
|
||||
t.Errorf("The bitrate calc did not delay outputting!")
|
||||
}
|
||||
time.Sleep(6000 * time.Millisecond)
|
||||
}
|
||||
actualBitrate := int64(amountOfData / ((testTime * time.Millisecond) / 1e9))
|
||||
if currentBitrate != actualBitrate {
|
||||
t.Errorf("Bitrate is wrong! Calculated: %v Actual %v", currentBitrate, actualBitrate)
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package efficientbuffer
|
||||
|
||||
type dataBlock struct {
|
||||
address []byte // Address of the data block (slice)
|
||||
lowerBound int // Lower bound of the data we're interested in
|
||||
upperBound int // Upper bound of the data we're interested in
|
||||
startIndex int // Index in our EffSlice
|
||||
}
|
||||
|
||||
type EffSlice struct {
|
||||
data map[int](*dataChunk)
|
||||
}
|
||||
|
||||
func (s *EffSlice)GetElement(index int) byte {
|
||||
}
|
||||
|
||||
func (s *EffSlice)AsByteSlice() []byte {
|
||||
|
||||
}
|
||||
|
||||
func (s *EffSlice)Append(data *EffSlice){
|
||||
}
|
||||
|
||||
func (s *EffSlice)Append(data []byte){
|
||||
}
|
||||
|
||||
func (s *EffSlice)Len(){
|
||||
}
|
92
flv/FLV.go
92
flv/FLV.go
|
@ -1,3 +1,30 @@
|
|||
/*
|
||||
NAME
|
||||
FLV.go
|
||||
|
||||
DESCRIPTION
|
||||
See Readme.md
|
||||
|
||||
AUTHORS
|
||||
Saxon A. Nelson-Milton <saxon@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
FLV.go is 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 [GNU licenses](http://www.gnu.org/licenses).
|
||||
*/
|
||||
|
||||
package flv
|
||||
|
||||
import (
|
||||
|
@ -13,29 +40,36 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
VideoTagType = 9
|
||||
AudioTagType = 8
|
||||
KeyFrameType = 1
|
||||
InterFrameType = 2
|
||||
H264 = 7
|
||||
AVCNALU = 1
|
||||
SequenceHeader = 0
|
||||
DataHeaderLength = 5
|
||||
VideoTagType = 9
|
||||
AudioTagType = 8
|
||||
KeyFrameType = 1
|
||||
InterFrameType = 2
|
||||
H264 = 7
|
||||
AVCNALU = 1
|
||||
SequenceHeader = 0
|
||||
DataHeaderLength = 5
|
||||
NoTimestampExtension = 0
|
||||
AACAudioFormat = 10
|
||||
PCMAudioFormat = 0
|
||||
AACAudioFormat = 10
|
||||
PCMAudioFormat = 0
|
||||
)
|
||||
|
||||
var flvHeaderCode = []byte{0x46, 0x4C, 0x56}
|
||||
|
||||
type Header struct {
|
||||
AudioFlag bool
|
||||
VideoFlag bool
|
||||
}
|
||||
|
||||
func btb(b bool) byte {
|
||||
return tools.BoolToByte(b)
|
||||
}
|
||||
|
||||
func (h *Header) ToByteSlice() (output []byte) {
|
||||
output = make([]byte, 0, headerLength)
|
||||
output = append(output, []byte{0x46, 0x4C, 0x56,
|
||||
output = append(output, flvheaderCode...)
|
||||
output = append(output, []byte {
|
||||
version,
|
||||
0x00 | tools.BoolToByte(h.AudioFlag)<<2 | tools.BoolToByte(h.VideoFlag),
|
||||
0x00 | btb(h.AudioFlag)<<2 | btb(h.VideoFlag),
|
||||
0x00, 0x00, 0x00, byte(9),
|
||||
}...)
|
||||
fmt.Println(output)
|
||||
|
@ -47,10 +81,10 @@ type VideoTag struct {
|
|||
DataSize uint32
|
||||
Timestamp uint32
|
||||
TimestampExtended uint32
|
||||
FrameType byte
|
||||
Codec byte
|
||||
PacketType byte
|
||||
CompositionTime uint32
|
||||
FrameType byte
|
||||
Codec byte
|
||||
PacketType byte
|
||||
CompositionTime uint32
|
||||
Data []byte
|
||||
PrevTagSize uint32
|
||||
}
|
||||
|
@ -66,10 +100,14 @@ func (t *VideoTag) ToByteSlice() (output []byte) {
|
|||
byte(t.Timestamp >> 8),
|
||||
byte(t.Timestamp),
|
||||
byte(t.TimestampExtended),
|
||||
0x00, 0x00, 0x00,
|
||||
0x00 | byte(t.FrameType << 4) | byte(t.Codec),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00 | byte(t.FrameType<<4) | byte(t.Codec),
|
||||
t.PacketType,
|
||||
byte(t.CompositionTime >> 16),byte(t.CompositionTime >> 8),byte(t.CompositionTime),
|
||||
byte(t.CompositionTime >> 16),
|
||||
byte(t.CompositionTime >> 8),
|
||||
byte(t.CompositionTime),
|
||||
}...)
|
||||
output = append(output, t.Data...)
|
||||
output = append(output, []byte{
|
||||
|
@ -86,11 +124,11 @@ type AudioTag struct {
|
|||
DataSize uint32
|
||||
Timestamp uint32
|
||||
TimestampExtended uint32
|
||||
SoundFormat uint8
|
||||
SoundRate uint8
|
||||
SoundSize bool
|
||||
SoundType bool
|
||||
Data []byte
|
||||
SoundFormat uint8
|
||||
SoundRate uint8
|
||||
SoundSize bool
|
||||
SoundType bool
|
||||
Data []byte
|
||||
PrevTagSize uint32
|
||||
}
|
||||
|
||||
|
@ -105,8 +143,10 @@ func (t *AudioTag) ToByteSlice() (output []byte) {
|
|||
byte(t.Timestamp >> 8),
|
||||
byte(t.Timestamp),
|
||||
byte(t.TimestampExtended),
|
||||
0x00, 0x00, 0x00,
|
||||
byte(t.SoundFormat << 4) | byte(t.SoundRate<<2) | byte(tools.BoolToByte(t.SoundSize)<<1) | byte(tools.BoolToByte(t.SoundType)),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
byte(t.SoundFormat<<4) | byte(t.SoundRate<<2) | btb(t.SoundSize)<<1 | btb(t.SoundType),
|
||||
}...)
|
||||
output = append(output, t.Data...)
|
||||
output = append(output, []byte{
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
/*
|
||||
NAME
|
||||
Config.go
|
||||
|
||||
DESCRIPTION
|
||||
See Readme.md
|
||||
|
||||
AUTHORS
|
||||
Saxon A. Nelson-Milton <saxon@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
Config.go is 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 [GNU licenses](http://www.gnu.org/licenses).
|
||||
*/
|
||||
|
||||
package revid
|
||||
|
||||
import (
|
||||
|
@ -19,9 +46,10 @@ type Config struct {
|
|||
InputCodec uint8
|
||||
Output uint8
|
||||
RtmpEncodingMethod uint8
|
||||
RtmpMethod uint8
|
||||
Packetization uint8
|
||||
FramesPerClip int
|
||||
RtmpUrl string
|
||||
RtmpMethod uint8
|
||||
Bitrate string
|
||||
OutputFileName string
|
||||
InputFileName string
|
||||
|
@ -31,7 +59,6 @@ type Config struct {
|
|||
HttpAddress string
|
||||
Quantization string
|
||||
Timeout string
|
||||
Packetization uint8
|
||||
IntraRefreshPeriod string
|
||||
Logger smartLogger.LogInstance
|
||||
}
|
||||
|
@ -43,7 +70,7 @@ const (
|
|||
Rtp = 2
|
||||
H264Codec = 3
|
||||
File = 4
|
||||
Http = 5
|
||||
Http = 5
|
||||
H264 = 6
|
||||
Mjpeg = 7
|
||||
None = 8
|
||||
|
@ -52,7 +79,7 @@ const (
|
|||
Ffmpeg = 11
|
||||
Revid = 12
|
||||
Flv = 13
|
||||
LibRtmp = 14
|
||||
LibRtmp = 14
|
||||
)
|
||||
|
||||
// Default config settings
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
NAME
|
||||
revid - a testbed for re-muxing and re-directing video streams as MPEG-TS over various protocols.
|
||||
RevidInstance.go
|
||||
|
||||
DESCRIPTION
|
||||
See Readme.md
|
||||
|
||||
AUTHORS
|
||||
Alan Noble <anoble@gmail.com>
|
||||
Saxon A. Nelson-Milton <saxon.milton@gmail.com>
|
||||
Saxon A. Nelson-Milton <saxon@ausocean.org>
|
||||
Alan Noble <alan@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
revid is Copyright (C) 2017 Alan Noble.
|
||||
revid is 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
|
||||
|
@ -67,7 +67,8 @@ const (
|
|||
bitrateTime = 60
|
||||
mjpegParserInChanLen = 100000
|
||||
ffmpegPath = "/home/saxon/bin/ffmpeg"
|
||||
rtmpConnectionTimout = 10
|
||||
rtmpConnectionTimout = 10
|
||||
outputChanSize = 10000
|
||||
)
|
||||
|
||||
// Log Types
|
||||
|
@ -109,8 +110,8 @@ type revidInst struct {
|
|||
setupOutput func() error
|
||||
getFrame func() []byte
|
||||
flushData func()
|
||||
sendClip func(clip []byte) error
|
||||
rtmpInst rtmp.RTMPSession
|
||||
sendClip func(clip []byte) error
|
||||
rtmpInst rtmp.RTMPSession
|
||||
}
|
||||
|
||||
// NewRevidInstance returns a pointer to a new revidInst with the desired
|
||||
|
@ -123,7 +124,7 @@ func NewRevidInstance(config Config) (r *revidInst, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.outputChan = make(chan []byte, 10000)
|
||||
r.outputChan = make(chan []byte, outputchanSize)
|
||||
r.parser.Start()
|
||||
go r.packClips()
|
||||
r.Log(Info, "New revid instance created! config is:")
|
||||
|
@ -145,6 +146,7 @@ func (r *revidInst) ChangeState(config Config) error {
|
|||
return errors.New("Config struct is bad!: " + err.Error())
|
||||
}
|
||||
r.config = config
|
||||
|
||||
switch r.config.Output {
|
||||
case File:
|
||||
r.sendClip = r.sendClipToFile
|
||||
|
@ -161,6 +163,7 @@ func (r *revidInst) ChangeState(config Config) error {
|
|||
case Http:
|
||||
r.sendClip = r.sendClipToHTTP
|
||||
}
|
||||
|
||||
switch r.config.Input {
|
||||
case Raspivid:
|
||||
r.setupInput = r.setupInputForRaspivid
|
||||
|
@ -176,24 +179,29 @@ func (r *revidInst) ChangeState(config Config) error {
|
|||
r.Log(Info, "Using MJPEG parser!")
|
||||
r.parser = parser.NewMJPEGParser(mjpegParserInChanLen)
|
||||
}
|
||||
if r.config.Packetization == None {
|
||||
|
||||
switch r.config.Packetization {
|
||||
case None:
|
||||
// no packetisation - Revid output chan grabs raw data straight from parser
|
||||
r.parser.SetOutputChan(r.outputChan)
|
||||
r.getFrame = r.getFrameNoPacketization
|
||||
} else {
|
||||
switch r.config.Packetization {
|
||||
case Mpegts:
|
||||
r.Log(Info, "Using MPEGTS packetisation!")
|
||||
frameRateAsInt, _ := strconv.Atoi(r.config.FrameRate)
|
||||
r.generator = generator.NewTsGenerator(uint(frameRateAsInt))
|
||||
case Flv:
|
||||
r.Log(Info, "Using FLV packetisation!")
|
||||
frameRateAsInt, _ := strconv.Atoi(r.config.FrameRate)
|
||||
r.generator = generator.NewFlvGenerator(true, true, uint(frameRateAsInt))
|
||||
}
|
||||
r.getFrame = r.getFramePacketization
|
||||
r.parser.SetOutputChan(r.generator.GetInputChan())
|
||||
r.generator.Start()
|
||||
goto noPacketizationSetup
|
||||
case Mpegts:
|
||||
r.Log(Info, "Using MPEGTS packetisation!")
|
||||
frameRateAsInt, _ := strconv.Atoi(r.config.FrameRate)
|
||||
r.generator = generator.NewTsGenerator(uint(frameRateAsInt))
|
||||
case Flv:
|
||||
r.Log(Info, "Using FLV packetisation!")
|
||||
frameRateAsInt, _ := strconv.Atoi(r.config.FrameRate)
|
||||
r.generator = generator.NewFlvGenerator(true, true, uint(frameRateAsInt))
|
||||
}
|
||||
// We have packetization of some sort, so we want to send data to Generator
|
||||
// to perform packetization
|
||||
r.getFrame = r.getFramePacketization
|
||||
r.parser.SetOutputChan(r.generator.GetInputChan())
|
||||
r.generator.Start()
|
||||
noPacketizationSetup:
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -214,7 +222,7 @@ func (r *revidInst) IsRunning() bool {
|
|||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
// and packetising (if theres packetization) to a defined output.
|
||||
func (r *revidInst) Start() {
|
||||
if r.isRunning {
|
||||
r.Log(Warning, "revidInst.Start() called but revid already running!")
|
||||
|
@ -236,6 +244,7 @@ func (r *revidInst) Stop() {
|
|||
if r.isRunning {
|
||||
r.Log(Info, "Stopping revid!")
|
||||
r.isRunning = false
|
||||
// If a cmd process is running, we kill!
|
||||
if r.cmd != nil {
|
||||
r.cmd.Process.Kill()
|
||||
}
|
||||
|
@ -244,39 +253,32 @@ func (r *revidInst) Stop() {
|
|||
}
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
// getFrameNoPacketization gets a frame directly from the revid output chan
|
||||
// as we don't need to go through the generator with no packetization settings
|
||||
func (r *revidInst) getFrameNoPacketization() []byte {
|
||||
return <-r.outputChan
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
// getFramePacketization gets a frame from the generators output chan - the
|
||||
// the generator being an mpegts or flv generator depending on the config
|
||||
func (r *revidInst) getFramePacketization() []byte {
|
||||
return <-(r.generator.GetOutputChan())
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
func (r *revidInst) flushDataNoPacketisation() {
|
||||
// flushDataPacketization removes data from the revid inst's coutput chan
|
||||
func (r *revidInst) flushData() {
|
||||
for len(r.outputChan) > 0 {
|
||||
<-(r.outputChan)
|
||||
}
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
func (r *revidInst) flushDataMpegtsPacketisation() {
|
||||
for len(r.generator.GetOutputChan()) > 0 {
|
||||
<-(r.generator.GetOutputChan())
|
||||
}
|
||||
}
|
||||
|
||||
// packClips takes data segments; whether that be tsPackets or jpeg frames and
|
||||
// packs them into clips 1s long.
|
||||
// packClips takes data segments; whether that be tsPackets or mjpeg frames and
|
||||
// packs them into clips consisting of the amount frames specified in the config
|
||||
func (r *revidInst) packClips() {
|
||||
clipSize := 0
|
||||
packetCount := 0
|
||||
for {
|
||||
// Get some memory from the ring buffer for out clip
|
||||
if clip, err := r.ringBuffer.Get(); err != nil {
|
||||
r.Log(Error, err.Error())
|
||||
r.Log(Warning, "Clearing output chan!")
|
||||
|
@ -334,7 +336,8 @@ func (r *revidInst) outputClips() {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
// let the ringbuffer know that we're done with the memory we grabbed when
|
||||
// we call ringBuffer.Get()
|
||||
if err := r.ringBuffer.DoneReading(); err != nil {
|
||||
r.Log(Error, err.Error())
|
||||
}
|
||||
|
@ -353,8 +356,7 @@ func (r *revidInst) outputClips() {
|
|||
}
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
// senClipToFile writes the passed clip to a file
|
||||
func (r *revidInst) sendClipToFile(clip []byte) error {
|
||||
_,err := r.outputFile.Write(clip)
|
||||
if err != nil {
|
||||
|
@ -366,9 +368,7 @@ func (r *revidInst) sendClipToFile(clip []byte) error {
|
|||
// sendClipToHTTP takes a clip and an output url and posts through http.
|
||||
func (r *revidInst) sendClipToHTTP(clip []byte) error {
|
||||
timeout := time.Duration(httpTimeOut * time.Second)
|
||||
client := http.Client{
|
||||
Timeout: timeout,
|
||||
}
|
||||
client := http.Client{Timeout: timeout}
|
||||
url := r.config.HttpAddress+strconv.Itoa(len(clip))
|
||||
r.Log(Debug, fmt.Sprintf("Posting %s (%d bytes)\n", url, len(clip)))
|
||||
resp, err := client.Post(url, "video/mp2t", bytes.NewReader(clip)) // lighter than NewBuffer
|
||||
|
@ -385,23 +385,21 @@ func (r *revidInst) sendClipToHTTP(clip []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
func (r *revidInst) sendClipToFfmpegRtmp(clip []byte) error {
|
||||
_, err := r.ffmpegStdin.Write(clip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
// sendClipToFfmpegRtmp sends the clip over the current rtmp connection using
|
||||
// an ffmpeg process.
|
||||
func (r *revidInst) sendClipToFfmpegRtmp(clip []byte) (err error) {
|
||||
_, err = r.ffmpegStdin.Write(clip)
|
||||
return
|
||||
}
|
||||
|
||||
// sendClipToLibRtmp send the clip over the current rtmp connection using the
|
||||
// c based librtmp library
|
||||
func (r *revidInst) sendClipToLibRtmp(clip []byte) (err error) {
|
||||
err = r.rtmpInst.WriteFrame(clip,uint(len(clip)))
|
||||
return
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
// setupOutputForFfmpegRtmp sets up output to rtmp using an ffmpeg process
|
||||
func (r *revidInst) setupOutputForFfmpegRtmp() error {
|
||||
r.ffmpegCmd = exec.Command(ffmpegPath,
|
||||
"-f", "h264",
|
||||
|
@ -434,20 +432,23 @@ func (r *revidInst) setupOutputForFfmpegRtmp() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// setupOutputForLibRtmp sets up rtmp output using the wrapper for the c based
|
||||
// librtmp library - makes connection and starts comms etc.
|
||||
func (r *revidInst) setupOutputForLibRtmp() (err error) {
|
||||
r.rtmpInst = rtmp.NewRTMPSession(r.config.RtmpUrl, rtmpConnectionTimout)
|
||||
err = r.rtmpInst.StartSession()
|
||||
//go r.testRtmp(5000)
|
||||
// go r.testRtmp(5000)
|
||||
return
|
||||
}
|
||||
|
||||
// setupOutputForFile sets up an output file to output data to
|
||||
func (r *revidInst) setupOutputForFile() (err error) {
|
||||
r.outputFile, err = os.Create(r.config.OutputFileName)
|
||||
return
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// and packetising to a defined output.
|
||||
// setupInputForRaspivid sets up things for input from raspivid i.e. starts
|
||||
// a raspivid process and pipes it's data output.
|
||||
func (r *revidInst) setupInputForRaspivid() error {
|
||||
r.Log(Info, "Starting raspivid!")
|
||||
switch r.config.InputCodec {
|
||||
|
@ -485,7 +486,7 @@ func (r *revidInst) setupInputForRaspivid() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Start invokes a revidInst to start processing video from a defined input
|
||||
// setupInputForFile sets things up for getting input from a file
|
||||
func (r *revidInst) setupInputForFile() error {
|
||||
fps,_ := strconv.Atoi(r.config.FrameRate)
|
||||
r.parser.SetDelay( uint( float64(1000) / float64(fps) ) )
|
||||
|
@ -493,31 +494,40 @@ func (r *revidInst) setupInputForFile() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// testRtmp is useful to check robustness of connections. Intended to be run as
|
||||
// goroutine. After every 'delayTime' the rtmp connection is ended and then
|
||||
// restarted
|
||||
func (r *revidInst)testRtmp(delayTime uint){
|
||||
for {
|
||||
time.Sleep(time.Duration(delayTime)*time.Millisecond)
|
||||
time.Sleep(time.Duration(delayTime)*time.Millisecond)
|
||||
r.rtmpInst.EndSession()
|
||||
r.rtmpInst.StartSession()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// readCamera reads data from the defined camera while the revidInst is running.
|
||||
// TODO: use ringbuffer here instead of allocating mem every time!
|
||||
func (r *revidInst) readCamera() {
|
||||
r.Log(Info, "Reading camera data!")
|
||||
for r.isRunning {
|
||||
data := make([]byte, 1)
|
||||
_, err := io.ReadFull(r.inputReader, data)
|
||||
switch {
|
||||
// We know this means we're getting nothing from the cam
|
||||
case err != nil && err.Error() == "EOF" && r.isRunning:
|
||||
r.Log(Error, "No data from camera!")
|
||||
time.Sleep(5 * time.Second)
|
||||
// We don't know what this one is, so let's just output the error to the log
|
||||
case err != nil && r.isRunning:
|
||||
r.Log(Error, err.Error())
|
||||
// Everything is fine! send the data to the parser to split it up into
|
||||
// frames/access units
|
||||
default:
|
||||
r.parser.GetInputChan() <- data[0]
|
||||
}
|
||||
}
|
||||
r.Log(Info, "Out of reading routine!")
|
||||
r.Log(Info, "Not trying to read from camera anymore!")
|
||||
}
|
||||
|
||||
// readFile reads data from the defined file while the revidInst is running.
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
/*
|
||||
NAME
|
||||
MpegTs.go - provides a data structure intended to encapsulate the properties
|
||||
of an MpegTs packet.
|
||||
revid_test.go
|
||||
|
||||
DESCRIPTION
|
||||
See Readme.md
|
||||
|
||||
AUTHOR
|
||||
Saxon Nelson-Milton <saxon.milton@gmail.com>
|
||||
Saxon Nelson-Milton <saxon@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
MpegTs.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
|
||||
revid_test.go is 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
|
||||
|
@ -33,7 +32,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
// Test revidInst with a file input
|
||||
func TestFileInput(t *testing.T){
|
||||
config := Config{
|
||||
|
@ -94,9 +93,9 @@ func TestRaspividMJPEGInput(t *testing.T){
|
|||
time.Sleep(20*time.Second)
|
||||
revidInst.Stop()
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
|
||||
// Test revidInst with rtmp output
|
||||
func TestRtmpOutput(t *testing.T){
|
||||
config := Config{
|
||||
|
@ -120,9 +119,9 @@ func TestRtmpOutput(t *testing.T){
|
|||
time.Sleep(120*time.Second)
|
||||
revidInst.Stop()
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
|
||||
// Test h264 inputfile to flv output files
|
||||
func TestFlvOutputFile(t *testing.T) {
|
||||
config := Config{
|
||||
|
@ -143,7 +142,7 @@ func TestFlvOutputFile(t *testing.T) {
|
|||
time.Sleep(30 * time.Second)
|
||||
revidInst.Stop()
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// Test h264 inputfile to flv format into rtmp using librtmp c wrapper
|
||||
func TestRtmpOutputUsingLibRtmp(t *testing.T){
|
||||
|
|
Loading…
Reference in New Issue