mirror of
https://github.com/pion/mediadevices.git
synced 2025-09-26 20:41:46 +08:00
Add pool optimization to frame decoders
This commit is contained in:
8
pkg/frame/buffer.go
Normal file
8
pkg/frame/buffer.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package frame
|
||||
|
||||
import "image"
|
||||
|
||||
type buffer struct {
|
||||
image image.Image
|
||||
raw []uint8
|
||||
}
|
@@ -6,7 +6,9 @@ import (
|
||||
"image/jpeg"
|
||||
)
|
||||
|
||||
func decodeMJPEG(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
func decodeMJPEG() decoderFunc {
|
||||
return func(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
img, err := jpeg.Decode(bytes.NewReader(frame))
|
||||
return img, func() {}, err
|
||||
}
|
||||
}
|
||||
|
@@ -5,22 +5,22 @@ import (
|
||||
)
|
||||
|
||||
func NewDecoder(f Format) (Decoder, error) {
|
||||
var decoder decoderFunc
|
||||
var buildDecoder func() decoderFunc
|
||||
|
||||
switch f {
|
||||
case FormatI420:
|
||||
decoder = decodeI420
|
||||
buildDecoder = decodeI420
|
||||
case FormatNV21:
|
||||
decoder = decodeNV21
|
||||
buildDecoder = decodeNV21
|
||||
case FormatYUY2:
|
||||
decoder = decodeYUY2
|
||||
buildDecoder = decodeYUY2
|
||||
case FormatUYVY:
|
||||
decoder = decodeUYVY
|
||||
buildDecoder = decodeUYVY
|
||||
case FormatMJPEG:
|
||||
decoder = decodeMJPEG
|
||||
buildDecoder = decodeMJPEG
|
||||
default:
|
||||
return nil, fmt.Errorf("%s is not supported", f)
|
||||
}
|
||||
|
||||
return decoder, nil
|
||||
return buildDecoder(), nil
|
||||
}
|
||||
|
@@ -5,7 +5,8 @@ import (
|
||||
"image"
|
||||
)
|
||||
|
||||
func decodeI420(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
func decodeI420() decoderFunc {
|
||||
return func(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
yi := width * height
|
||||
cbi := yi + width*height/4
|
||||
cri := cbi + width*height/4
|
||||
@@ -23,9 +24,11 @@ func decodeI420(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}, func() {}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func decodeNV21(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
func decodeNV21() decoderFunc {
|
||||
return func(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
yi := width * height
|
||||
ci := yi + width*height/2
|
||||
|
||||
@@ -48,4 +51,5 @@ func decodeNV21(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}, func() {}, nil
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,8 @@ import (
|
||||
// void decodeUYVYCGO(uint8_t* y, uint8_t* cb, uint8_t* cr, uint8_t* uyvy, int width, int height);
|
||||
import "C"
|
||||
|
||||
func decodeYUY2(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
func decodeYUY2() decoderFunc {
|
||||
return func(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
yi := width * height
|
||||
ci := yi / 2
|
||||
fi := yi + 2*ci
|
||||
@@ -42,9 +43,11 @@ func decodeYUY2(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}, func() {}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func decodeUYVY(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
func decodeUYVY() decoderFunc {
|
||||
return func(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
yi := width * height
|
||||
ci := yi / 2
|
||||
fi := yi + 2*ci
|
||||
@@ -74,4 +77,5 @@ func decodeUYVY(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}, func() {}, nil
|
||||
}
|
||||
}
|
||||
|
@@ -5,20 +5,37 @@ package frame
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func decodeYUY2(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
func decodeYUY2() decoderFunc {
|
||||
pool := sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &buffer{
|
||||
image: &image.YCbCr{},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return func(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
buff := pool.Get().(*buffer)
|
||||
|
||||
yi := width * height
|
||||
ci := yi / 2
|
||||
fi := yi + 2*ci
|
||||
|
||||
if len(frame) != fi {
|
||||
pool.Put(buff)
|
||||
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
||||
}
|
||||
|
||||
y := make([]byte, yi)
|
||||
cb := make([]byte, ci)
|
||||
cr := make([]byte, ci)
|
||||
if len(buff.raw) < fi {
|
||||
need := fi - len(buff.raw)
|
||||
buff.raw = append(buff.raw, make([]uint8, need)...)
|
||||
}
|
||||
y := buff.raw[:yi:yi]
|
||||
cb := buff.raw[yi : yi+ci : yi+ci]
|
||||
cr := buff.raw[yi+ci : fi : fi]
|
||||
|
||||
fast := 0
|
||||
slow := 0
|
||||
@@ -31,18 +48,23 @@ func decodeYUY2(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
slow++
|
||||
}
|
||||
|
||||
return &image.YCbCr{
|
||||
Y: y,
|
||||
YStride: width,
|
||||
Cb: cb,
|
||||
Cr: cr,
|
||||
CStride: width / 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}, func() {}, nil
|
||||
img := buff.image.(*image.YCbCr)
|
||||
img.Y = y
|
||||
img.YStride = width
|
||||
img.Cb = cb
|
||||
img.Cr = cr
|
||||
img.CStride = width / 2
|
||||
img.SubsampleRatio = image.YCbCrSubsampleRatio422
|
||||
img.Rect.Min.X = 0
|
||||
img.Rect.Min.Y = 0
|
||||
img.Rect.Max.X = width
|
||||
img.Rect.Max.Y = height
|
||||
return img, func() { pool.Put(buff) }, nil
|
||||
}
|
||||
}
|
||||
|
||||
func decodeUYVY(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
func decodeUYVY() decoderFunc {
|
||||
return func(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
yi := width * height
|
||||
ci := yi / 2
|
||||
fi := yi + 2*ci
|
||||
@@ -75,4 +97,5 @@ func decodeUYVY(frame []byte, width, height int) (image.Image, func(), error) {
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}, func() {}, nil
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ func TestDecodeYUY2(t *testing.T) {
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}
|
||||
|
||||
img, _, err := decodeYUY2(input, width, height)
|
||||
img, _, err := decodeYUY2()(input, width, height)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func TestDecodeUYVY(t *testing.T) {
|
||||
Rect: image.Rect(0, 0, width, height),
|
||||
}
|
||||
|
||||
img, _, err := decodeUYVY(input, width, height)
|
||||
img, _, err := decodeUYVY()(input, width, height)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -76,11 +76,13 @@ func BenchmarkDecodeYUY2(b *testing.B) {
|
||||
sz := sz
|
||||
b.Run(fmt.Sprintf("%dx%d", sz.width, sz.height), func(b *testing.B) {
|
||||
input := make([]byte, sz.width*sz.height*2)
|
||||
decode := decodeYUY2()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, err := decodeYUY2(input, sz.width, sz.height)
|
||||
_, release, err := decode(input, sz.width, sz.height)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
release()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user