Test monochrome encoding

This commit is contained in:
DataHoarder 2023-08-10 19:01:39 +02:00
parent 4617d8eb53
commit 194149963d
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
8 changed files with 200 additions and 96 deletions

View file

@ -12,13 +12,21 @@
| Depth/Sampling | 4:0:0 | 4:2:0 | 4:2:2 | 4:4:4 |
|:--------------:|:-----:|:-----:|:-----:|:-----:|
| 8-bit | ⚠️ | ✅ | ✅ | ✅ |
| 10-bit | ⚠️ | ✅ | ⚠️ | ⚠️ |
| 8-bit | | ✅ | ✅ | ✅ |
| 10-bit | | ✅ | ⚠️ | ⚠️ |
| 12-bit | ⚠️ | ⚠️ | ⚠️ | ✅ |
| 14-bit | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
| 16-bit | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
| 14-bit | ❔ | ❔ | ❔ | ❔ |
| 16-bit | ❔ | ❔ | ❔ | ❔ |
Legend: ✅ = supported, tested; ️⚠️ = supported, untested; ❌ = unsupported
Legend:
✅ = supported, tested regularly
⚠️ = supported, tested sparsely/manually
❔ = probably supported, not tested
❌ = unsupported
## Formats supported

View file

@ -222,7 +222,6 @@ func (d *Decoder) pictureToFrame() (frame.Frame, error) {
if d.picture.p.layout != C.DAV1D_PIXEL_LAYOUT_I400 {
uData = unsafe.Slice((*byte)(d.picture.data[planeU]), chromaHeight*chromaWidth*2)
vData = unsafe.Slice((*byte)(d.picture.data[planeV]), chromaHeight*chromaWidth*2)
}
n := len(yData) + len(uData) + len(vData)

View file

@ -5,9 +5,6 @@ package libdav1d
import (
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
"git.gammaspectra.live/S.O.N.G/Ignite/testdata"
"io"
"net/http"
"os"
"testing"
)
@ -16,27 +13,11 @@ func TestVersion(t *testing.T) {
}
func testDecode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if _, err = os.Stat(sample.Path); err != nil {
if sample.SkipNotFound || sample.Url == "" {
t.Skip("skipping without sample")
}
response, err := http.DefaultClient.Get(sample.Url)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
reader = response.Body
} else {
f, err := os.Open(sample.Path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
reader = f
reader, err := sample.Open(t)
if err != nil {
t.Fatal(err)
}
defer reader.Close()
if decoder, err := NewDecoder(reader, nil); err != nil {
t.Fatal(err)

View file

@ -3,34 +3,15 @@ package y4m
import (
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
"git.gammaspectra.live/S.O.N.G/Ignite/testdata"
"io"
"net/http"
"os"
"testing"
)
func testDecode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if _, err = os.Stat(sample.Path); err != nil {
if sample.SkipNotFound || sample.Url == "" {
t.Skip("skipping without sample")
}
response, err := http.DefaultClient.Get(sample.Url)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
reader = response.Body
} else {
f, err := os.Open(sample.Path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
reader = f
reader, err := sample.Open(t)
if err != nil {
t.Fatal(err)
}
defer reader.Close()
var y4m *Decoder

View file

@ -5,8 +5,6 @@ package libaom
import (
"git.gammaspectra.live/S.O.N.G/Ignite/decoder/y4m"
"git.gammaspectra.live/S.O.N.G/Ignite/testdata"
"io"
"net/http"
"os"
"runtime"
"sync"
@ -18,27 +16,11 @@ func TestVersion(t *testing.T) {
}
func testEncode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if _, err = os.Stat(sample.Path); err != nil {
if sample.SkipNotFound || sample.Url == "" {
t.Skip("skipping without sample")
}
response, err := http.DefaultClient.Get(sample.Url)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
reader = response.Body
} else {
f, err := os.Open(sample.Path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
reader = f
reader, err := sample.Open(t)
if err != nil {
t.Fatal(err)
}
defer reader.Close()
var pipe *y4m.Decoder

View file

@ -5,8 +5,6 @@ package libx264
import (
"git.gammaspectra.live/S.O.N.G/Ignite/decoder/y4m"
"git.gammaspectra.live/S.O.N.G/Ignite/testdata"
"io"
"net/http"
"os"
"runtime"
"sync"
@ -18,27 +16,11 @@ func TestVersion(t *testing.T) {
}
func testEncode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if _, err = os.Stat(sample.Path); err != nil {
if sample.SkipNotFound || sample.Url == "" {
t.Skip("skipping without sample")
}
response, err := http.DefaultClient.Get(sample.Url)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
reader = response.Body
} else {
f, err := os.Open(sample.Path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
reader = f
reader, err := sample.Open(t)
if err != nil {
t.Fatal(err)
}
defer reader.Close()
var pipe *y4m.Decoder
@ -116,6 +98,89 @@ func testEncode(sample testdata.TestSample, t *testing.T) {
}
}
func testEncodeMono(sample testdata.TestSample, t *testing.T) {
reader, err := sample.Open(t)
if err != nil {
t.Fatal(err)
}
defer reader.Close()
var pipe *y4m.Decoder
switch sample.Type {
case "y4m":
pipe, err = y4m.NewDecoder(reader, nil)
case "y4m.xz":
pipe, err = y4m.NewXZCompressedDecoder(reader, nil)
default:
t.Fatal("unsupported sample type")
}
if err != nil {
t.Fatal(err)
} else {
defer pipe.Close()
target, err := os.CreateTemp("", "encode_test_*.h264")
if err != nil {
t.Fatal(err)
return
}
defer func() {
name := target.Name()
target.Close()
os.Remove(name)
}()
stream := pipe.DecodeStream().Monochrome()
settings := make(map[string]any)
settings["threads"] = runtime.NumCPU()
settings["preset"] = "fast"
settings["log"] = LogLevelInfo
if sample.ColorSpace.ChromaSampling.J == 4 && sample.ColorSpace.ChromaSampling.A == 4 && sample.ColorSpace.ChromaSampling.B == 4 {
settings["profile"] = "high444"
} else if sample.ColorSpace.ChromaSampling.J == 4 && sample.ColorSpace.ChromaSampling.A == 2 && sample.ColorSpace.ChromaSampling.B == 2 {
settings["profile"] = "high422"
} else if sample.ColorSpace.BitDepth > 8 {
settings["profile"] = "high10"
} else {
settings["profile"] = "high"
}
if encoder, err := NewEncoder(target, stream.Properties(), settings); err != nil {
t.Fatal(err)
} else {
defer encoder.Close()
s := stream.Copy(2)
encoded := 0
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for range s[0].Channel() {
if encoded%10 == 0 {
t.Logf("frame %d/%d", encoded, sample.Frames)
}
encoded++
}
}()
if err = encoder.EncodeStream(s[1]); err != nil {
t.Fatal(err)
}
wg.Wait()
if encoded != sample.Frames {
t.Fatalf("expected %d frames, got %d", sample.Frames, encoded)
}
}
}
}
func TestEncode_YUV420_8bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping encode test in short mode")
@ -139,3 +204,19 @@ func TestEncode_YUV444_8bit(t *testing.T) {
testEncode(testdata.Y4M_Ducks_Take_Off_720p50_YUV444_8bit, t)
}
func TestEncode_YUV400_8bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping encode test in short mode")
}
testEncodeMono(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit, t)
}
func TestEncode_YUV400_10bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping encode test in short mode")
}
testEncodeMono(testdata.Y4M_Netflix_FoodMarket_2160p60_YUV420_10bit, t)
}

View file

@ -190,3 +190,48 @@ func (s *Stream) Sample(each int) *Stream {
return slice
}
// Monochrome makes stream luma-only
func (s *Stream) Monochrome() *Stream {
if !s.Lock() {
return nil
}
props := s.Properties()
props.ColorSpace.ChromaSampling.A = 0
props.ColorSpace.ChromaSampling.B = 0
slice, channel := NewStream(props)
go func() {
defer close(channel)
for f := range s.channel {
frameProps := f.Properties()
frameProps.ColorSpace.ChromaSampling.A = 0
frameProps.ColorSpace.ChromaSampling.B = 0
switch typedFrame := f.(type) {
case TypedFrame[uint8]:
channel <- &FrameUint8{
properties: frameProps,
Pts: typedFrame.PTS(),
Y: typedFrame.GetNativeLuma(),
Cb: nil,
Cr: nil,
}
case TypedFrame[uint16]:
channel <- &FrameUint16{
properties: frameProps,
Pts: typedFrame.PTS(),
Y: typedFrame.GetNativeLuma(),
Cb: nil,
Cr: nil,
}
default:
panic("unknown frame type")
}
}
}()
return slice
}

27
testdata/testdata.go vendored
View file

@ -2,9 +2,12 @@ package testdata
import (
"git.gammaspectra.live/S.O.N.G/Ignite/color"
"io"
"net/http"
"os"
"path"
"runtime"
"testing"
)
func init() {
@ -27,6 +30,30 @@ type TestSample struct {
SkipNotFound bool
}
func (sample *TestSample) Open(t *testing.T) (io.ReadCloser, error) {
var reader io.ReadCloser
var err error
if _, err = os.Stat(sample.Path); err != nil {
if sample.SkipNotFound || sample.Url == "" {
t.Skip("skipping without sample")
}
response, err := http.DefaultClient.Get(sample.Url)
if err != nil {
t.Fatal(err)
}
reader = response.Body
} else {
f, err := os.Open(sample.Path)
if err != nil {
t.Fatal(err)
}
reader = f
}
return reader, nil
}
var (
Y4M_Sintel_Trailer_720p24_YUV420_8bit = TestSample{
Path: "testdata/sintel_trailer_2k_720p24.y4m",