mirror of
https://github.com/pion/mediadevices.git
synced 2025-10-05 08:36:55 +08:00
281 lines
7.1 KiB
Go
281 lines
7.1 KiB
Go
package video
|
|
|
|
import (
|
|
"image"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestScale(t *testing.T) {
|
|
cases := map[string]struct {
|
|
src image.Image
|
|
width, height int
|
|
expected image.Image
|
|
}{
|
|
"RGBA": {
|
|
src: &image.RGBA{
|
|
Pix: []uint8{
|
|
// R G B A | R G B A | R G B A | R G B A
|
|
0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
|
0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
|
0x00, 0x40, 0x00, 0xFF, 0x00, 0x40, 0x00, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x60, 0xFF,
|
|
0x00, 0x40, 0x00, 0xFF, 0x00, 0x40, 0x00, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x60, 0xFF,
|
|
},
|
|
Stride: 16,
|
|
Rect: image.Rect(0, 0, 4, 4),
|
|
},
|
|
width: 2,
|
|
height: 2,
|
|
expected: &image.RGBA{
|
|
Pix: []uint8{
|
|
// R G B A | R G B A
|
|
0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
|
0x00, 0x40, 0x00, 0xFF, 0x00, 0x00, 0x60, 0xFF,
|
|
},
|
|
Stride: 8,
|
|
Rect: image.Rect(0, 0, 2, 2),
|
|
},
|
|
},
|
|
"I444": {
|
|
src: &image.YCbCr{
|
|
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
|
Y: []uint8{
|
|
0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
|
|
0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
|
|
0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
|
|
0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
|
|
},
|
|
Cb: []uint8{
|
|
0x20, 0x20, 0x80, 0x80, 0x80, 0x80,
|
|
0x20, 0x20, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0,
|
|
0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
},
|
|
Cr: []uint8{
|
|
0xE0, 0xE0, 0x80, 0x80, 0x80, 0x80,
|
|
0xE0, 0xE0, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x40, 0x40, 0x80, 0x80,
|
|
0x80, 0x80, 0x40, 0x40, 0x80, 0x80,
|
|
},
|
|
YStride: 6,
|
|
CStride: 6,
|
|
Rect: image.Rect(0, 0, 6, 6),
|
|
},
|
|
width: 3,
|
|
height: 3,
|
|
expected: &image.YCbCr{
|
|
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
|
Y: []uint8{
|
|
0xF0, 0x00, 0x00,
|
|
0x00, 0x00, 0x40,
|
|
0x00, 0x80, 0x00,
|
|
},
|
|
Cb: []uint8{
|
|
0x20, 0x80, 0x80,
|
|
0x80, 0x80, 0xC0,
|
|
0x80, 0x80, 0x80,
|
|
},
|
|
Cr: []uint8{
|
|
0xE0, 0x80, 0x80,
|
|
0x80, 0x80, 0x80,
|
|
0x80, 0x40, 0x80,
|
|
},
|
|
YStride: 3,
|
|
CStride: 3,
|
|
Rect: image.Rect(0, 0, 3, 3),
|
|
},
|
|
},
|
|
"I422": {
|
|
src: &image.YCbCr{
|
|
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
|
Y: []uint8{
|
|
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
|
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
|
|
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
|
|
},
|
|
Cb: []uint8{
|
|
0x20, 0x20, 0x80, 0x80,
|
|
0x20, 0x20, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0xE0, 0xE0,
|
|
0x80, 0x80, 0xE0, 0xE0,
|
|
},
|
|
Cr: []uint8{
|
|
0xE0, 0xE0, 0x80, 0x80,
|
|
0xE0, 0xE0, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80,
|
|
0xF0, 0xF0, 0x40, 0x40,
|
|
0xF0, 0xF0, 0x40, 0x40,
|
|
},
|
|
YStride: 8,
|
|
CStride: 4,
|
|
Rect: image.Rect(0, 0, 8, 8),
|
|
},
|
|
width: 4,
|
|
height: 4,
|
|
expected: &image.YCbCr{
|
|
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
|
Y: []uint8{
|
|
0xF0, 0x10, 0x00, 0x00,
|
|
0x00, 0x00, 0x40, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x80, 0x30, 0x00,
|
|
},
|
|
Cb: []uint8{
|
|
0x20, 0x80,
|
|
0x80, 0x80,
|
|
0x80, 0x80,
|
|
0x80, 0xE0,
|
|
},
|
|
Cr: []uint8{
|
|
0xE0, 0x80,
|
|
0x80, 0x80,
|
|
0x80, 0x80,
|
|
0xF0, 0x40,
|
|
},
|
|
YStride: 4,
|
|
CStride: 2,
|
|
Rect: image.Rect(0, 0, 4, 4),
|
|
},
|
|
},
|
|
"I420": {
|
|
src: &image.YCbCr{
|
|
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
|
Y: []uint8{
|
|
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
|
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
|
|
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
|
|
},
|
|
Cb: []uint8{
|
|
0x20, 0x20, 0x80, 0x80,
|
|
0x20, 0x20, 0x80, 0x80,
|
|
0x80, 0x80, 0xE0, 0xE0,
|
|
0x80, 0x80, 0xE0, 0xE0,
|
|
},
|
|
Cr: []uint8{
|
|
0xE0, 0xE0, 0x80, 0x80,
|
|
0xE0, 0xE0, 0x80, 0x80,
|
|
0xF0, 0xF0, 0x40, 0x40,
|
|
0xF0, 0xF0, 0x40, 0x40,
|
|
},
|
|
YStride: 8,
|
|
CStride: 4,
|
|
Rect: image.Rect(0, 0, 8, 8),
|
|
},
|
|
width: 4,
|
|
height: 4,
|
|
expected: &image.YCbCr{
|
|
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
|
Y: []uint8{
|
|
0xF0, 0x10, 0x00, 0x00,
|
|
0x00, 0x00, 0x40, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x80, 0x30, 0x00,
|
|
},
|
|
Cb: []uint8{
|
|
0x20, 0x80,
|
|
0x80, 0xE0,
|
|
},
|
|
Cr: []uint8{
|
|
0xE0, 0x80,
|
|
0xF0, 0x40,
|
|
},
|
|
YStride: 4,
|
|
CStride: 2,
|
|
Rect: image.Rect(0, 0, 4, 4),
|
|
},
|
|
},
|
|
}
|
|
for name, algo := range scalerTestAlgos {
|
|
algo := algo
|
|
t.Run(name, func(t *testing.T) {
|
|
for name, c := range cases {
|
|
c := c
|
|
t.Run(name, func(t *testing.T) {
|
|
trans := Scale(c.width, c.height, algo)
|
|
r := trans(ReaderFunc(func() (image.Image, func(), error) {
|
|
return c.src, func() {}, nil
|
|
}))
|
|
for i := 0; i < 4; i++ {
|
|
out, _, err := r.Read()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(c.expected, out) {
|
|
t.Errorf("Expected output image:\n%v\ngot:\n%v\nrepeat: %d", c.expected, out, i)
|
|
}
|
|
// Destroy output contents
|
|
switch v := out.(type) {
|
|
case *image.RGBA:
|
|
v.Stride = 10
|
|
v.Pix = v.Pix[:1]
|
|
v.Rect.Max.X = 1
|
|
case *image.YCbCr:
|
|
v.YStride = 10
|
|
v.CStride = 100
|
|
v.Y = v.Y[:1]
|
|
v.Cb = v.Cb[:2]
|
|
v.Cr = v.Cr[:1]
|
|
v.Rect.Max.X = 1
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkScale(b *testing.B) {
|
|
for name, algo := range scalerBenchAlgos {
|
|
algo := algo
|
|
b.Run(name, func(b *testing.B) {
|
|
for name, sz := range imageSizes {
|
|
cases := map[string]image.Image{
|
|
"RGBA": image.NewRGBA(image.Rect(0, 0, sz[0], sz[1])),
|
|
"I444": image.NewYCbCr(image.Rect(0, 0, sz[0], sz[1]), image.YCbCrSubsampleRatio444),
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
for name, img := range cases {
|
|
img := img
|
|
b.Run(name, func(b *testing.B) {
|
|
trans := Scale(640, 360, algo)
|
|
r := trans(ReaderFunc(func() (image.Image, func(), error) {
|
|
return img, func() {}, nil
|
|
}))
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_, _, err := r.Read()
|
|
if err != nil {
|
|
b.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|