Update codec.Reader interface to return byte slice

This commit is contained in:
Lukas Herman
2020-10-28 07:34:43 -07:00
parent c8547c4597
commit f4a4edcabd
12 changed files with 80 additions and 228 deletions

View File

@@ -201,11 +201,11 @@ type mockVideoCodec struct {
closed chan struct{} closed chan struct{}
} }
func (m *mockVideoCodec) Read(b []byte) (int, error) { func (m *mockVideoCodec) Read() ([]byte, error) {
if _, err := m.r.Read(); err != nil { if _, err := m.r.Read(); err != nil {
return 0, err return nil, err
} }
return len(b), nil return make([]byte, 20), nil
} }
func (m *mockVideoCodec) Close() error { return nil } func (m *mockVideoCodec) Close() error { return nil }
@@ -216,11 +216,11 @@ type mockAudioCodec struct {
closed chan struct{} closed chan struct{}
} }
func (m *mockAudioCodec) Read(b []byte) (int, error) { func (m *mockAudioCodec) Read() ([]byte, error) {
if _, err := m.r.Read(); err != nil { if _, err := m.r.Read(); err != nil {
return 0, err return nil, err
} }
return len(b), nil return make([]byte, 20), nil
} }
func (m *mockAudioCodec) Close() error { return nil } func (m *mockAudioCodec) Close() error { return nil }

View File

@@ -1,8 +1,6 @@
package codec package codec
import ( import (
"io"
"github.com/pion/mediadevices/pkg/io/audio" "github.com/pion/mediadevices/pkg/io/audio"
"github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/io/video"
"github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/prop"
@@ -60,7 +58,8 @@ type VideoEncoderBuilder interface {
// ReadCloser is an io.ReadCloser with methods for rate limiting: SetBitRate and ForceKeyFrame // ReadCloser is an io.ReadCloser with methods for rate limiting: SetBitRate and ForceKeyFrame
type ReadCloser interface { type ReadCloser interface {
io.ReadCloser Read() ([]byte, error)
Close() error
// SetBitRate sets current target bitrate, lower bitrate means smaller data will be transmitted // SetBitRate sets current target bitrate, lower bitrate means smaller data will be transmitted
// but this also means that the quality will also be lower. // but this also means that the quality will also be lower.
SetBitRate(int) error SetBitRate(int) error

View File

@@ -14,14 +14,12 @@ import (
"unsafe" "unsafe"
"github.com/pion/mediadevices/pkg/codec" "github.com/pion/mediadevices/pkg/codec"
mio "github.com/pion/mediadevices/pkg/io"
"github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/io/video"
"github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/prop"
) )
type encoder struct { type encoder struct {
engine C.Encoder engine C.Encoder
buff []byte
r video.Reader r video.Reader
mu sync.Mutex mu sync.Mutex
closed bool closed bool
@@ -57,25 +55,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser,
return &e, nil return &e, nil
} }
func (e *encoder) Read(p []byte) (int, error) { func (e *encoder) Read() ([]byte, error) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
if e.closed { if e.closed {
return 0, io.EOF return nil, io.EOF
}
if e.buff != nil {
n, err := mio.Copy(p, e.buff)
if err == nil {
e.buff = nil
}
return n, err
} }
img, err := e.r.Read() img, err := e.r.Read()
if err != nil { if err != nil {
return 0, err return nil, err
} }
imgReal := img.(*image.YCbCr) imgReal := img.(*image.YCbCr)
var y, cb, cr C.Slice var y, cb, cr C.Slice
@@ -89,7 +79,7 @@ func (e *encoder) Read(p []byte) (int, error) {
var encodedBuffer *C.MMAL_BUFFER_HEADER_T var encodedBuffer *C.MMAL_BUFFER_HEADER_T
status := C.enc_encode(&e.engine, y, cb, cr, &encodedBuffer) status := C.enc_encode(&e.engine, y, cb, cr, &encodedBuffer)
if status.code != 0 { if status.code != 0 {
return 0, statusToErr(&status) return nil, statusToErr(&status)
} }
// GoBytes copies the C array to Go slice. After this, it's safe to release the C array // GoBytes copies the C array to Go slice. After this, it's safe to release the C array
@@ -97,11 +87,7 @@ func (e *encoder) Read(p []byte) (int, error) {
// Release the buffer so that mmal can reuse this memory // Release the buffer so that mmal can reuse this memory
C.mmal_buffer_header_release(encodedBuffer) C.mmal_buffer_header_release(encodedBuffer)
n, err := mio.Copy(p, encoded) return encoded, err
if err != nil {
e.buff = encoded
}
return n, err
} }
func (e *encoder) SetBitRate(b int) error { func (e *encoder) SetBitRate(b int) error {

View File

@@ -16,7 +16,6 @@ import (
"unsafe" "unsafe"
"github.com/pion/mediadevices/pkg/codec" "github.com/pion/mediadevices/pkg/codec"
mio "github.com/pion/mediadevices/pkg/io"
"github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/io/video"
"github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/prop"
) )
@@ -24,7 +23,6 @@ import (
type encoder struct { type encoder struct {
engine *C.Encoder engine *C.Encoder
r video.Reader r video.Reader
buff []byte
mu sync.Mutex mu sync.Mutex
closed bool closed bool
@@ -52,26 +50,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser,
}, nil }, nil
} }
func (e *encoder) Read(p []byte) (n int, err error) { func (e *encoder) Read() ([]byte, error) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
if e.closed { if e.closed {
return 0, io.EOF return nil, io.EOF
}
if e.buff != nil {
n, err = mio.Copy(p, e.buff)
if err == nil {
e.buff = nil
}
return n, err
} }
img, err := e.r.Read() img, err := e.r.Read()
if err != nil { if err != nil {
return 0, err return nil, err
} }
yuvImg := img.(*image.YCbCr) yuvImg := img.(*image.YCbCr)
@@ -85,16 +74,11 @@ func (e *encoder) Read(p []byte) (n int, err error) {
width: C.int(bounds.Max.X - bounds.Min.X), width: C.int(bounds.Max.X - bounds.Min.X),
}, &rv) }, &rv)
if err := errResult(rv); err != nil { if err := errResult(rv); err != nil {
return 0, fmt.Errorf("failed in encoding: %v", err) return nil, fmt.Errorf("failed in encoding: %v", err)
} }
encoded := C.GoBytes(unsafe.Pointer(s.data), s.data_len) encoded := C.GoBytes(unsafe.Pointer(s.data), s.data_len)
n, err = mio.Copy(p, encoded) return encoded, nil
if err != nil {
e.buff = encoded
}
return n, err
} }
func (e *encoder) SetBitRate(b int) error { func (e *encoder) SetBitRate(b int) error {

View File

@@ -72,27 +72,22 @@ func newEncoder(r audio.Reader, p prop.Media, params Params) (codec.ReadCloser,
return &e, nil return &e, nil
} }
func (e *encoder) Read(p []byte) (int, error) { func (e *encoder) Read() ([]byte, error) {
buff, err := e.reader.Read() buff, err := e.reader.Read()
if err != nil { if err != nil {
return 0, err return nil, err
} }
encoded := make([]byte, 1024)
switch b := buff.(type) { switch b := buff.(type) {
case *wave.Int16Interleaved: case *wave.Int16Interleaved:
n, err := e.engine.Encode(b.Data, p) n, err := e.engine.Encode(b.Data, encoded)
if err != nil { return encoded[:n:n], err
return n, err
}
return n, nil
case *wave.Float32Interleaved: case *wave.Float32Interleaved:
n, err := e.engine.EncodeFloat32(b.Data, p) n, err := e.engine.EncodeFloat32(b.Data, encoded)
if err != nil { return encoded[:n:n], err
return n, err
}
return n, nil
default: default:
return 0, errors.New("unknown type of audio buffer") return nil, errors.New("unknown type of audio buffer")
} }
} }

View File

@@ -80,7 +80,6 @@ const (
type encoderVP8 struct { type encoderVP8 struct {
r video.Reader r video.Reader
buf []byte
frame []byte frame []byte
fdDRI C.int fdDRI C.int
@@ -297,25 +296,17 @@ func newVP8Encoder(r video.Reader, p prop.Media, params ParamsVP8) (codec.ReadCl
return e, nil return e, nil
} }
func (e *encoderVP8) Read(p []byte) (int, error) { func (e *encoderVP8) Read() ([]byte, error) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
if e.closed { if e.closed {
return 0, io.EOF return nil, io.EOF
}
if e.buf != nil {
n, err := mio.Copy(p, e.buf)
if err == nil {
e.buf = nil
}
return n, err
} }
img, err := e.r.Read() img, err := e.r.Read()
if err != nil { if err != nil {
return 0, err return nil, err
} }
yuvImg := img.(*image.YCbCr) yuvImg := img.(*image.YCbCr)
@@ -357,7 +348,7 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
} }
} }
if e.picParam.reconstructed_frame == C.VA_INVALID_SURFACE { if e.picParam.reconstructed_frame == C.VA_INVALID_SURFACE {
return 0, errors.New("no available surface") return nil, errors.New("no available surface")
} }
C.setForceKFFlagVP8(&e.picParam, 0) C.setForceKFFlagVP8(&e.picParam, 0)
@@ -425,7 +416,7 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
C.size_t(uintptr(p.src)), C.size_t(uintptr(p.src)),
&id, &id,
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to create buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to create buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
buffs = append(buffs, id) buffs = append(buffs, id)
} }
@@ -435,17 +426,17 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
e.display, e.ctxID, e.display, e.ctxID,
e.surfs[surfaceVP8Input], e.surfs[surfaceVP8Input],
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to begin picture: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to begin picture: %s", C.GoString(C.vaErrorStr(s)))
} }
// Upload image // Upload image
var vaImg C.VAImage var vaImg C.VAImage
var rawBuf unsafe.Pointer var rawBuf unsafe.Pointer
if s := C.vaDeriveImage(e.display, e.surfs[surfaceVP8Input], &vaImg); s != C.VA_STATUS_SUCCESS { if s := C.vaDeriveImage(e.display, e.surfs[surfaceVP8Input], &vaImg); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to derive image: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to derive image: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaMapBuffer(e.display, vaImg.buf, &rawBuf); s != C.VA_STATUS_SUCCESS { if s := C.vaMapBuffer(e.display, vaImg.buf, &rawBuf); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
// TODO: use vaImg.pitches to support padding // TODO: use vaImg.pitches to support padding
C.memcpy( C.memcpy(
@@ -461,10 +452,10 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
unsafe.Pointer(&yuvImg.Cr[0]), C.size_t(len(yuvImg.Cr)), unsafe.Pointer(&yuvImg.Cr[0]), C.size_t(len(yuvImg.Cr)),
) )
if s := C.vaUnmapBuffer(e.display, vaImg.buf); s != C.VA_STATUS_SUCCESS { if s := C.vaUnmapBuffer(e.display, vaImg.buf); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to unmap buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to unmap buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaDestroyImage(e.display, vaImg.image_id); s != C.VA_STATUS_SUCCESS { if s := C.vaDestroyImage(e.display, vaImg.image_id); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to destroy image: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to destroy image: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaRenderPicture( if s := C.vaRenderPicture(
@@ -472,38 +463,38 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
&buffs[1], // 0 is for ouput &buffs[1], // 0 is for ouput
C.int(len(buffs)-1), C.int(len(buffs)-1),
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to render picture: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to render picture: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaEndPicture( if s := C.vaEndPicture(
e.display, e.ctxID, e.display, e.ctxID,
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to end picture: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to end picture: %s", C.GoString(C.vaErrorStr(s)))
} }
// Load encoded data // Load encoded data
for retry := 3; retry >= 0; retry-- { for retry := 3; retry >= 0; retry-- {
if s := C.vaSyncSurface(e.display, e.picParam.reconstructed_frame); s != C.VA_STATUS_SUCCESS { if s := C.vaSyncSurface(e.display, e.picParam.reconstructed_frame); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to sync surface: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to sync surface: %s", C.GoString(C.vaErrorStr(s)))
} }
var surfStat C.VASurfaceStatus var surfStat C.VASurfaceStatus
if s := C.vaQuerySurfaceStatus( if s := C.vaQuerySurfaceStatus(
e.display, e.picParam.reconstructed_frame, &surfStat, e.display, e.picParam.reconstructed_frame, &surfStat,
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to query surface status: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to query surface status: %s", C.GoString(C.vaErrorStr(s)))
} }
if surfStat == C.VASurfaceReady { if surfStat == C.VASurfaceReady {
break break
} }
if retry == 0 { if retry == 0 {
return 0, fmt.Errorf("failed to sync surface: %d", surfStat) return nil, fmt.Errorf("failed to sync surface: %d", surfStat)
} }
} }
var seg *C.VACodedBufferSegment var seg *C.VACodedBufferSegment
if s := C.vaMapBufferSeg(e.display, buffs[0], &seg); s != C.VA_STATUS_SUCCESS { if s := C.vaMapBufferSeg(e.display, buffs[0], &seg); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
if seg.status&C.VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK != 0 { if seg.status&C.VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK != 0 {
return 0, errors.New("buffer size too small") return nil, errors.New("buffer size too small")
} }
if cap(e.frame) < int(seg.size) { if cap(e.frame) < int(seg.size) {
@@ -516,13 +507,13 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
) )
if s := C.vaUnmapBuffer(e.display, buffs[0]); s != C.VA_STATUS_SUCCESS { if s := C.vaUnmapBuffer(e.display, buffs[0]); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to unmap buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to unmap buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
// Destroy buffers // Destroy buffers
for _, b := range buffs { for _, b := range buffs {
if s := C.vaDestroyBuffer(e.display, b); s != C.VA_STATUS_SUCCESS { if s := C.vaDestroyBuffer(e.display, b); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to destroy buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to destroy buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
} }
@@ -545,11 +536,9 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
e.picParam.ref_last_frame = e.picParam.reconstructed_frame e.picParam.ref_last_frame = e.picParam.reconstructed_frame
C.setRefreshLastFlagVP8(&e.picParam, 1) C.setRefreshLastFlagVP8(&e.picParam, 1)
n, err := mio.Copy(p, e.frame) encoded := make([]byte, len(e.frame))
if err != nil { copy(encoded, e.frame)
e.buf = e.frame return encoded, err
}
return n, err
} }
func (e *encoderVP8) SetBitRate(b int) error { func (e *encoderVP8) SetBitRate(b int) error {

View File

@@ -67,7 +67,6 @@ const (
type encoderVP9 struct { type encoderVP9 struct {
r video.Reader r video.Reader
buf []byte
frame []byte frame []byte
fdDRI C.int fdDRI C.int
@@ -286,25 +285,17 @@ func newVP9Encoder(r video.Reader, p prop.Media, params ParamsVP9) (codec.ReadCl
return e, nil return e, nil
} }
func (e *encoderVP9) Read(p []byte) (int, error) { func (e *encoderVP9) Read() ([]byte, error) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
if e.closed { if e.closed {
return 0, io.EOF return nil, io.EOF
}
if e.buf != nil {
n, err := mio.Copy(p, e.buf)
if err == nil {
e.buf = nil
}
return n, err
} }
img, err := e.r.Read() img, err := e.r.Read()
if err != nil { if err != nil {
return 0, err return nil, err
} }
yuvImg := img.(*image.YCbCr) yuvImg := img.(*image.YCbCr)
@@ -398,17 +389,17 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
e.display, e.ctxID, e.display, e.ctxID,
e.surfs[surfaceVP9Input], e.surfs[surfaceVP9Input],
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to begin picture: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to begin picture: %s", C.GoString(C.vaErrorStr(s)))
} }
// Upload image // Upload image
var vaImg C.VAImage var vaImg C.VAImage
var rawBuf unsafe.Pointer var rawBuf unsafe.Pointer
if s := C.vaDeriveImage(e.display, e.surfs[surfaceVP9Input], &vaImg); s != C.VA_STATUS_SUCCESS { if s := C.vaDeriveImage(e.display, e.surfs[surfaceVP9Input], &vaImg); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to derive image: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to derive image: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaMapBuffer(e.display, vaImg.buf, &rawBuf); s != C.VA_STATUS_SUCCESS { if s := C.vaMapBuffer(e.display, vaImg.buf, &rawBuf); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
// TODO: use vaImg.pitches to support padding // TODO: use vaImg.pitches to support padding
C.copyI420toNV12( C.copyI420toNV12(
@@ -419,10 +410,10 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
C.uint(len(yuvImg.Y)), C.uint(len(yuvImg.Y)),
) )
if s := C.vaUnmapBuffer(e.display, vaImg.buf); s != C.VA_STATUS_SUCCESS { if s := C.vaUnmapBuffer(e.display, vaImg.buf); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to unmap buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to unmap buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaDestroyImage(e.display, vaImg.image_id); s != C.VA_STATUS_SUCCESS { if s := C.vaDestroyImage(e.display, vaImg.image_id); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to destroy image: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to destroy image: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaRenderPicture( if s := C.vaRenderPicture(
@@ -430,27 +421,27 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
&buffs[1], // 0 is for ouput &buffs[1], // 0 is for ouput
C.int(len(buffs)-1), C.int(len(buffs)-1),
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to render picture: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to render picture: %s", C.GoString(C.vaErrorStr(s)))
} }
if s := C.vaEndPicture( if s := C.vaEndPicture(
e.display, e.ctxID, e.display, e.ctxID,
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to end picture: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to end picture: %s", C.GoString(C.vaErrorStr(s)))
} }
// Load encoded data // Load encoded data
if s := C.vaSyncSurface(e.display, e.picParam.reconstructed_frame); s != C.VA_STATUS_SUCCESS { if s := C.vaSyncSurface(e.display, e.picParam.reconstructed_frame); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to sync surface: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to sync surface: %s", C.GoString(C.vaErrorStr(s)))
} }
var surfStat C.VASurfaceStatus var surfStat C.VASurfaceStatus
if s := C.vaQuerySurfaceStatus( if s := C.vaQuerySurfaceStatus(
e.display, e.picParam.reconstructed_frame, &surfStat, e.display, e.picParam.reconstructed_frame, &surfStat,
); s != C.VA_STATUS_SUCCESS { ); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to query surface status: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to query surface status: %s", C.GoString(C.vaErrorStr(s)))
} }
var seg *C.VACodedBufferSegment var seg *C.VACodedBufferSegment
if s := C.vaMapBufferSeg(e.display, buffs[0], &seg); s != C.VA_STATUS_SUCCESS { if s := C.vaMapBufferSeg(e.display, buffs[0], &seg); s != C.VA_STATUS_SUCCESS {
return 0, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s))) return nil, fmt.Errorf("failed to map buffer: %s", C.GoString(C.vaErrorStr(s)))
} }
if cap(e.frame) < int(seg.size) { if cap(e.frame) < int(seg.size) {
e.frame = make([]byte, int(seg.size)) e.frame = make([]byte, int(seg.size))
@@ -480,11 +471,9 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
e.slotCurr = 0 e.slotCurr = 0
} }
n, err := mio.Copy(p, e.frame) encoded := make([]byte, len(e.frame))
if err != nil { copy(encoded, e.frame)
e.buf = e.frame return encoded, err
}
return n, err
} }
func (e *encoderVP9) SetBitRate(b int) error { func (e *encoderVP9) SetBitRate(b int) error {

View File

@@ -56,7 +56,6 @@ import (
"unsafe" "unsafe"
"github.com/pion/mediadevices/pkg/codec" "github.com/pion/mediadevices/pkg/codec"
mio "github.com/pion/mediadevices/pkg/io"
"github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/io/video"
"github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/prop"
) )
@@ -67,7 +66,6 @@ type encoder struct {
cfg *C.vpx_codec_enc_cfg_t cfg *C.vpx_codec_enc_cfg_t
r video.Reader r video.Reader
frameIndex int frameIndex int
buff []byte
tStart int tStart int
tLastFrame int tLastFrame int
frame []byte frame []byte
@@ -206,25 +204,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params, codecIface *C.vpx_c
}, nil }, nil
} }
func (e *encoder) Read(p []byte) (int, error) { func (e *encoder) Read() ([]byte, error) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
if e.closed { if e.closed {
return 0, io.EOF return nil, io.EOF
}
if e.buff != nil {
n, err := mio.Copy(p, e.buff)
if err == nil {
e.buff = nil
}
return n, err
} }
img, err := e.r.Read() img, err := e.r.Read()
if err != nil { if err != nil {
return 0, err return nil, err
} }
yuvImg := img.(*image.YCbCr) yuvImg := img.(*image.YCbCr)
bounds := yuvImg.Bounds() bounds := yuvImg.Bounds()
@@ -240,7 +230,7 @@ func (e *encoder) Read(p []byte) (int, error) {
if e.cfg.g_w != C.uint(width) || e.cfg.g_h != C.uint(height) { if e.cfg.g_w != C.uint(width) || e.cfg.g_h != C.uint(height) {
e.cfg.g_w, e.cfg.g_h = C.uint(width), C.uint(height) e.cfg.g_w, e.cfg.g_h = C.uint(width), C.uint(height)
if ec := C.vpx_codec_enc_config_set(e.codec, e.cfg); ec != C.VPX_CODEC_OK { if ec := C.vpx_codec_enc_config_set(e.codec, e.cfg); ec != C.VPX_CODEC_OK {
return 0, fmt.Errorf("vpx_codec_enc_config_set failed (%d)", ec) return nil, fmt.Errorf("vpx_codec_enc_config_set failed (%d)", ec)
} }
e.raw.w, e.raw.h = C.uint(width), C.uint(height) e.raw.w, e.raw.h = C.uint(width), C.uint(height)
e.raw.r_w, e.raw.r_h = C.uint(width), C.uint(height) e.raw.r_w, e.raw.r_h = C.uint(width), C.uint(height)
@@ -253,7 +243,7 @@ func (e *encoder) Read(p []byte) (int, error) {
C.long(t-e.tStart), C.ulong(t-e.tLastFrame), C.long(flags), C.ulong(e.deadline), C.long(t-e.tStart), C.ulong(t-e.tLastFrame), C.long(flags), C.ulong(e.deadline),
(*C.uchar)(&yuvImg.Y[0]), (*C.uchar)(&yuvImg.Cb[0]), (*C.uchar)(&yuvImg.Cr[0]), (*C.uchar)(&yuvImg.Y[0]), (*C.uchar)(&yuvImg.Cb[0]), (*C.uchar)(&yuvImg.Cr[0]),
); ec != C.VPX_CODEC_OK { ); ec != C.VPX_CODEC_OK {
return 0, fmt.Errorf("vpx_codec_encode failed (%d)", ec) return nil, fmt.Errorf("vpx_codec_encode failed (%d)", ec)
} }
e.frameIndex++ e.frameIndex++
@@ -271,11 +261,10 @@ func (e *encoder) Read(p []byte) (int, error) {
e.frame = append(e.frame, encoded...) e.frame = append(e.frame, encoded...)
} }
} }
n, err := mio.Copy(p, e.frame)
if err != nil { encoded := make([]byte, len(e.frame))
e.buff = e.frame copy(encoded, e.frame)
} return encoded, err
return n, err
} }
func (e *encoder) SetBitRate(b int) error { func (e *encoder) SetBitRate(b int) error {

View File

@@ -14,14 +14,12 @@ import (
"unsafe" "unsafe"
"github.com/pion/mediadevices/pkg/codec" "github.com/pion/mediadevices/pkg/codec"
mio "github.com/pion/mediadevices/pkg/io"
"github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/io/video"
"github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/prop"
) )
type encoder struct { type encoder struct {
engine *C.Encoder engine *C.Encoder
buff []byte
r video.Reader r video.Reader
mu sync.Mutex mu sync.Mutex
closed bool closed bool
@@ -96,25 +94,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser,
return &e, nil return &e, nil
} }
func (e *encoder) Read(p []byte) (int, error) { func (e *encoder) Read() ([]byte, error) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
if e.closed { if e.closed {
return 0, io.EOF return nil, io.EOF
}
if e.buff != nil {
n, err := mio.Copy(p, e.buff)
if err == nil {
e.buff = nil
}
return n, err
} }
img, err := e.r.Read() img, err := e.r.Read()
if err != nil { if err != nil {
return 0, err return nil, err
} }
yuvImg := img.(*image.YCbCr) yuvImg := img.(*image.YCbCr)
@@ -127,15 +117,11 @@ func (e *encoder) Read(p []byte) (int, error) {
&rc, &rc,
) )
if err := errFromC(rc); err != nil { if err := errFromC(rc); err != nil {
return 0, err return nil, err
} }
encoded := C.GoBytes(unsafe.Pointer(s.data), s.data_len) encoded := C.GoBytes(unsafe.Pointer(s.data), s.data_len)
n, err := mio.Copy(p, encoded) return encoded, err
if err != nil {
e.buff = encoded
}
return n, err
} }
func (e *encoder) SetBitRate(b int) error { func (e *encoder) SetBitRate(b int) error {

View File

@@ -1,11 +0,0 @@
package io
// Copy copies data from src to dst. If dst is not big enough, return an
// InsufficientBufferError.
func Copy(dst, src []byte) (n int, err error) {
if len(dst) < len(src) {
return 0, &InsufficientBufferError{len(src)}
}
return copy(dst, src), nil
}

View File

@@ -1,45 +0,0 @@
package io
import (
"log"
"testing"
)
func TestCopy(t *testing.T) {
var dst []byte
src := make([]byte, 4)
n, err := Copy(dst, src)
if err == nil {
t.Fatal("expected err to be non-nill")
}
if n != 0 {
t.Fatalf("expected n to be 0, but got %d", n)
}
e, ok := err.(*InsufficientBufferError)
if !ok {
t.Fatalf("expected error to be InsufficientBufferError")
}
if e.RequiredSize != len(src) {
t.Fatalf("expected required size to be %d, but got %d", len(src), e.RequiredSize)
}
dst = make([]byte, 2*e.RequiredSize)
n, err = Copy(dst, src)
if err != nil {
t.Fatalf("expected to not get an error after expanding the buffer")
}
if n != len(src) {
t.Fatalf("expected n to be %d, but got %d", len(src), n)
}
for i := 0; i < len(src); i++ {
if src[i] != dst[i] {
log.Fatalf("expected value at %d to be %d, but got %d", i, src[i], dst[i])
}
}
}

View File

@@ -7,7 +7,6 @@ import (
"github.com/pion/mediadevices/pkg/codec" "github.com/pion/mediadevices/pkg/codec"
"github.com/pion/mediadevices/pkg/driver" "github.com/pion/mediadevices/pkg/driver"
mio "github.com/pion/mediadevices/pkg/io"
"github.com/pion/webrtc/v2" "github.com/pion/webrtc/v2"
"github.com/pion/webrtc/v2/pkg/media" "github.com/pion/webrtc/v2/pkg/media"
) )
@@ -160,22 +159,14 @@ func (t *track) onError(err error) {
// start starts the data flow from the driver all the way to the localTrack // start starts the data flow from the driver all the way to the localTrack
func (t *track) start() { func (t *track) start() {
var n int
var err error
buff := make([]byte, 1024)
for { for {
n, err = t.encoder.Read(buff) buff, err := t.encoder.Read()
if err != nil { if err != nil {
if e, ok := err.(*mio.InsufficientBufferError); ok {
buff = make([]byte, 2*e.RequiredSize)
continue
}
t.onError(err) t.onError(err)
return return
} }
if err := t.sample(buff[:n]); err != nil { if err := t.sample(buff); err != nil {
t.onError(err) t.onError(err)
return return
} }