mirror of
https://github.com/pion/mediadevices.git
synced 2025-10-05 08:36:55 +08:00
Update codec.Reader interface to return byte slice
This commit is contained in:
@@ -201,11 +201,11 @@ type mockVideoCodec 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 {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
return len(b), nil
|
||||
return make([]byte, 20), nil
|
||||
}
|
||||
|
||||
func (m *mockVideoCodec) Close() error { return nil }
|
||||
@@ -216,11 +216,11 @@ type mockAudioCodec 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 {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
return len(b), nil
|
||||
return make([]byte, 20), nil
|
||||
}
|
||||
func (m *mockAudioCodec) Close() error { return nil }
|
||||
|
||||
|
@@ -1,8 +1,6 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/pion/mediadevices/pkg/io/audio"
|
||||
"github.com/pion/mediadevices/pkg/io/video"
|
||||
"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
|
||||
type ReadCloser interface {
|
||||
io.ReadCloser
|
||||
Read() ([]byte, error)
|
||||
Close() error
|
||||
// SetBitRate sets current target bitrate, lower bitrate means smaller data will be transmitted
|
||||
// but this also means that the quality will also be lower.
|
||||
SetBitRate(int) error
|
||||
|
@@ -14,14 +14,12 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"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/prop"
|
||||
)
|
||||
|
||||
type encoder struct {
|
||||
engine C.Encoder
|
||||
buff []byte
|
||||
r video.Reader
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
@@ -57,25 +55,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser,
|
||||
return &e, nil
|
||||
}
|
||||
|
||||
func (e *encoder) Read(p []byte) (int, error) {
|
||||
func (e *encoder) Read() ([]byte, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if e.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if e.buff != nil {
|
||||
n, err := mio.Copy(p, e.buff)
|
||||
if err == nil {
|
||||
e.buff = nil
|
||||
}
|
||||
return n, err
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
img, err := e.r.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
imgReal := img.(*image.YCbCr)
|
||||
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
|
||||
status := C.enc_encode(&e.engine, y, cb, cr, &encodedBuffer)
|
||||
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
|
||||
@@ -97,11 +87,7 @@ func (e *encoder) Read(p []byte) (int, error) {
|
||||
// Release the buffer so that mmal can reuse this memory
|
||||
C.mmal_buffer_header_release(encodedBuffer)
|
||||
|
||||
n, err := mio.Copy(p, encoded)
|
||||
if err != nil {
|
||||
e.buff = encoded
|
||||
}
|
||||
return n, err
|
||||
return encoded, err
|
||||
}
|
||||
|
||||
func (e *encoder) SetBitRate(b int) error {
|
||||
|
@@ -16,7 +16,6 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"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/prop"
|
||||
)
|
||||
@@ -24,7 +23,6 @@ import (
|
||||
type encoder struct {
|
||||
engine *C.Encoder
|
||||
r video.Reader
|
||||
buff []byte
|
||||
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
@@ -52,26 +50,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *encoder) Read(p []byte) (n int, err error) {
|
||||
func (e *encoder) Read() ([]byte, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if e.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if e.buff != nil {
|
||||
n, err = mio.Copy(p, e.buff)
|
||||
if err == nil {
|
||||
e.buff = nil
|
||||
}
|
||||
|
||||
return n, err
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
img, err := e.r.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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),
|
||||
}, &rv)
|
||||
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)
|
||||
n, err = mio.Copy(p, encoded)
|
||||
if err != nil {
|
||||
e.buff = encoded
|
||||
}
|
||||
|
||||
return n, err
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
func (e *encoder) SetBitRate(b int) error {
|
||||
|
@@ -72,27 +72,22 @@ func newEncoder(r audio.Reader, p prop.Media, params Params) (codec.ReadCloser,
|
||||
return &e, nil
|
||||
}
|
||||
|
||||
func (e *encoder) Read(p []byte) (int, error) {
|
||||
func (e *encoder) Read() ([]byte, error) {
|
||||
buff, err := e.reader.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encoded := make([]byte, 1024)
|
||||
switch b := buff.(type) {
|
||||
case *wave.Int16Interleaved:
|
||||
n, err := e.engine.Encode(b.Data, p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
n, err := e.engine.Encode(b.Data, encoded)
|
||||
return encoded[:n:n], err
|
||||
case *wave.Float32Interleaved:
|
||||
n, err := e.engine.EncodeFloat32(b.Data, p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
n, err := e.engine.EncodeFloat32(b.Data, encoded)
|
||||
return encoded[:n:n], err
|
||||
default:
|
||||
return 0, errors.New("unknown type of audio buffer")
|
||||
return nil, errors.New("unknown type of audio buffer")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -80,7 +80,6 @@ const (
|
||||
|
||||
type encoderVP8 struct {
|
||||
r video.Reader
|
||||
buf []byte
|
||||
frame []byte
|
||||
|
||||
fdDRI C.int
|
||||
@@ -297,25 +296,17 @@ func newVP8Encoder(r video.Reader, p prop.Media, params ParamsVP8) (codec.ReadCl
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (e *encoderVP8) Read(p []byte) (int, error) {
|
||||
func (e *encoderVP8) Read() ([]byte, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if e.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if e.buf != nil {
|
||||
n, err := mio.Copy(p, e.buf)
|
||||
if err == nil {
|
||||
e.buf = nil
|
||||
}
|
||||
return n, err
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
img, err := e.r.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
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 {
|
||||
return 0, errors.New("no available surface")
|
||||
return nil, errors.New("no available surface")
|
||||
}
|
||||
|
||||
C.setForceKFFlagVP8(&e.picParam, 0)
|
||||
@@ -425,7 +416,7 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
|
||||
C.size_t(uintptr(p.src)),
|
||||
&id,
|
||||
); 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)
|
||||
}
|
||||
@@ -435,17 +426,17 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
|
||||
e.display, e.ctxID,
|
||||
e.surfs[surfaceVP8Input],
|
||||
); 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
|
||||
var vaImg C.VAImage
|
||||
var rawBuf unsafe.Pointer
|
||||
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 {
|
||||
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
|
||||
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)),
|
||||
)
|
||||
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 {
|
||||
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(
|
||||
@@ -472,38 +463,38 @@ func (e *encoderVP8) Read(p []byte) (int, error) {
|
||||
&buffs[1], // 0 is for ouput
|
||||
C.int(len(buffs)-1),
|
||||
); 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(
|
||||
e.display, e.ctxID,
|
||||
); 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
|
||||
for retry := 3; retry >= 0; retry-- {
|
||||
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
|
||||
if s := C.vaQuerySurfaceStatus(
|
||||
e.display, e.picParam.reconstructed_frame, &surfStat,
|
||||
); 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 {
|
||||
break
|
||||
}
|
||||
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
|
||||
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 {
|
||||
return 0, errors.New("buffer size too small")
|
||||
return nil, errors.New("buffer size too small")
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
for _, b := range buffs {
|
||||
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
|
||||
C.setRefreshLastFlagVP8(&e.picParam, 1)
|
||||
|
||||
n, err := mio.Copy(p, e.frame)
|
||||
if err != nil {
|
||||
e.buf = e.frame
|
||||
}
|
||||
return n, err
|
||||
encoded := make([]byte, len(e.frame))
|
||||
copy(encoded, e.frame)
|
||||
return encoded, err
|
||||
}
|
||||
|
||||
func (e *encoderVP8) SetBitRate(b int) error {
|
||||
|
@@ -67,7 +67,6 @@ const (
|
||||
|
||||
type encoderVP9 struct {
|
||||
r video.Reader
|
||||
buf []byte
|
||||
frame []byte
|
||||
|
||||
fdDRI C.int
|
||||
@@ -286,25 +285,17 @@ func newVP9Encoder(r video.Reader, p prop.Media, params ParamsVP9) (codec.ReadCl
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (e *encoderVP9) Read(p []byte) (int, error) {
|
||||
func (e *encoderVP9) Read() ([]byte, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if e.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if e.buf != nil {
|
||||
n, err := mio.Copy(p, e.buf)
|
||||
if err == nil {
|
||||
e.buf = nil
|
||||
}
|
||||
return n, err
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
img, err := e.r.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
yuvImg := img.(*image.YCbCr)
|
||||
|
||||
@@ -398,17 +389,17 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
|
||||
e.display, e.ctxID,
|
||||
e.surfs[surfaceVP9Input],
|
||||
); 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
|
||||
var vaImg C.VAImage
|
||||
var rawBuf unsafe.Pointer
|
||||
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 {
|
||||
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
|
||||
C.copyI420toNV12(
|
||||
@@ -419,10 +410,10 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
|
||||
C.uint(len(yuvImg.Y)),
|
||||
)
|
||||
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 {
|
||||
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(
|
||||
@@ -430,27 +421,27 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
|
||||
&buffs[1], // 0 is for ouput
|
||||
C.int(len(buffs)-1),
|
||||
); 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(
|
||||
e.display, e.ctxID,
|
||||
); 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
|
||||
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
|
||||
if s := C.vaQuerySurfaceStatus(
|
||||
e.display, e.picParam.reconstructed_frame, &surfStat,
|
||||
); 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
|
||||
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) {
|
||||
e.frame = make([]byte, int(seg.size))
|
||||
@@ -480,11 +471,9 @@ func (e *encoderVP9) Read(p []byte) (int, error) {
|
||||
e.slotCurr = 0
|
||||
}
|
||||
|
||||
n, err := mio.Copy(p, e.frame)
|
||||
if err != nil {
|
||||
e.buf = e.frame
|
||||
}
|
||||
return n, err
|
||||
encoded := make([]byte, len(e.frame))
|
||||
copy(encoded, e.frame)
|
||||
return encoded, err
|
||||
}
|
||||
|
||||
func (e *encoderVP9) SetBitRate(b int) error {
|
||||
|
@@ -56,7 +56,6 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"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/prop"
|
||||
)
|
||||
@@ -67,7 +66,6 @@ type encoder struct {
|
||||
cfg *C.vpx_codec_enc_cfg_t
|
||||
r video.Reader
|
||||
frameIndex int
|
||||
buff []byte
|
||||
tStart int
|
||||
tLastFrame int
|
||||
frame []byte
|
||||
@@ -206,25 +204,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params, codecIface *C.vpx_c
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *encoder) Read(p []byte) (int, error) {
|
||||
func (e *encoder) Read() ([]byte, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if e.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if e.buff != nil {
|
||||
n, err := mio.Copy(p, e.buff)
|
||||
if err == nil {
|
||||
e.buff = nil
|
||||
}
|
||||
return n, err
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
img, err := e.r.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
yuvImg := img.(*image.YCbCr)
|
||||
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) {
|
||||
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 {
|
||||
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.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.uchar)(&yuvImg.Y[0]), (*C.uchar)(&yuvImg.Cb[0]), (*C.uchar)(&yuvImg.Cr[0]),
|
||||
); 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++
|
||||
@@ -271,11 +261,10 @@ func (e *encoder) Read(p []byte) (int, error) {
|
||||
e.frame = append(e.frame, encoded...)
|
||||
}
|
||||
}
|
||||
n, err := mio.Copy(p, e.frame)
|
||||
if err != nil {
|
||||
e.buff = e.frame
|
||||
}
|
||||
return n, err
|
||||
|
||||
encoded := make([]byte, len(e.frame))
|
||||
copy(encoded, e.frame)
|
||||
return encoded, err
|
||||
}
|
||||
|
||||
func (e *encoder) SetBitRate(b int) error {
|
||||
|
@@ -14,14 +14,12 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"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/prop"
|
||||
)
|
||||
|
||||
type encoder struct {
|
||||
engine *C.Encoder
|
||||
buff []byte
|
||||
r video.Reader
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
@@ -96,25 +94,17 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser,
|
||||
return &e, nil
|
||||
}
|
||||
|
||||
func (e *encoder) Read(p []byte) (int, error) {
|
||||
func (e *encoder) Read() ([]byte, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if e.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if e.buff != nil {
|
||||
n, err := mio.Copy(p, e.buff)
|
||||
if err == nil {
|
||||
e.buff = nil
|
||||
}
|
||||
return n, err
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
img, err := e.r.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
yuvImg := img.(*image.YCbCr)
|
||||
|
||||
@@ -127,15 +117,11 @@ func (e *encoder) Read(p []byte) (int, error) {
|
||||
&rc,
|
||||
)
|
||||
if err := errFromC(rc); err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encoded := C.GoBytes(unsafe.Pointer(s.data), s.data_len)
|
||||
n, err := mio.Copy(p, encoded)
|
||||
if err != nil {
|
||||
e.buff = encoded
|
||||
}
|
||||
return n, err
|
||||
return encoded, err
|
||||
}
|
||||
|
||||
func (e *encoder) SetBitRate(b int) error {
|
||||
|
11
pkg/io/io.go
11
pkg/io/io.go
@@ -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
|
||||
}
|
@@ -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])
|
||||
}
|
||||
}
|
||||
}
|
13
track.go
13
track.go
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/pion/mediadevices/pkg/codec"
|
||||
"github.com/pion/mediadevices/pkg/driver"
|
||||
mio "github.com/pion/mediadevices/pkg/io"
|
||||
"github.com/pion/webrtc/v2"
|
||||
"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
|
||||
func (t *track) start() {
|
||||
var n int
|
||||
var err error
|
||||
buff := make([]byte, 1024)
|
||||
for {
|
||||
n, err = t.encoder.Read(buff)
|
||||
buff, err := t.encoder.Read()
|
||||
if err != nil {
|
||||
if e, ok := err.(*mio.InsufficientBufferError); ok {
|
||||
buff = make([]byte, 2*e.RequiredSize)
|
||||
continue
|
||||
}
|
||||
|
||||
t.onError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := t.sample(buff[:n]); err != nil {
|
||||
if err := t.sample(buff); err != nil {
|
||||
t.onError(err)
|
||||
return
|
||||
}
|
||||
|
Reference in New Issue
Block a user