mirror of
https://github.com/asticode/go-astiav.git
synced 2025-10-24 16:40:22 +08:00
Added FrameData ToImage()
This commit is contained in:
150
frame_data.go
150
frame_data.go
@@ -9,6 +9,38 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type frameDataImageFormat int
|
||||||
|
|
||||||
|
const (
|
||||||
|
frameDataImageFormatNone frameDataImageFormat = iota
|
||||||
|
frameDataImageFormatNRGBA
|
||||||
|
frameDataImageFormatNYCbCrA
|
||||||
|
frameDataImageFormatYCbCr
|
||||||
|
)
|
||||||
|
|
||||||
|
func frameDataImageFormatFromPixelFormat(pf PixelFormat) frameDataImageFormat {
|
||||||
|
// Switch on pixel format
|
||||||
|
switch pf {
|
||||||
|
// NRGBA
|
||||||
|
case PixelFormatRgba:
|
||||||
|
return frameDataImageFormatNRGBA
|
||||||
|
// NYCbCrA
|
||||||
|
case PixelFormatYuva420P,
|
||||||
|
PixelFormatYuva422P,
|
||||||
|
PixelFormatYuva444P:
|
||||||
|
return frameDataImageFormatNYCbCrA
|
||||||
|
// YCbCr
|
||||||
|
case PixelFormatYuv410P,
|
||||||
|
PixelFormatYuv411P, PixelFormatYuvj411P,
|
||||||
|
PixelFormatYuv420P, PixelFormatYuvj420P,
|
||||||
|
PixelFormatYuv422P, PixelFormatYuvj422P,
|
||||||
|
PixelFormatYuv440P, PixelFormatYuvj440P,
|
||||||
|
PixelFormatYuv444P, PixelFormatYuvj444P:
|
||||||
|
return frameDataImageFormatYCbCr
|
||||||
|
}
|
||||||
|
return frameDataImageFormatNone
|
||||||
|
}
|
||||||
|
|
||||||
type FrameData struct {
|
type FrameData struct {
|
||||||
f *Frame
|
f *Frame
|
||||||
}
|
}
|
||||||
@@ -44,9 +76,9 @@ func (d *FrameData) Bytes(align int) ([]byte, error) {
|
|||||||
return nil, errors.New("astiav: frame type not implemented")
|
return nil, errors.New("astiav: frame type not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *FrameData) planeData(i int, sizeFunc func(linesize int) int) []byte {
|
func (d *FrameData) planeBytes(i int) []byte {
|
||||||
return bytesFromC(func(size *cUlong) *C.uint8_t {
|
return bytesFromC(func(size *cUlong) *C.uint8_t {
|
||||||
*size = cUlong(sizeFunc(int(d.f.c.linesize[i])))
|
*size = cUlong(int(d.f.c.linesize[i]) * d.f.Height())
|
||||||
return d.f.c.data[i]
|
return d.f.c.data[i]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -68,53 +100,99 @@ func (d *FrameData) imageYCbCrSubsampleRatio() image.YCbCrSubsampleRatio {
|
|||||||
return image.YCbCrSubsampleRatio444
|
return image.YCbCrSubsampleRatio444
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *FrameData) imageNRGBA() *image.NRGBA {
|
func (d *FrameData) copyPlaneBytes(i int, s *[]uint8) {
|
||||||
return &image.NRGBA{
|
b := d.planeBytes(0)
|
||||||
Pix: d.planeData(0, func(linesize int) int { return linesize * d.f.Height() }),
|
if len(b) > cap(*s) {
|
||||||
Stride: d.f.Linesize()[0],
|
*s = make([]uint8, len(b))
|
||||||
Rect: image.Rect(0, 0, d.f.Width(), d.f.Height()),
|
}
|
||||||
|
copy(*s, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *FrameData) toImageNRGBA(i *image.NRGBA) {
|
||||||
|
d.copyPlaneBytes(0, &i.Pix)
|
||||||
|
if v := d.f.Linesize()[0]; i.Stride != v {
|
||||||
|
i.Stride = v
|
||||||
|
}
|
||||||
|
if w, h := d.f.Width(), d.f.Height(); i.Rect.Dy() != w || i.Rect.Dx() != h {
|
||||||
|
i.Rect = image.Rect(0, 0, w, h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *FrameData) imageYCbCr() *image.YCbCr {
|
func (d *FrameData) toImageYCbCr(i *image.YCbCr) {
|
||||||
return &image.YCbCr{
|
d.copyPlaneBytes(0, &i.Y)
|
||||||
Y: d.planeData(0, func(linesize int) int { return linesize * d.f.Height() }),
|
d.copyPlaneBytes(1, &i.Cb)
|
||||||
Cb: d.planeData(1, func(linesize int) int { return linesize * d.f.Height() }),
|
d.copyPlaneBytes(2, &i.Cr)
|
||||||
Cr: d.planeData(2, func(linesize int) int { return linesize * d.f.Height() }),
|
if v := d.f.Linesize()[0]; i.YStride != v {
|
||||||
YStride: d.f.Linesize()[0],
|
i.YStride = v
|
||||||
CStride: d.f.Linesize()[1],
|
}
|
||||||
SubsampleRatio: d.imageYCbCrSubsampleRatio(),
|
if v := d.f.Linesize()[1]; i.CStride != v {
|
||||||
Rect: image.Rect(0, 0, d.f.Width(), d.f.Height()),
|
i.CStride = v
|
||||||
|
}
|
||||||
|
if v := d.imageYCbCrSubsampleRatio(); i.SubsampleRatio != v {
|
||||||
|
i.SubsampleRatio = v
|
||||||
|
}
|
||||||
|
if w, h := d.f.Width(), d.f.Height(); i.Rect.Dy() != w || i.Rect.Dx() != h {
|
||||||
|
i.Rect = image.Rect(0, 0, w, h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *FrameData) imageNYCbCrA() *image.NYCbCrA {
|
func (d *FrameData) toImageNYCbCrA(i *image.NYCbCrA) {
|
||||||
return &image.NYCbCrA{
|
d.toImageYCbCr(&i.YCbCr)
|
||||||
YCbCr: *d.imageYCbCr(),
|
d.copyPlaneBytes(3, &i.A)
|
||||||
A: d.planeData(3, func(linesize int) int { return linesize * d.f.Height() }),
|
if v := d.f.Linesize()[3]; i.AStride != v {
|
||||||
AStride: d.f.Linesize()[3],
|
i.AStride = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *FrameData) Image() (image.Image, error) {
|
func (d *FrameData) Image() (image.Image, error) {
|
||||||
// Switch on pixel format
|
// Switch on image format
|
||||||
switch d.f.PixelFormat() {
|
switch frameDataImageFormatFromPixelFormat(d.f.PixelFormat()) {
|
||||||
// NRGBA
|
// NRGBA
|
||||||
case PixelFormatRgba:
|
case frameDataImageFormatNRGBA:
|
||||||
return d.imageNRGBA(), nil
|
i := &image.NRGBA{}
|
||||||
|
d.toImageNRGBA(i)
|
||||||
|
return i, nil
|
||||||
// NYCbCrA
|
// NYCbCrA
|
||||||
case PixelFormatYuva420P,
|
case frameDataImageFormatNYCbCrA:
|
||||||
PixelFormatYuva422P,
|
i := &image.NYCbCrA{}
|
||||||
PixelFormatYuva444P:
|
d.toImageNYCbCrA(i)
|
||||||
return d.imageNYCbCrA(), nil
|
return i, nil
|
||||||
// YCbCr
|
// YCbCr
|
||||||
case PixelFormatYuv410P,
|
case frameDataImageFormatYCbCr:
|
||||||
PixelFormatYuv411P, PixelFormatYuvj411P,
|
i := &image.YCbCr{}
|
||||||
PixelFormatYuv420P, PixelFormatYuvj420P,
|
d.toImageYCbCr(i)
|
||||||
PixelFormatYuv422P, PixelFormatYuvj422P,
|
return i, nil
|
||||||
PixelFormatYuv440P, PixelFormatYuvj440P,
|
|
||||||
PixelFormatYuv444P, PixelFormatYuvj444P:
|
|
||||||
return d.imageYCbCr(), nil
|
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("astiav: %s pixel format not handled by the Go standard image package", d.f.PixelFormat())
|
return nil, fmt.Errorf("astiav: %s pixel format not handled by the Go standard image package", d.f.PixelFormat())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *FrameData) ToImage(dst image.Image) error {
|
||||||
|
// Switch on image format
|
||||||
|
switch frameDataImageFormatFromPixelFormat(d.f.PixelFormat()) {
|
||||||
|
// NRGBA
|
||||||
|
case frameDataImageFormatNRGBA:
|
||||||
|
i, ok := dst.(*image.NRGBA)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("astiav: image should be *image.NRGBA")
|
||||||
|
}
|
||||||
|
d.toImageNRGBA(i)
|
||||||
|
return nil
|
||||||
|
// NYCbCrA
|
||||||
|
case frameDataImageFormatNYCbCrA:
|
||||||
|
i, ok := dst.(*image.NYCbCrA)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("astiav: image should be *image.NYCbCrA")
|
||||||
|
}
|
||||||
|
d.toImageNYCbCrA(i)
|
||||||
|
return nil
|
||||||
|
// YCbCr
|
||||||
|
case frameDataImageFormatYCbCr:
|
||||||
|
i, ok := dst.(*image.YCbCr)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("astiav: image should be *image.YCbCr")
|
||||||
|
}
|
||||||
|
d.toImageYCbCr(i)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("astiav: %s pixel format not handled by the Go standard image package", d.f.PixelFormat())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package astiav_test
|
package astiav_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image"
|
||||||
"image/png"
|
"image/png"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -12,10 +13,12 @@ import (
|
|||||||
func TestFrameData(t *testing.T) {
|
func TestFrameData(t *testing.T) {
|
||||||
for _, v := range []struct {
|
for _, v := range []struct {
|
||||||
ext string
|
ext string
|
||||||
|
i image.Image
|
||||||
name string
|
name string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
ext: "png",
|
ext: "png",
|
||||||
|
i: &image.NRGBA{},
|
||||||
name: "image-rgba",
|
name: "image-rgba",
|
||||||
},
|
},
|
||||||
// TODO Find a way to test yuv and yuva even though result seems to change randomly
|
// TODO Find a way to test yuv and yuva even though result seems to change randomly
|
||||||
@@ -39,9 +42,11 @@ func TestFrameData(t *testing.T) {
|
|||||||
|
|
||||||
i1, err := fd.Image()
|
i1, err := fd.Image()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, fd.ToImage(v.i))
|
||||||
i2, err := png.Decode(f1)
|
i2, err := png.Decode(f1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, i1, i2)
|
require.Equal(t, i1, i2)
|
||||||
|
require.Equal(t, v.i, i2)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user