Just updating remote

This commit is contained in:
Saxon Milton 2018-03-13 11:24:37 +10:30
parent ce790ed2b0
commit bfb31136c8
7 changed files with 144 additions and 355 deletions

View File

@ -131,8 +131,8 @@ type MpegTsPacket struct {
payload []byte // Mpeg ts payload payload []byte // Mpeg ts payload
} }
// TODO: make payload private considering we now have FillPayload method // FillPayload takes a channel and fills the packets payload field until the
// channel is empty or we've the packet reaches capacity
func (p *MpegTsPacket) FillPayload(channel chan byte){ func (p *MpegTsPacket) FillPayload(channel chan byte){
p.Payload = make([]byte,0,mpegtsPayloadSize) p.Payload = make([]byte,0,mpegtsPayloadSize)
currentPktLength := 6 + int(btb(p.PCRF))*6+int(btb(p.OPCRF))*6+ currentPktLength := 6 + int(btb(p.PCRF))*6+int(btb(p.OPCRF))*6+
@ -143,10 +143,14 @@ func (p *MpegTsPacket) FillPayload(channel chan byte){
} }
} }
// btb is a simple wrapper function for tools.BoolToByte which takes a bool
// and returns an equivalent byte
func btb(b bool) byte { func btb(b bool) byte {
return tools.BoolToByte(b) return tools.BoolToByte(b)
} }
// ToByteSlice interprets the fields of the ts packet instance and outputs a
// corresponding byte slice
func (p *MpegTsPacket) ToByteSlice() (output []byte) { func (p *MpegTsPacket) ToByteSlice() (output []byte) {
stuffingLength := 182-len(p.Payload)-len(p.TPD)-int(btb(p.PCRF))*6- stuffingLength := 182-len(p.Payload)-len(p.TPD)-int(btb(p.PCRF))*6-
int(btb(p.OPCRF))*6 - int(btb(p.SPF)) int(btb(p.OPCRF))*6 - int(btb(p.SPF))

View File

@ -1,50 +0,0 @@
/*
NAME
PES.go -
DESCRIPTION
See Readme.md
AUTHOR
Saxon Nelson-Milton <saxon.milton@gmail.com>
LICENSE
PES.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 nal
type NalAccessUnit struct {
SPS []byte
PPS []byte
SEI [][]byte
Data [][]byte
}
func (u *NalAccessUnit) AsAnnexB() (output []byte) {
startCode := []byte{ 0x00,0x00,0x01}
AUD := []byte{0x09, 0xF0}
format := [][]byte{startCode, AUD, startCode, u.SPS, startCode, u.PPS }
for i := range format {
output = append(output,format[i]...)
}
for i := range u.SEI {
output = append(output, append(startCode,u.SEI[i]...)...)
}
for i := range u.Data {
output = append(output, append(startCode,u.Data[i]...)...)
}
return
}

View File

@ -1,101 +0,0 @@
/*
NAME
PES.go -
DESCRIPTION
See Readme.md
AUTHOR
Saxon Nelson-Milton <saxon.milton@gmail.com>
LICENSE
PES.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 nal
type NALUnit interface {
ToByteSlice() []byte
GetType() byte
}
type NALSpsPps struct {
Data []byte
}
type NALFragment struct {
ThreeNUBs byte
FragmentType byte
Start bool
End bool
Reserved bool
FiveNUBs byte
Data []byte
}
func GetNalType(unit []byte) byte {
return unit[0] & 0x1F
}
/*
First byte: [ 3 NAL UNIT BITS | 5 FRAGMENT TYPE BITS]
Second byte: [ START BIT | END BIT | RESERVED BIT | 5 NAL UNIT BITS]
Other bytes: [... VIDEO FRAGMENT DATA...]
*/
func ParseNALFragment(unit []byte) (u *NALFragment) {
u = new(NALFragment)
u.ThreeNUBs = (unit[0] & 0xE0) >> 5
u.FragmentType = unit[0] & 0x1F
u.Start = (unit[1] & 0x80) != 0
u.End = (unit[1] & 0x40) != 0
u.Reserved = (unit[1] & 0x20) != 0
u.FiveNUBs = unit[1] & 0x1F
u.Data = make([]byte,len(unit[2:]))
copy(u.Data[:],unit[2:])
return
}
func ParseNALSpsPps(unit []byte)(u *NALSpsPps){
u = new(NALSpsPps)
u.Data = make([]byte,len(unit))
copy(u.Data[:],unit[:])
return
}
func (u *NALFragment) ToByteSlice() (output []byte) {
output = make([]byte, 2+len(u.Data))
output[0] = ( u.ThreeNUBs << 5 ) | u.FragmentType
output[1] = boolToByte( u.Start ) << 7 |
boolToByte( u.End ) << 6 |
boolToByte( u.Reserved ) << 5 |
u.FiveNUBs
copy(output[2:],u.Data)
return
}
func (u *NALFragment) GetType() byte {
return GetNalType(u.ToByteSlice())
}
func (u *NALSpsPps) GetType() byte {
return GetNalType(u.ToByteSlice())
}
func (u *NALSpsPps) ToByteSlice() (output []byte){
output = make([]byte,len(u.Data))
output = u.Data
return
}

View File

@ -1,118 +0,0 @@
/*
NAME
MpegTs.go - provides a data structure intended to encapsulate the properties
of an MpegTs packet.
DESCRIPTION
See Readme.md
AUTHOR
Saxon Nelson-Milton <saxon.milton@gmail.com>
LICENSE
MpegTs.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 nal
import (
"testing"
)
var parseInput = []byte{
0x6C, // 3NalUnitBits = 101(5), Fragment type = 1100 (type = 12 )
0x94, // starbit = 1, endbit = 0, Reservedbit = 0, 5NalUnitBits = 10100 (20)
0x8E, // 10001110 random frame byte
0x26, // 00100110 random frame byte
0xD0, // 11010000 random frame byte
}
var expectedParsing = []interface{}{
byte(3),
byte(12),
bool(true),
bool(false),
bool(false),
byte(20),
[]byte{0x8E, 0x26, 0xD0},
}
const (
nalTestType = 12
)
func TestNalFragmentParsing(t *testing.T) {
nalUnit := ParseNALFragment(parseInput)
value := reflect.ValueOf(*nalUnit)
length := value.NumField()
fields := make([]interface{}, length)
for ii := 0; ii < length; ii++ {
fields[ii] = value.Field(ii).Interface()
}
for ii := range fields {
if !reflect.DeepEqual(fields[ii], expectedParsing[ii]) {
t.Errorf("Bad Parsing! Field: %v wanted: %v got: %v\n", ii, expectedParsing[ii],
fields[ii])
}
}
}
func TestNalFragmentToByteSlice(t *testing.T) {
nalUnit := ParseNALFragment(parseInput)
output := nalUnit.ToByteSlice()
for ii := range output {
if output[ii] != parseInput[ii] {
t.Errorf("Bad conversion to byte slice at %vth byte! wanted: %v got: %v",
parseInput[ii], output[ii])
}
}
}
func TestNalFragmentType(t *testing.T) {
nalUnit := ParseNALFragment(parseInput)
nalType := nalUnit.GetType()
if nalType != nalTestType {
t.Errorf("Returned wrong type!")
}
}
func TestNalSpsPpsParsing(t *testing.T) {
nalSpsPps := ParseNALSpsPps(parseInput)
for ii := range parseInput {
if nalSpsPps.Data[ii] != parseInput[ii] {
t.Errorf("Bad Parsing! Byte: %v wanted: %v got: %v\n", ii, parseInput[ii],
nalSpsPps.Data[ii])
}
}
}
func TestNalSpsPpsToByteSlice(t *testing.T) {
nalSpsPps := ParseNALSpsPps(parseInput)
nalSpsPpsByteSlice := nalSpsPps.ToByteSlice()
for ii := range parseInput {
if nalSpsPpsByteSlice[ii] != parseInput[ii] {
t.Errorf("Bad conversion to byte slice! Byte: %v wanted: %v got: %v\n", ii,
parseInput[ii], nalSpsPpsByteSlice[ii])
}
}
}
func TestNalSpsPpsType(t *testing.T) {
nalSpsPps := ParseNALSpsPps(parseInput)
if nalSpsPps.GetType() != nalTestType {
t.Errorf("Returned wrong type!")
}
}

View File

@ -1,16 +1,15 @@
/* /*
NAME NAME
RtpToTsConverter.go - provides utilities for the conversion of Rtp packets H264Parser.go
to equivalent MpegTs packets.
DESCRIPTION DESCRIPTION
See Readme.md See Readme.md
AUTHOR AUTHOR
Saxon Nelson-Milton <saxon.milton@gmail.com> Saxon Nelson-Milton <saxon@ausocean.org>
LICENSE LICENSE
RtpToTsConverter.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) H264Parser.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them 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 under the terms of the GNU General Public License as published by the
@ -28,74 +27,96 @@ LICENSE
package parser package parser
import ( import (
//"bitbucket.org/ausocean/av/itut" //"bitbucket.org/ausocean/av/itut"
"../itut" "../itut"
_"fmt" _ "fmt"
"time" "time"
) )
const (
inputChanSize = 100000
outputBufferSize = 10000
)
// h264Parser provides properties and methods to allow for the parsing of a
// h264 stream - i.e. to allow extraction of the individual access units
type h264Parser struct { type h264Parser struct {
inputBuffer []byte inputBuffer []byte
isParsing bool isParsing bool
parserOutputChanRef chan []byte parserOutputChanRef chan []byte
userOutputChanRef chan []byte userOutputChanRef chan []byte
inputChan chan byte inputChan chan byte
delay uint delay uint
} }
// NewH264Parser returns an instance of the h264Parser struct
func NewH264Parser() (p *h264Parser) { func NewH264Parser() (p *h264Parser) {
p = new(h264Parser) p = new(h264Parser)
p.isParsing = true p.isParsing = true
p.inputChan = make(chan byte, 100000) p.inputChan = make(chan byte, inputChanSize)
p.delay = 0 p.delay = 0
return return
} }
func (p* h264Parser)Stop(){ // Stop simply sets the isParsing flag to false to indicate to the parser that
p.isParsing = false // we don't want to interpret incoming data anymore - this will also make the
// parser jump out of the parse func
func (p *h264Parser) Stop() {
p.isParsing = false
} }
func (p *h264Parser)Start(){ // Start starts the parse func as a goroutine so that incoming data is interpreted
go p.parse() func (p *h264Parser) Start() {
go p.parse()
} }
func (p *h264Parser)SetDelay(delay uint){ // SetDelay sets a delay inbetween each buffer output. Useful if we're parsing
p.delay = delay // a file but want to replicate the speed of incoming video frames from a
// camera
func (p *h264Parser) SetDelay(delay uint) {
p.delay = delay
} }
func (p *h264Parser)GetInputChan() chan byte { // GetInputChan returns a handle to the input channel of the parser
return p.inputChan func (p *h264Parser) GetInputChan() chan byte {
return p.inputChan
} }
func (p *h264Parser)GetOutputChan() chan []byte { // GetOutputChan returns a handle to the output chan of the parser
return p.userOutputChanRef func (p *h264Parser) GetOutputChan() chan []byte {
return p.userOutputChanRef
} }
func (p *h264Parser)SetOutputChan(aChan chan []byte){ // SetOutputChan sets the parser output chan to the passed output chan. This is
p.parserOutputChanRef = aChan // useful if we want the parser output to go directly to a generator of some sort
p.userOutputChanRef = aChan // for packetization.
func (p *h264Parser) SetOutputChan(aChan chan []byte) {
p.parserOutputChanRef = aChan
p.userOutputChanRef = aChan
} }
func (p *h264Parser)parse() { // parse interprets an incoming h264 stream and extracts individual frames
outputBuffer := make([]byte, 0, 10000) // aka access units
func (p *h264Parser) parse() {
outputBuffer := make([]byte, 0, outputBufferSize)
searchingForEnd := false searchingForEnd := false
for p.isParsing { for p.isParsing {
aByte := <-p.inputChan aByte := <-p.inputChan
outputBuffer = append(outputBuffer, aByte) outputBuffer = append(outputBuffer, aByte)
for i:=1; aByte == 0x00 && i != 4; i++ { for i := 1; aByte == 0x00 && i != 4; i++ {
aByte = <-p.inputChan aByte = <-p.inputChan
outputBuffer = append(outputBuffer, aByte) outputBuffer = append(outputBuffer, aByte)
if ( aByte == 0x01 && i == 2 ) || ( aByte == 0x01 && i == 3 ) { if (aByte == 0x01 && i == 2) || (aByte == 0x01 && i == 3) {
if searchingForEnd { if searchingForEnd {
output := append(append(itut.StartCode1(),itut.AUD()...),outputBuffer[:len(outputBuffer)-(i+1)]...) output := append(append(itut.StartCode1(), itut.AUD()...), outputBuffer[:len(outputBuffer)-(i+1)]...)
time.Sleep(time.Duration(p.delay)*time.Millisecond) time.Sleep(time.Duration(p.delay) * time.Millisecond)
p.parserOutputChanRef<-output p.parserOutputChanRef <- output
outputBuffer = outputBuffer[len(outputBuffer)-1-i:] outputBuffer = outputBuffer[len(outputBuffer)-1-i:]
searchingForEnd = false searchingForEnd = false
} }
aByte = <-p.inputChan aByte = <-p.inputChan
outputBuffer = append(outputBuffer, aByte) outputBuffer = append(outputBuffer, aByte)
if nalType := aByte & 0x1F; nalType == 1 || nalType == 5 || nalType == 8{ if nalType := aByte & 0x1F; nalType == 1 || nalType == 5 || nalType == 8 {
searchingForEnd = true searchingForEnd = true
} }
} }

View File

@ -1,16 +1,17 @@
/* /*
NOTE: this file is in progress...
NAME NAME
RtpToTsConverter.go - provides utilities for the conversion of Rtp packets H264Writer.go
to equivalent MpegTs packets.
DESCRIPTION DESCRIPTION
See Readme.md See Readme.md
AUTHOR AUTHOR
Saxon Nelson-Milton <saxon.milton@gmail.com> Saxon Nelson-Milton <saxon@ausocean.org>
LICENSE LICENSE
RtpToTsConverter.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) H264Writer.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them 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 under the terms of the GNU General Public License as published by the
@ -26,6 +27,8 @@ LICENSE
along with revid in gpl.txt. If not, see [GNU licenses](http://www.gnu.org/licenses). along with revid in gpl.txt. If not, see [GNU licenses](http://www.gnu.org/licenses).
*/ */
// TODO: complete this file
package parser package parser
import ( import (

View File

@ -1,64 +1,94 @@
/*
NAME
MJPEGParser.go
DESCRIPTION
See Readme.md
AUTHOR
Saxon Nelson-Milton <saxon@ausocean.org>
LICENSE
MJPEGParser.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 parser package parser
import ( import (
//"bitbucket.org/ausocean/av/itut" //"bitbucket.org/ausocean/av/itut"
_"fmt" _ "fmt"
)
const (
frameStartCode = 0xD8
) )
type mjpegParser struct { type mjpegParser struct {
inputBuffer []byte inputBuffer []byte
isParsing bool isParsing bool
parserOutputChanRef chan []byte parserOutputChanRef chan []byte
userOutputChanRef chan []byte userOutputChanRef chan []byte
inputChan chan byte inputChan chan byte
delay uint delay uint
} }
func NewMJPEGParser(inputChanLen int) (p *mjpegParser){ func NewMJPEGParser(inputChanLen int) (p *mjpegParser) {
p = new(mjpegParser) p = new(mjpegParser)
p.isParsing = true p.isParsing = true
p.inputChan = make(chan byte, inputChanLen ) p.inputChan = make(chan byte, inputChanLen)
return return
} }
func (p *mjpegParser)Stop(){ func (p *mjpegParser) Stop() {
p.isParsing = false p.isParsing = false
} }
func (p *mjpegParser)Start(){ func (p *mjpegParser) Start() {
go p.parse() go p.parse()
} }
func (p *mjpegParser)SetDelay(delay uint){ func (p *mjpegParser) SetDelay(delay uint) {
p.delay = delay p.delay = delay
} }
func (p *mjpegParser) GetInputChan() chan byte {
func (p *mjpegParser)GetInputChan() chan byte { return p.inputChan
return p.inputChan
} }
func (p *mjpegParser)GetOutputChan() chan []byte { func (p *mjpegParser) GetOutputChan() chan []byte {
return p.userOutputChanRef return p.userOutputChanRef
} }
func (p *mjpegParser)SetOutputChan(aChan chan []byte){ func (p *mjpegParser) SetOutputChan(aChan chan []byte) {
p.parserOutputChanRef = aChan p.parserOutputChanRef = aChan
p.userOutputChanRef = aChan p.userOutputChanRef = aChan
} }
func (p *mjpegParser)parse() { func (p *mjpegParser) parse() {
var outputBuffer []byte var outputBuffer []byte
for p.isParsing { for p.isParsing {
aByte := <-p.inputChan aByte := <-p.inputChan
outputBuffer = append(outputBuffer, aByte) outputBuffer = append(outputBuffer, aByte)
if aByte == 0xFF && len(outputBuffer) != 0 { if aByte == 0xFF && len(outputBuffer) != 0 {
aByte := <-p.inputChan aByte := <-p.inputChan
outputBuffer = append(outputBuffer, aByte) outputBuffer = append(outputBuffer, aByte)
if aByte == 0xD8 { if aByte == frameStartCode {
p.parserOutputChanRef<-outputBuffer[:len(outputBuffer)-2] p.parserOutputChanRef <- outputBuffer[:len(outputBuffer)-2]
outputBuffer = outputBuffer[len(outputBuffer)-2:] outputBuffer = outputBuffer[len(outputBuffer)-2:]
} }
} }
} }
} }