diff --git a/codec/mjpeg/lex.go b/codec/mjpeg/lex.go index aea4ce9f..d7bb504d 100644 --- a/codec/mjpeg/lex.go +++ b/codec/mjpeg/lex.go @@ -3,10 +3,12 @@ NAME lex.go DESCRIPTION - lex.go provides a lexer to extract separate JPEG images from a MJPEG stream. + lex.go provides a lexer to extract separate JPEG images from a JPEG stream. + This could either be a series of descrete JPEG images, or an MJPEG stream. AUTHOR Dan Kortschak + Saxon Nelson-Milton LICENSE lex.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) @@ -25,8 +27,6 @@ LICENSE along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. */ -// lex.go provides a lexer to extract separate JPEG images from a MJPEG stream. - package mjpeg import ( @@ -35,15 +35,19 @@ import ( "fmt" "io" "time" + + "bitbucket.org/ausocean/utils/logger" ) +var Log logger.LoggerIF + var noDelay = make(chan time.Time) func init() { close(noDelay) } -// Lex parses MJPEG frames read from src into separate writes to dst with +// Lex parses JPEG frames read from src into separate writes to dst with // successive writes being performed not earlier than the specified delay. func Lex(dst io.Writer, src io.Reader, delay time.Duration) error { var tick <-chan time.Time @@ -65,9 +69,13 @@ func Lex(dst io.Writer, src io.Reader, delay time.Duration) error { if err != nil { return err } + if !bytes.Equal(buf, []byte{0xff, 0xd8}) { - return fmt.Errorf("parser: not MJPEG frame start: %#v", buf) + return fmt.Errorf("parser: not JPEG frame start: %#v", buf) } + + nImg := 1 + var last byte for { b, err := r.ReadByte() @@ -77,16 +85,28 @@ func Lex(dst io.Writer, src io.Reader, delay time.Duration) error { } return err } + buf = append(buf, b) + + if last == 0xff && b == 0xd8 { + nImg++ + } + if last == 0xff && b == 0xd9 { + nImg-- + } + + if nImg == 0 { + <-tick + Log.Debug("writing buf","len(buf)",len(buf)) + _, err = dst.Write(buf) + if err != nil { + return err + } break } + last = b } - <-tick - _, err = dst.Write(buf) - if err != nil { - return err - } } } diff --git a/codec/mjpeg/lex_test.go b/codec/mjpeg/lex_test.go index fd8b6f86..9e37c57a 100644 --- a/codec/mjpeg/lex_test.go +++ b/codec/mjpeg/lex_test.go @@ -30,10 +30,17 @@ LICENSE package mjpeg import ( + "bytes" + "fmt" + "io" + "reflect" + "testing" "time" + + "bitbucket.org/ausocean/utils/logger" ) -var mjpegTests = []struct { +var jpegTests = []struct { name string input []byte delay time.Duration @@ -42,18 +49,21 @@ var mjpegTests = []struct { }{ { name: "empty", + err: io.ErrUnexpectedEOF, }, { name: "null", input: []byte{0xff, 0xd8, 0xff, 0xd9}, delay: 0, want: [][]byte{{0xff, 0xd8, 0xff, 0xd9}}, + err: io.ErrUnexpectedEOF, }, { name: "null delayed", input: []byte{0xff, 0xd8, 0xff, 0xd9}, delay: time.Millisecond, want: [][]byte{{0xff, 0xd8, 0xff, 0xd9}}, + err: io.ErrUnexpectedEOF, }, { name: "full", @@ -72,6 +82,7 @@ var mjpegTests = []struct { {0xff, 0xd8, 'l', 'e', 'n', 'g', 't', 'h', 0xff, 0xd9}, {0xff, 0xd8, 's', 'p', 'r', 'e', 'a', 'd', 0xff, 0xd9}, }, + err: io.ErrUnexpectedEOF, }, { name: "full delayed", @@ -90,15 +101,15 @@ var mjpegTests = []struct { {0xff, 0xd8, 'l', 'e', 'n', 'g', 't', 'h', 0xff, 0xd9}, {0xff, 0xd8, 's', 'p', 'r', 'e', 'a', 'd', 0xff, 0xd9}, }, + err: io.ErrUnexpectedEOF, }, } -// FIXME this needs to be adapted -/* -func Lex(t *testing.T) { - for _, test := range mjpegTests { +func TestLex(t *testing.T) { + Log = (*logger.TestLogger)(t) + for _, test := range jpegTests { var buf chunkEncoder - err := MJPEG(&buf, bytes.NewReader(test.input), test.delay) + err := Lex(&buf, bytes.NewReader(test.input), test.delay) if fmt.Sprint(err) != fmt.Sprint(test.err) { t.Errorf("unexpected error for %q: got:%v want:%v", test.name, err, test.err) } @@ -111,4 +122,12 @@ func Lex(t *testing.T) { } } } -*/ + +type chunkEncoder [][]byte + +func (e *chunkEncoder) Write(b []byte) (int, error) { + *e = append(*e, b) + return len(b), nil +} + +func (*chunkEncoder) Stream() <-chan []byte { panic("INVALID USE") } diff --git a/go.mod b/go.mod index 7b6d86c9..86fbc1d3 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( bitbucket.org/ausocean/iot v1.3.0 - bitbucket.org/ausocean/utils v1.2.15 + bitbucket.org/ausocean/utils v1.2.17 github.com/Comcast/gots v0.0.0-20190305015453-8d56e473f0f7 github.com/go-audio/audio v0.0.0-20181013203223-7b2a6ca21480 github.com/go-audio/wav v0.0.0-20181013172942-de841e69b884 diff --git a/go.sum b/go.sum index 542785d5..8c9944dc 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ bitbucket.org/ausocean/utils v1.2.14 h1:v5eBYavkEqKOBCppR6P451eT9UT/CQReMsOZZBUP bitbucket.org/ausocean/utils v1.2.14/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8= bitbucket.org/ausocean/utils v1.2.15 h1:Pz99ZfobdhACTtU6oj9BTyBcNSQulLvPT7wq4P343Es= bitbucket.org/ausocean/utils v1.2.15/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8= +bitbucket.org/ausocean/utils v1.2.17 h1:6ZqXvxRXHHL18s2kn22E2/AORNn2WsgQXcEnctWwvrk= +bitbucket.org/ausocean/utils v1.2.17/go.mod h1:uoIRyy4jwH0/9b/t9tfPuV9Vl14AONeILw9KimUISYg= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Comcast/gots v0.0.0-20190305015453-8d56e473f0f7 h1:LdOc9B9Bj6LEsKiXShkLA3/kpxXb6LJpH+ekU2krbzw=