rename colorspace to colorformat

This commit is contained in:
DataHoarder 2022-09-15 23:43:42 +02:00
parent 52147f9138
commit 86a7d25bcd
Signed by: DataHoarder
SSH key fingerprint: SHA256:EnPQOqPpbCa7nzalCEJY2sd9iPluFIBuJu2rDFalACI
7 changed files with 103 additions and 101 deletions

View file

@ -1,4 +1,4 @@
package colorspace
package colorformat
import (
"encoding/binary"
@ -18,42 +18,42 @@ type SubsamplingScheme struct {
B byte
}
type ColorSpace struct {
type ColorFormat struct {
Subsampling SubsamplingScheme
BitDepth byte
}
func (c ColorSpace) ToInteger() uint32 {
func (c ColorFormat) ToInteger() uint32 {
return binary.BigEndian.Uint32([]byte{c.Subsampling.J, c.Subsampling.A, c.Subsampling.B, c.BitDepth})
}
// ElementPixels returns the number of pixels for a full element
func (c ColorSpace) ElementPixels() int {
func (c ColorFormat) ElementPixels() int {
return int(c.Subsampling.J) * 2
}
// ElementSamples returns the number of actual samples (total Y, Cb, Cr) for an encoded element
func (c ColorSpace) ElementSamples() int {
func (c ColorFormat) ElementSamples() int {
return int(c.Subsampling.J)*2 + c.ElementChromaSamples()
}
func (c ColorSpace) ElementChromaSamples() int {
func (c ColorFormat) ElementChromaSamples() int {
return int(c.Subsampling.A)*2 + int(c.Subsampling.B)*2
}
func (c ColorSpace) PlaneLumaSamples(width, height int) int {
func (c ColorFormat) PlaneLumaSamples(width, height int) int {
return width * height
}
func (c ColorSpace) PlaneCrSamples(width, height int) int {
func (c ColorFormat) PlaneCrSamples(width, height int) int {
return int((int64(width) * int64(height) * (int64(c.Subsampling.A) + int64(c.Subsampling.B))) / int64(c.ElementPixels()))
}
func (c ColorSpace) PlaneCbSamples(width, height int) int {
func (c ColorFormat) PlaneCbSamples(width, height int) int {
return int((int64(width) * int64(height) * (int64(c.Subsampling.A) + int64(c.Subsampling.B))) / int64(c.ElementPixels()))
}
func (c ColorSpace) FrameSizePacked(width, height int) (int, error) {
func (c ColorFormat) FrameSizePacked(width, height int) (int, error) {
a1 := int64(width) * int64(height)
a2 := int64(c.ElementPixels())
if a1%a2 != 0 {
@ -67,7 +67,7 @@ func (c ColorSpace) FrameSizePacked(width, height int) (int, error) {
return int(a3 / 8), nil
}
func (c ColorSpace) FrameSize(width, height int) (int, error) {
func (c ColorFormat) FrameSize(width, height int) (int, error) {
actualBitDepth := int64(c.BitDepth)
if actualBitDepth&0b111 != 0 {
actualBitDepth = ((actualBitDepth + 8) >> 3) << 3
@ -86,7 +86,7 @@ func (c ColorSpace) FrameSize(width, height int) (int, error) {
return int(a3 / 8), nil
}
func (c ColorSpace) check() error {
func (c ColorFormat) check() error {
if c.Subsampling.J <= 0 {
return fmt.Errorf("unsupported J %d", c.Subsampling.J)
}
@ -103,11 +103,11 @@ func (c ColorSpace) check() error {
return nil
}
func NewColorSpaceFromInteger(colorSpace uint32) (ColorSpace, error) {
func NewColorFormatFromInteger(colorFormat uint32) (ColorFormat, error) {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, colorSpace)
binary.BigEndian.PutUint32(buf, colorFormat)
space := ColorSpace{
space := ColorFormat{
Subsampling: SubsamplingScheme{
J: buf[0],
A: buf[1],
@ -119,17 +119,17 @@ func NewColorSpaceFromInteger(colorSpace uint32) (ColorSpace, error) {
return space, space.check()
}
func NewColorSpaceFromString(colorSpace string) (ColorSpace, error) {
colorSpace = strings.ToLower(colorSpace)
if colorSpace == "420mpeg2" {
return NewColorSpaceFromString("420p8")
func NewColorFormatFromString(colorFormat string) (ColorFormat, error) {
colorFormat = strings.ToLower(colorFormat)
if colorFormat == "420mpeg2" {
return NewColorFormatFromString("420p8")
}
splits := strings.Split(colorSpace, "p")
splits := strings.Split(colorFormat, "p")
if len(splits) == 1 { //default 8 bit
splits = append(splits, "8")
}
space := ColorSpace{}
space := ColorFormat{}
switch strings.ReplaceAll(splits[0], ":", "") {
case "420":
space.Subsampling.J = 4
@ -156,22 +156,22 @@ func NewColorSpaceFromString(colorSpace string) (ColorSpace, error) {
return space, space.check()
}
func newColorSpaceFromStringInternal(colorSpace string) ColorSpace {
space, _ := NewColorSpaceFromString(colorSpace)
func newColorFormatFromStringInternal(colorFormat string) ColorFormat {
space, _ := NewColorFormatFromString(colorFormat)
return space
}
var (
Space420 ColorSpace = newColorSpaceFromStringInternal("420")
Space422 ColorSpace = newColorSpaceFromStringInternal("422")
Space444 ColorSpace = newColorSpaceFromStringInternal("444")
Space420P10 ColorSpace = newColorSpaceFromStringInternal("420p10")
Space422P10 ColorSpace = newColorSpaceFromStringInternal("422p10")
Space444P10 ColorSpace = newColorSpaceFromStringInternal("444p10")
Space420P12 ColorSpace = newColorSpaceFromStringInternal("420p12")
Space422P12 ColorSpace = newColorSpaceFromStringInternal("422p12")
Space444P12 ColorSpace = newColorSpaceFromStringInternal("444p12")
Space420P16 ColorSpace = newColorSpaceFromStringInternal("420p16")
Space422P16 ColorSpace = newColorSpaceFromStringInternal("422p16")
Space444P16 ColorSpace = newColorSpaceFromStringInternal("444p16")
Space420 ColorFormat = newColorFormatFromStringInternal("420")
Space422 ColorFormat = newColorFormatFromStringInternal("422")
Space444 ColorFormat = newColorFormatFromStringInternal("444")
Space420P10 ColorFormat = newColorFormatFromStringInternal("420p10")
Space422P10 ColorFormat = newColorFormatFromStringInternal("422p10")
Space444P10 ColorFormat = newColorFormatFromStringInternal("444p10")
Space420P12 ColorFormat = newColorFormatFromStringInternal("420p12")
Space422P12 ColorFormat = newColorFormatFromStringInternal("422p12")
Space444P12 ColorFormat = newColorFormatFromStringInternal("444p12")
Space420P16 ColorFormat = newColorFormatFromStringInternal("420p16")
Space422P16 ColorFormat = newColorFormatFromStringInternal("422p16")
Space444P16 ColorFormat = newColorFormatFromStringInternal("444p16")
)

View file

@ -55,13 +55,13 @@ func NewEncoder(w io.Writer, stream *y4m.Stream, settings map[string]any) (*Enco
}
switch true {
case stream.ColorSpace().Subsampling.J == 4 && stream.ColorSpace().Subsampling.A == 4 && stream.ColorSpace().Subsampling.B == 4:
case stream.ColorFormat().Subsampling.J == 4 && stream.ColorFormat().Subsampling.A == 4 && stream.ColorFormat().Subsampling.B == 4:
imageFormat = C.AOM_IMG_FMT_I444
e.cfg.g_profile = 1
case stream.ColorSpace().Subsampling.J == 4 && stream.ColorSpace().Subsampling.A == 2 && stream.ColorSpace().Subsampling.B == 2:
case stream.ColorFormat().Subsampling.J == 4 && stream.ColorFormat().Subsampling.A == 2 && stream.ColorFormat().Subsampling.B == 2:
imageFormat = C.AOM_IMG_FMT_I422
e.cfg.g_profile = 2
case stream.ColorSpace().Subsampling.J == 4 && stream.ColorSpace().Subsampling.A == 2 && stream.ColorSpace().Subsampling.B == 0:
case stream.ColorFormat().Subsampling.J == 4 && stream.ColorFormat().Subsampling.A == 2 && stream.ColorFormat().Subsampling.B == 0:
imageFormat = C.AOM_IMG_FMT_I420
e.cfg.g_profile = 0
default:
@ -69,12 +69,12 @@ func NewEncoder(w io.Writer, stream *y4m.Stream, settings map[string]any) (*Enco
}
if stream.ColorSpace().BitDepth > 8 {
if stream.ColorFormat().BitDepth > 8 {
imageFormat |= C.AOM_IMG_FMT_HIGHBITDEPTH
}
e.cfg.g_input_bit_depth = C.uint(stream.ColorSpace().BitDepth)
e.cfg.g_bit_depth = C.aom_bit_depth_t(stream.ColorSpace().BitDepth)
e.cfg.g_input_bit_depth = C.uint(stream.ColorFormat().BitDepth)
e.cfg.g_bit_depth = C.aom_bit_depth_t(stream.ColorFormat().BitDepth)
if e.cfg.g_bit_depth >= 12 {
e.cfg.g_bit_depth = 12

View file

@ -55,13 +55,13 @@ func NewEncoder(w io.Writer, stream *y4m.Stream, settings map[string]any) (*Enco
defaultProfile := "high"
switch true {
case stream.ColorSpace().Subsampling.J == 4 && stream.ColorSpace().Subsampling.A == 4 && stream.ColorSpace().Subsampling.B == 4:
case stream.ColorFormat().Subsampling.J == 4 && stream.ColorFormat().Subsampling.A == 4 && stream.ColorFormat().Subsampling.B == 4:
e.params.i_csp = C.X264_CSP_I444
defaultProfile = "high444"
case stream.ColorSpace().Subsampling.J == 4 && stream.ColorSpace().Subsampling.A == 2 && stream.ColorSpace().Subsampling.B == 2:
case stream.ColorFormat().Subsampling.J == 4 && stream.ColorFormat().Subsampling.A == 2 && stream.ColorFormat().Subsampling.B == 2:
e.params.i_csp = C.X264_CSP_I422
defaultProfile = "high422"
case stream.ColorSpace().Subsampling.J == 4 && stream.ColorSpace().Subsampling.A == 2 && stream.ColorSpace().Subsampling.B == 0:
case stream.ColorFormat().Subsampling.J == 4 && stream.ColorFormat().Subsampling.A == 2 && stream.ColorFormat().Subsampling.B == 0:
e.params.i_csp = C.X264_CSP_I420
defaultProfile = "high"
default:
@ -72,13 +72,13 @@ func NewEncoder(w io.Writer, stream *y4m.Stream, settings map[string]any) (*Enco
profile := C.CString(getSettingString(settings, "profile", defaultProfile))
defer C.free(unsafe.Pointer(profile))
if stream.ColorSpace().BitDepth > 8 {
if stream.ColorFormat().BitDepth > 8 {
e.params.i_csp |= C.X264_CSP_HIGH_DEPTH
if defaultProfile == "high" {
defaultProfile = "high10"
}
}
e.params.i_bitdepth = C.int(stream.ColorSpace().BitDepth)
e.params.i_bitdepth = C.int(stream.ColorFormat().BitDepth)
width, height := stream.Resolution()
e.params.i_width = C.int(width)

View file

@ -1,6 +1,8 @@
package frame
import "git.gammaspectra.live/S.O.N.G/Ignite/colorspace"
import (
"git.gammaspectra.live/S.O.N.G/Ignite/colorformat"
)
type AllowedFrameTypes interface {
uint8 | uint16
@ -9,7 +11,7 @@ type AllowedFrameTypes interface {
type Frame interface {
Width() int
Height() int
ColorSpace() colorspace.ColorSpace
ColorFormat() colorformat.ColorFormat
Get16(x, y int) (Y uint16, Cb uint16, Cr uint16)
Get8(x, y int) (Y uint8, Cb uint8, Cr uint8)
}

View file

@ -2,21 +2,21 @@ package frame
import (
"errors"
"git.gammaspectra.live/S.O.N.G/Ignite/colorspace"
"git.gammaspectra.live/S.O.N.G/Ignite/colorformat"
"runtime"
"unsafe"
)
type uint16Frame struct {
colorSpace colorspace.ColorSpace
width int
height int
Y []uint16
Cb []uint16
Cr []uint16
colorFormat colorformat.ColorFormat
width int
height int
Y []uint16
Cb []uint16
Cr []uint16
}
func NewUint16FrameFromBytes(space colorspace.ColorSpace, width, height int, data []byte) (*uint16Frame, error) {
func NewUint16FrameFromBytes(space colorformat.ColorFormat, width, height int, data []byte) (*uint16Frame, error) {
if frameLength, _ := space.FrameSize(width, height); frameLength != len(data) {
return nil, errors.New("wrong length of data")
}
@ -34,25 +34,25 @@ func NewUint16FrameFromBytes(space colorspace.ColorSpace, width, height int, dat
iCr := space.PlaneCrSamples(width, height)
return &uint16Frame{
colorSpace: space,
height: height,
width: width,
Y: buf[:iY],
Cb: buf[iY : iY+iCb],
Cr: buf[iY+iCb : iY+iCb+iCr],
colorFormat: space,
height: height,
width: width,
Y: buf[:iY],
Cb: buf[iY : iY+iCb],
Cr: buf[iY+iCb : iY+iCb+iCr],
}, nil
}
func (i *uint16Frame) Get16(x, y int) (Y uint16, Cb uint16, Cr uint16) {
cy, cb, cr := i.GetNative(x, y)
return cy << (16 - i.colorSpace.BitDepth), cb << (16 - i.colorSpace.BitDepth), cr << (16 - i.colorSpace.BitDepth)
return cy << (16 - i.colorFormat.BitDepth), cb << (16 - i.colorFormat.BitDepth), cr << (16 - i.colorFormat.BitDepth)
}
func (i *uint16Frame) Get8(x, y int) (Y uint8, Cb uint8, Cr uint8) {
cy, cb, cr := i.GetNative(x, y)
return uint8(cy >> (i.colorSpace.BitDepth - 8)), uint8(cb >> (i.colorSpace.BitDepth - 8)), uint8(cr >> (i.colorSpace.BitDepth - 8))
return uint8(cy >> (i.colorFormat.BitDepth - 8)), uint8(cb >> (i.colorFormat.BitDepth - 8)), uint8(cr >> (i.colorFormat.BitDepth - 8))
}
func (i *uint16Frame) Width() int {
@ -63,18 +63,18 @@ func (i *uint16Frame) Height() int {
return i.height
}
func (i *uint16Frame) ColorSpace() colorspace.ColorSpace {
return i.colorSpace
func (i *uint16Frame) ColorFormat() colorformat.ColorFormat {
return i.colorFormat
}
func (i *uint16Frame) GetNative(x, y int) (Y uint16, Cb uint16, Cr uint16) {
Yindex := x + y*i.width
Cwidth := (i.width * int(i.colorSpace.Subsampling.A)) / int(i.colorSpace.Subsampling.J)
if i.colorSpace.Subsampling.B == 0 {
Cwidth := (i.width * int(i.colorFormat.Subsampling.A)) / int(i.colorFormat.Subsampling.J)
if i.colorFormat.Subsampling.B == 0 {
y /= 2
}
Cindex := (x*int(i.colorSpace.Subsampling.A))/int(i.colorSpace.Subsampling.J) + y*Cwidth
Cindex := (x*int(i.colorFormat.Subsampling.A))/int(i.colorFormat.Subsampling.J) + y*Cwidth
Y = i.Y[Yindex]
Cb = i.Cb[Cindex]
Cr = i.Cr[Cindex]

View file

@ -2,19 +2,19 @@ package frame
import (
"errors"
"git.gammaspectra.live/S.O.N.G/Ignite/colorspace"
"git.gammaspectra.live/S.O.N.G/Ignite/colorformat"
)
type uint8Frame struct {
colorSpace colorspace.ColorSpace
width int
height int
Y []uint8
Cb []uint8
Cr []uint8
colorFormat colorformat.ColorFormat
width int
height int
Y []uint8
Cb []uint8
Cr []uint8
}
func NewUint8FrameFromBytes(space colorspace.ColorSpace, width, height int, data []byte) (*uint8Frame, error) {
func NewUint8FrameFromBytes(space colorformat.ColorFormat, width, height int, data []byte) (*uint8Frame, error) {
if frameLength, _ := space.FrameSize(width, height); frameLength != len(data) {
return nil, errors.New("wrong length of data")
}
@ -28,19 +28,19 @@ func NewUint8FrameFromBytes(space colorspace.ColorSpace, width, height int, data
iCr := space.PlaneCrSamples(width, height)
return &uint8Frame{
colorSpace: space,
height: height,
width: width,
Y: data[:iY],
Cb: data[iY : iY+iCb],
Cr: data[iY+iCb : iY+iCb+iCr],
colorFormat: space,
height: height,
width: width,
Y: data[:iY],
Cb: data[iY : iY+iCb],
Cr: data[iY+iCb : iY+iCb+iCr],
}, nil
}
func (i *uint8Frame) Get16(x, y int) (Y uint16, Cb uint16, Cr uint16) {
cy, cb, cr := i.GetNative(x, y)
return uint16(cy) << (16 - i.colorSpace.BitDepth), uint16(cb) << (16 - i.colorSpace.BitDepth), uint16(cr) << (16 - i.colorSpace.BitDepth)
return uint16(cy) << (16 - i.colorFormat.BitDepth), uint16(cb) << (16 - i.colorFormat.BitDepth), uint16(cr) << (16 - i.colorFormat.BitDepth)
}
func (i *uint8Frame) Get8(x, y int) (Y uint8, Cb uint8, Cr uint8) {
@ -55,18 +55,18 @@ func (i *uint8Frame) Height() int {
return i.height
}
func (i *uint8Frame) ColorSpace() colorspace.ColorSpace {
return i.colorSpace
func (i *uint8Frame) ColorFormat() colorformat.ColorFormat {
return i.colorFormat
}
func (i *uint8Frame) GetNative(x, y int) (Y uint8, Cb uint8, Cr uint8) {
Yindex := x + y*i.width
Cwidth := (i.width * int(i.colorSpace.Subsampling.A)) / int(i.colorSpace.Subsampling.J)
if i.colorSpace.Subsampling.B == 0 {
Cwidth := (i.width * int(i.colorFormat.Subsampling.A)) / int(i.colorFormat.Subsampling.J)
if i.colorFormat.Subsampling.B == 0 {
y /= 2
}
Cindex := (x*int(i.colorSpace.Subsampling.A))/int(i.colorSpace.Subsampling.J) + y*Cwidth
Cindex := (x*int(i.colorFormat.Subsampling.A))/int(i.colorFormat.Subsampling.J) + y*Cwidth
Y = i.Y[Yindex]
Cb = i.Cb[Cindex]
Cr = i.Cr[Cindex]

View file

@ -3,7 +3,7 @@ package y4m
import (
"errors"
"fmt"
"git.gammaspectra.live/S.O.N.G/Ignite/colorspace"
"git.gammaspectra.live/S.O.N.G/Ignite/colorformat"
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
"git.gammaspectra.live/S.O.N.G/Ignite/utilities"
"io"
@ -20,7 +20,7 @@ type Stream struct {
height int
frameRate utilities.Ratio
pixelAspectRatio utilities.Ratio
colorSpace colorspace.ColorSpace
colorFormat colorformat.ColorFormat
colorRangeFull bool
frameSize int
@ -36,7 +36,7 @@ const (
ParameterFrameRate Parameter = 'F'
ParameterInterlacing Parameter = 'I'
ParameterPixelAspectRatio Parameter = 'A'
ParameterColorSpace Parameter = 'C'
ParameterColorFormat Parameter = 'C'
ParameterExtension Parameter = 'X'
)
@ -68,8 +68,8 @@ func (s *Stream) FrameRate() utilities.Ratio {
return s.frameRate
}
func (s *Stream) ColorSpace() colorspace.ColorSpace {
return s.colorSpace
func (s *Stream) ColorFormat() colorformat.ColorFormat {
return s.colorFormat
}
func (s *Stream) ColorRange() bool {
@ -125,12 +125,12 @@ func (s *Stream) GetFrame() (frameNumber int, parameters map[Parameter][]string,
return 0, nil, nil, err
}
if s.colorSpace.BitDepth > 8 {
if frameObject, err = frame.NewUint16FrameFromBytes(s.colorSpace, s.width, s.height, buf); err != nil {
if s.colorFormat.BitDepth > 8 {
if frameObject, err = frame.NewUint16FrameFromBytes(s.colorFormat, s.width, s.height, buf); err != nil {
return 0, nil, nil, err
}
} else {
if frameObject, err = frame.NewUint8FrameFromBytes(s.colorSpace, s.width, s.height, buf); err != nil {
if frameObject, err = frame.NewUint8FrameFromBytes(s.colorFormat, s.width, s.height, buf); err != nil {
return 0, nil, nil, err
}
}
@ -260,8 +260,8 @@ func (s *Stream) parseParameters() (err error) {
if s.pixelAspectRatio.Denominator, err = strconv.Atoi(v[1]); err != nil {
return err
}
case ParameterColorSpace:
if s.colorSpace, err = colorspace.NewColorSpaceFromString(values[0]); err != nil {
case ParameterColorFormat:
if s.colorFormat, err = colorformat.NewColorFormatFromString(values[0]); err != nil {
return err
}
case ParameterExtension:
@ -283,9 +283,9 @@ func (s *Stream) parseParameters() (err error) {
}
}
//TODO: check for missing values width, height, colorspace etc.
//TODO: check for missing values width, height, colorformat etc.
s.frameSize, err = s.colorSpace.FrameSize(s.width, s.height)
s.frameSize, err = s.colorFormat.FrameSize(s.width, s.height)
return err
}