mirror of https://bitbucket.org/ausocean/av.git
Just updating remote
This commit is contained in:
parent
ce790ed2b0
commit
bfb31136c8
|
@ -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))
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
101
nal/NalUnit.go
101
nal/NalUnit.go
|
@ -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
|
|
||||||
}
|
|
118
nal/nal_test.go
118
nal/nal_test.go
|
@ -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!")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue