Extract ModuloReader from service.go
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
2445ebc02f
commit
dd526b6916
|
@ -0,0 +1,43 @@
|
||||||
|
package media
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModuloReader reads from a reader in block sizes that are exactly modulo
|
||||||
|
// modSize, with any remainder buffered until the next read.
|
||||||
|
type ModuloReader struct {
|
||||||
|
io.ReadCloser
|
||||||
|
|
||||||
|
buf bytes.Buffer
|
||||||
|
modSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewModuloReader(r io.ReadCloser, modSize int) *ModuloReader {
|
||||||
|
return &ModuloReader{ReadCloser: r, modSize: modSize}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ModuloReader) Read(p []byte) (int, error) {
|
||||||
|
// err is always io.EOF or nil
|
||||||
|
nr1, _ := r.buf.Read(p)
|
||||||
|
nr2, err := r.ReadCloser.Read(p[nr1:])
|
||||||
|
|
||||||
|
nr := nr1 + nr2
|
||||||
|
rem := nr % r.modSize
|
||||||
|
|
||||||
|
// if there was an error, return immediately.
|
||||||
|
if err == io.EOF {
|
||||||
|
return nr, err
|
||||||
|
} else if err != nil {
|
||||||
|
return nr - rem, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write any remainder to the buffer
|
||||||
|
if rem != 0 {
|
||||||
|
// err is always nil
|
||||||
|
_, _ = r.buf.Write(p[nr-rem : nr])
|
||||||
|
}
|
||||||
|
|
||||||
|
return nr - rem, err
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package media_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.netflux.io/rob/clipper/media"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testReader struct {
|
||||||
|
count int
|
||||||
|
data [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *testReader) Read(p []byte) (int, error) {
|
||||||
|
if r.count == len(r.data) {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
n := copy(p, r.data[r.count])
|
||||||
|
r.count++
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModuloBufReader(t *testing.T) {
|
||||||
|
reader := testReader{
|
||||||
|
data: [][]byte{
|
||||||
|
{'a', 'b', 'c', 'd'},
|
||||||
|
{'e', 'f', 'g', 'h', 'i'},
|
||||||
|
{},
|
||||||
|
{'j', 'k', 'l', 'm'},
|
||||||
|
{'n', 'o', 'p'},
|
||||||
|
{'q', 'r', 's', 't', 'u'},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
modReader := media.NewModuloReader(io.NopCloser(&reader), 4)
|
||||||
|
|
||||||
|
out := make([]byte, 5)
|
||||||
|
|
||||||
|
n, err := modReader.Read(out)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 4, n)
|
||||||
|
assert.Equal(t, []byte{'a', 'b', 'c', 'd'}, out[:n])
|
||||||
|
|
||||||
|
n, err = modReader.Read(out)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 4, n)
|
||||||
|
assert.Equal(t, []byte{'e', 'f', 'g', 'h'}, out[:n])
|
||||||
|
|
||||||
|
n, err = modReader.Read(out)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Zero(t, n)
|
||||||
|
assert.Empty(t, out[:n])
|
||||||
|
|
||||||
|
n, err = modReader.Read(out)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 4, n)
|
||||||
|
assert.Equal(t, []byte{'i', 'j', 'k', 'l'}, out[:n])
|
||||||
|
|
||||||
|
n, err = modReader.Read(out)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 4, n)
|
||||||
|
assert.Equal(t, []byte{'m', 'n', 'o', 'p'}, out[:n])
|
||||||
|
|
||||||
|
n, err = modReader.Read(out)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 4, n)
|
||||||
|
assert.Equal(t, []byte{'q', 'r', 's', 't'}, out[:n])
|
||||||
|
|
||||||
|
n, err = modReader.Read(out)
|
||||||
|
assert.Equal(t, io.EOF, err)
|
||||||
|
assert.Equal(t, 1, n)
|
||||||
|
assert.Equal(t, []byte{'u'}, out[:n])
|
||||||
|
|
||||||
|
n, err = modReader.Read(out)
|
||||||
|
assert.Zero(t, n)
|
||||||
|
assert.Equal(t, io.EOF, err)
|
||||||
|
}
|
|
@ -291,7 +291,7 @@ func (s *MediaSetService) getPeaksFromFileStore(ctx context.Context, mediaSet st
|
||||||
|
|
||||||
state := getPeaksFromFileStoreState{
|
state := getPeaksFromFileStoreState{
|
||||||
getPeaksProgressReader: getPeaksProgressReader,
|
getPeaksProgressReader: getPeaksProgressReader,
|
||||||
reader: NewModuloBufReader(object, int(mediaSet.AudioChannels)*SizeOfInt16),
|
reader: NewModuloReader(object, int(mediaSet.AudioChannels)*SizeOfInt16),
|
||||||
fileStore: s.fileStore,
|
fileStore: s.fileStore,
|
||||||
config: s.config,
|
config: s.config,
|
||||||
logger: s.logger,
|
logger: s.logger,
|
||||||
|
@ -376,7 +376,7 @@ func (s *MediaSetService) GetPeaksForSegment(ctx context.Context, id uuid.UUID,
|
||||||
|
|
||||||
const readBufSizeBytes = 8_192
|
const readBufSizeBytes = 8_192
|
||||||
channels := int(mediaSet.AudioChannels)
|
channels := int(mediaSet.AudioChannels)
|
||||||
modReader := NewModuloBufReader(object, channels*SizeOfInt16)
|
modReader := NewModuloReader(object, channels*SizeOfInt16)
|
||||||
readBuf := make([]byte, readBufSizeBytes)
|
readBuf := make([]byte, readBufSizeBytes)
|
||||||
peaks := make([]int16, channels*numBins)
|
peaks := make([]int16, channels*numBins)
|
||||||
totalFrames := endFrame - startFrame
|
totalFrames := endFrame - startFrame
|
||||||
|
@ -449,43 +449,6 @@ func sqlInt32(i int32) sql.NullInt32 {
|
||||||
return sql.NullInt32{Int32: i, Valid: true}
|
return sql.NullInt32{Int32: i, Valid: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModuloBufReader reads from a reader in block sizes that are exactly modulo
|
|
||||||
// modSize, with any remainder buffered until the next read.
|
|
||||||
type ModuloBufReader struct {
|
|
||||||
io.ReadCloser
|
|
||||||
|
|
||||||
buf bytes.Buffer
|
|
||||||
modSize int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewModuloBufReader(r io.ReadCloser, modSize int) *ModuloBufReader {
|
|
||||||
return &ModuloBufReader{ReadCloser: r, modSize: modSize}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ModuloBufReader) Read(p []byte) (int, error) {
|
|
||||||
// err is always io.EOF or nil
|
|
||||||
nr1, _ := r.buf.Read(p)
|
|
||||||
nr2, err := r.ReadCloser.Read(p[nr1:])
|
|
||||||
|
|
||||||
nr := nr1 + nr2
|
|
||||||
rem := nr % r.modSize
|
|
||||||
|
|
||||||
// if there was an error, return immediately.
|
|
||||||
if err == io.EOF {
|
|
||||||
return nr, err
|
|
||||||
} else if err != nil {
|
|
||||||
return nr - rem, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// write any remainder to the buffer
|
|
||||||
if rem != 0 {
|
|
||||||
// err is always nil
|
|
||||||
_, _ = r.buf.Write(p[nr-rem : nr])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nr - rem, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type VideoThumbnail struct {
|
type VideoThumbnail struct {
|
||||||
Data []byte
|
Data []byte
|
||||||
Width, Height int
|
Width, Height int
|
||||||
|
|
|
@ -160,74 +160,3 @@ func BenchmarkGetPeaksForSegment(b *testing.B) {
|
||||||
require.NoError(b, err)
|
require.NoError(b, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type testReader struct {
|
|
||||||
count int
|
|
||||||
data [][]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *testReader) Read(p []byte) (int, error) {
|
|
||||||
if r.count == len(r.data) {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
n := copy(p, r.data[r.count])
|
|
||||||
r.count++
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestModuloBufReader(t *testing.T) {
|
|
||||||
reader := testReader{
|
|
||||||
data: [][]byte{
|
|
||||||
{'a', 'b', 'c', 'd'},
|
|
||||||
{'e', 'f', 'g', 'h', 'i'},
|
|
||||||
{},
|
|
||||||
{'j', 'k', 'l', 'm'},
|
|
||||||
{'n', 'o', 'p'},
|
|
||||||
{'q', 'r', 's', 't', 'u'},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
modReader := media.NewModuloBufReader(io.NopCloser(&reader), 4)
|
|
||||||
|
|
||||||
out := make([]byte, 5)
|
|
||||||
|
|
||||||
n, err := modReader.Read(out)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 4, n)
|
|
||||||
assert.Equal(t, []byte{'a', 'b', 'c', 'd'}, out[:n])
|
|
||||||
|
|
||||||
n, err = modReader.Read(out)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 4, n)
|
|
||||||
assert.Equal(t, []byte{'e', 'f', 'g', 'h'}, out[:n])
|
|
||||||
|
|
||||||
n, err = modReader.Read(out)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Zero(t, n)
|
|
||||||
assert.Empty(t, out[:n])
|
|
||||||
|
|
||||||
n, err = modReader.Read(out)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 4, n)
|
|
||||||
assert.Equal(t, []byte{'i', 'j', 'k', 'l'}, out[:n])
|
|
||||||
|
|
||||||
n, err = modReader.Read(out)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 4, n)
|
|
||||||
assert.Equal(t, []byte{'m', 'n', 'o', 'p'}, out[:n])
|
|
||||||
|
|
||||||
n, err = modReader.Read(out)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 4, n)
|
|
||||||
assert.Equal(t, []byte{'q', 'r', 's', 't'}, out[:n])
|
|
||||||
|
|
||||||
n, err = modReader.Read(out)
|
|
||||||
assert.Equal(t, io.EOF, err)
|
|
||||||
assert.Equal(t, 1, n)
|
|
||||||
assert.Equal(t, []byte{'u'}, out[:n])
|
|
||||||
|
|
||||||
n, err = modReader.Read(out)
|
|
||||||
assert.Zero(t, n)
|
|
||||||
assert.Equal(t, io.EOF, err)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue