Cleanup and add samples for tests, decode .y4m.xz streams

This commit is contained in:
DataHoarder 2023-08-10 12:44:17 +02:00
parent 0c4167a1f5
commit 120df4a734
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
16 changed files with 458 additions and 60 deletions

View file

@ -1,3 +1,4 @@
testdata/*.ivf
testdata/*.y4m
testdata/*.y4m.xz
testdata/testoutput

View file

@ -1,10 +1,35 @@
# Supported
* y4m pipes
* 4:4:4, 4:2:0, and probably 4:2:2 and 4:0:0.
* 8, 10, 12 bit depth. Probably 14 and 16 as well.
* Frame tested support for 4:4:4, 4:2:2, 4:2:0. Probably 4:0:0 as well, untested.
* Frame tested support for 8, 10, 12 bit depth. Probably 14 and 16 as well, untested.
* VMAF tools
* IVF reader
* Frameserver
* TODO: make list per encoder and decoder.
## Bitdepth / subsampling Frame support matrix
| Depth/Sampling | 4:0:0 | 4:2:0 | 4:2:2 | 4:4:4 |
|:--------------:|:-----:|:-----:|:-----:|:-----:|
| 8-bit | ⚠️ | ✅ | ✅ | ✅ |
| 10-bit | ⚠️ | ✅ | ⚠️ | ⚠️ |
| 12-bit | ⚠️ | ⚠️ | ⚠️ | ✅ |
| 14-bit | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
| 16-bit | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
Legend: ✅ = supported, tested; ️⚠️ = supported, untested; ❌ = unsupported
## Formats supported
| Format | Decoder | Encoder | Notes |
|:-------------:|:-------:|:-------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **YUV4MPEG2** | ✅ | ❌ | Supports most bitdepth and chroma subsampling. Library limited, not format limited.</br>Decoding via [S.O.N.G/Ignite](https://git.gammaspectra.live/S.O.N.G/Ignite) |
| **H.264** | ❌ | ✅ | Supports 8-bit and 10-bit; 4:0:0, 4:2:0, 4:2:2, 4:4:4 chroma subsampling.</br>Encoding via [x264](https://code.videolan.org/videolan/x264) into .h264 bitstream. |
| **H.265** | ❌ | ❌ | |
| **VP9** | ❌ | ❌ | |
| **AV1** | ✅ | ✅ | Supports 8-bit, 10-bit and 12-bit; 4:0:0, 4:2:0, 4:2:2, 4:4:4 chroma subsampling.</br>Decoding via [dav1d](https://code.videolan.org/videolan/dav1d) from .ivf bitstream</br>Encoding via [libaom-av1](https://aomedia.googlesource.com/aom) into .ivf bitstream. |
# TODO
* No SAR/PAR handling.
* No color primary / transfer / matrix coefficients handling.

View file

@ -81,6 +81,14 @@ func (c Space) check() error {
return nil
}
func MustColorFormatFromString(colorFormat string) Space {
s, err := NewColorFormatFromString(colorFormat)
if err != nil {
panic(err)
}
return s
}
func NewColorFormatFromString(colorFormat string) (Space, error) {
colorFormat = strings.ToLower(colorFormat)
if colorFormat == "420paldv" {

View file

@ -3,7 +3,10 @@
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"
)
@ -12,28 +15,77 @@ func TestVersion(t *testing.T) {
t.Logf("dav1d version: %s", Version())
}
func TestDecodeYUV420_8bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode")
}
f, err := os.Open(testdata.AV1_Sintel_Trailer_720p24_YUV420_8bit_Low)
if err != nil {
t.Fatal(err)
}
defer f.Close()
func testDecode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if decoder, err := NewDecoder(f, nil); err != nil {
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
}
if decoder, err := NewDecoder(reader, nil); err != nil {
t.Fatal(err)
} else {
defer decoder.Close()
decoded := 0
for range decoder.DecodeStream().Channel() {
var frameProperties frame.Properties
for decodedFrame := range decoder.DecodeStream().Channel() {
if decoded == 0 {
frameProperties = decodedFrame.Properties()
}
//ingest
decoded++
if decoded%50 == 0 {
t.Logf("%d/%d", decoded, sample.Frames)
}
}
if decoded != 1253 {
t.Fatalf("expected %d frames, got %d", 1253, decoded)
if decoded != sample.Frames {
t.Fatalf("expected %d frames, got %d", sample.Frames, decoded)
}
if frameProperties.Width != sample.Width {
t.Fatalf("expected %d width, got %d", sample.Width, frameProperties.Width)
}
if frameProperties.Height != sample.Height {
t.Fatalf("expected %d height, got %d", sample.Height, frameProperties.Height)
}
if frameProperties.ColorSpace.String() != sample.ColorSpace.String() {
t.Fatalf("expected %s color space, got %s", sample.ColorSpace.String(), frameProperties.ColorSpace.String())
}
}
}
func TestDecode_YUV420_8bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode")
}
testDecode(testdata.AV1_Sintel_Trailer_720p24_YUV420_8bit_Low, t)
}
func TestDecode_YUV444_12bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode")
}
testDecode(testdata.AV1_Netflix_Sol_Levante_2160p24_YUV444_12bit_Lossy, t)
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"git.gammaspectra.live/S.O.N.G/Ignite/color"
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
"github.com/ulikunitz/xz"
"io"
"runtime"
"strconv"
@ -43,6 +44,14 @@ const (
const fileMagic = "YUV4MPEG2 "
const frameMagic = "FRAME"
func NewXZCompressedDecoder(reader io.Reader, settings map[string]any) (*Decoder, error) {
r, err := xz.NewReader(reader)
if err != nil {
return nil, err
}
return NewDecoder(r, settings)
}
func NewDecoder(reader io.Reader, settings map[string]any) (*Decoder, error) {
s := &Decoder{
r: reader,

View file

@ -1,30 +1,100 @@
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 TestDecodeYUV420_8bit(t *testing.T) {
f, err := os.Open(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit)
if err != nil {
t.Fatal(err)
}
defer f.Close()
func testDecode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if y4m, err := NewDecoder(f, nil); err != nil {
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
}
var y4m *Decoder
switch sample.Type {
case "y4m":
y4m, err = NewDecoder(reader, nil)
case "y4m.xz":
y4m, err = NewXZCompressedDecoder(reader, nil)
default:
t.Fatal("unsupported sample type")
}
if err != nil {
t.Fatal(err)
} else {
defer y4m.Close()
decoded := 0
for range y4m.DecodeStream().Channel() {
var frameProperties frame.Properties
for decodedFrame := range y4m.DecodeStream().Channel() {
if decoded == 0 {
frameProperties = decodedFrame.Properties()
}
//ingest
decoded++
if decoded%50 == 0 {
t.Logf("%d/%d", decoded, sample.Frames)
}
}
if decoded != 1253 {
t.Fatalf("expected %d frames, got %d", 1253, decoded)
if decoded != sample.Frames {
t.Fatalf("expected %d frames, got %d", sample.Frames, decoded)
}
if frameProperties.Width != sample.Width {
t.Fatalf("expected %d width, got %d", sample.Width, frameProperties.Width)
}
if frameProperties.Height != sample.Height {
t.Fatalf("expected %d height, got %d", sample.Height, frameProperties.Height)
}
if frameProperties.ColorSpace.String() != sample.ColorSpace.String() {
t.Fatalf("expected %s color space, got %s", sample.ColorSpace.String(), frameProperties.ColorSpace.String())
}
}
}
func TestDecode_YUV420_720p24_8bit(t *testing.T) {
testDecode(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit, t)
}
func TestDecode_YUV444_720p50_8bit(t *testing.T) {
testDecode(testdata.Y4M_Ducks_Take_Off_720p50_YUV444_8bit, t)
}
func TestDecode_YUV422_720p50_8bit(t *testing.T) {
testDecode(testdata.Y4M_Ducks_Take_Off_720p50_YUV422_8bit, t)
}
func TestDecode_YUV420_2160p60_10bit(t *testing.T) {
testDecode(testdata.Y4M_Netflix_FoodMarket_2160p60_YUV420_10bit, t)
}
func TestDecode_YUV420_360p24_8bit_xz(t *testing.T) {
testDecode(testdata.Y4M_Big_Buck_Bunny_360p24_YUV420_8bit, t)
}

View file

@ -5,6 +5,8 @@ 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"
@ -15,20 +17,45 @@ func TestVersion(t *testing.T) {
t.Logf("libaom version: %s", Version())
}
func TestEncode(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode")
}
f, err := os.Open(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit)
if err != nil {
t.Fatal(err)
}
defer f.Close()
func testEncode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if pipe, err := y4m.NewDecoder(f, nil); err != nil {
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
}
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_*.ivf")
if err != nil {
t.Fatal(err)
@ -51,7 +78,7 @@ func TestEncode(t *testing.T) {
settings["frame-parallel"] = 1
settings["lag-in-frames"] = 2
settings["tile-columns"] = 1
settings["tile-rows"] = 1
settings["tile-rows"] = 4
if encoder, err := NewEncoder(target, stream.Properties(), settings); err != nil {
t.Fatal(err)
@ -65,7 +92,7 @@ func TestEncode(t *testing.T) {
defer wg.Done()
for range s[0].Channel() {
if encoded%10 == 0 {
t.Logf("frame %d/1253", encoded)
t.Logf("frame %d/%d", encoded, sample.Frames)
}
encoded++
}
@ -77,9 +104,17 @@ func TestEncode(t *testing.T) {
wg.Wait()
if encoded != 1253 {
t.Fatalf("expected %d frames, got %d", 1253, encoded)
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 test in short mode")
}
testEncode(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit, t)
}

View file

@ -5,6 +5,8 @@ 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"
@ -15,20 +17,45 @@ func TestVersion(t *testing.T) {
t.Logf("libx264 version: %s", Version())
}
func TestEncode(t *testing.T) {
if testing.Short() {
t.Skip("skipping encode test in short mode")
}
f, err := os.Open(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit)
if err != nil {
t.Fatal(err)
}
defer f.Close()
func testEncode(sample testdata.TestSample, t *testing.T) {
var reader io.Reader
var err error
if pipe, err := y4m.NewDecoder(f, nil); err != nil {
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
}
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)
@ -46,7 +73,17 @@ func TestEncode(t *testing.T) {
settings := make(map[string]any)
settings["threads"] = runtime.NumCPU()
settings["preset"] = "fast"
settings["profile"] = "high"
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)
@ -60,7 +97,7 @@ func TestEncode(t *testing.T) {
defer wg.Done()
for range s[0].Channel() {
if encoded%10 == 0 {
t.Logf("frame %d/1253", encoded)
t.Logf("frame %d/%d", encoded, sample.Frames)
}
encoded++
}
@ -72,9 +109,33 @@ func TestEncode(t *testing.T) {
wg.Wait()
if encoded != 1253 {
t.Fatalf("expected %d frames, got %d", 1253, encoded)
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")
}
testEncode(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit, t)
}
func TestEncode_YUV422_8bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping encode test in short mode")
}
testEncode(testdata.Y4M_Ducks_Take_Off_720p50_YUV422_8bit, t)
}
func TestEncode_YUV444_8bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping encode test in short mode")
}
testEncode(testdata.Y4M_Ducks_Take_Off_720p50_YUV444_8bit, t)
}

View file

@ -13,12 +13,18 @@ type Frame interface {
Properties() Properties
// PTS usually frame number
PTS() int64
// Get16 get a pixel sample in 16-bit depth
Get16(x, y int) (Y uint16, Cb uint16, Cr uint16)
// Get8 get a pixel sample in 8-bit depth
Get8(x, y int) (Y uint8, Cb uint8, Cr uint8)
}
type TypedFrame[T AllowedFrameTypes] interface {
Frame
// GetNative get a pixel sample in native bit depth
GetNative(x, y int) (Y T, Cb T, Cr T)
// GetNativeLuma also known as Y. Do not keep references to this slice, copy instead.

1
go.mod
View file

@ -4,6 +4,7 @@ go 1.21
require (
github.com/stretchr/testify v1.8.1
github.com/ulikunitz/xz v0.5.11
golang.org/x/exp v0.0.0-20230807204917-050eac23e9de
)

2
go.sum
View file

@ -10,6 +10,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
golang.org/x/exp v0.0.0-20230807204917-050eac23e9de h1:l5Za6utMv/HsBWWqzt4S8X17j+kt1uVETUX5UFhn2rE=
golang.org/x/exp v0.0.0-20230807204917-050eac23e9de/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

1
testdata/.gitignore vendored
View file

@ -1,2 +1,3 @@
*.y4m
*.y4m.xz
*.ivf

14
testdata/prepare.sh vendored
View file

@ -2,12 +2,22 @@
pushd "${0%/*}" || exit
# Samples taken from https://media.xiph.org/
if [[ ! -f "sintel_trailer_2k_720p24.y4m" ]]; then
wget --show-progress -O "sintel_trailer_2k_720p24.y4m" https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/sintel_trailer_2k_720p24.y4m
fi
if [[ ! -f "ducks_take_off_422_720p50.y4m" ]]; then
wget --show-progress -O "ducks_take_off_422_720p50.y4m" https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/ducks_take_off_422_720p50.y4m
fi
if [[ ! -f "ducks_take_off_444_720p50.y4m" ]]; then
wget --show-progress -O "ducks_take_off_444_720p50.y4m" https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/ducks_take_off_444_720p50.y4m
fi
if [[ ! -f "netflix_sol_levante_2160p24_12bit_av1_lossy.ivf" ]]; then
wget --show-progress -O "sintel_trailer_2k_720p24_av1_low.ivf" https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/netflix_sol_levante_2160p24_12bit_av1_lossy.ivf
fi
if [[ ! -f "sintel_trailer_2k_720p24_av1_low.ivf" ]]; then
wget --show-progress -O "sintel_trailer_2k_720p24_av1_low.ivf" https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/sintel_trailer_2k_720p24_av1_low.ivf
fi

84
testdata/testdata.go vendored
View file

@ -1,6 +1,7 @@
package testdata
import (
"git.gammaspectra.live/S.O.N.G/Ignite/color"
"os"
"path"
"runtime"
@ -16,7 +17,84 @@ func init() {
}
}
const (
Y4M_Sintel_Trailer_720p24_YUV420_8bit = "testdata/sintel_trailer_2k_720p24.y4m"
AV1_Sintel_Trailer_720p24_YUV420_8bit_Low = "testdata/sintel_trailer_2k_720p24_av1_low.ivf"
type TestSample struct {
Path string
Url string
Type string
Width, Height int
Frames int
ColorSpace color.Space
SkipNotFound bool
}
var (
Y4M_Sintel_Trailer_720p24_YUV420_8bit = TestSample{
Path: "testdata/sintel_trailer_2k_720p24.y4m",
// https://media.xiph.org/video/derf/y4m/sintel_trailer_2k_720p24.y4m
Url: "https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/sintel_trailer_2k_720p24.y4m",
Type: "y4m",
Width: 1280,
Height: 720,
Frames: 1253,
ColorSpace: color.MustColorFormatFromString("420jpeg"),
}
Y4M_Big_Buck_Bunny_360p24_YUV420_8bit = TestSample{
Path: "testdata/big_buck_bunny_360p24.y4m.xz",
Url: "https://media.xiph.org/video/derf/y4m/big_buck_bunny_360p24.y4m.xz",
Type: "y4m.xz",
Width: 640,
Height: 360,
Frames: 14315,
ColorSpace: color.MustColorFormatFromString("420jpeg"),
SkipNotFound: true,
}
Y4M_Ducks_Take_Off_720p50_YUV444_8bit = TestSample{
Path: "testdata/ducks_take_off_444_720p50.y4m",
// https://media.xiph.org/video/derf/y4m/ducks_take_off_444_720p50.y4m
Url: "https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/ducks_take_off_444_720p50.y4m",
Type: "y4m",
Width: 1280,
Height: 720,
Frames: 500,
ColorSpace: color.MustColorFormatFromString("444p8"),
}
Y4M_Ducks_Take_Off_720p50_YUV422_8bit = TestSample{
Path: "testdata/ducks_take_off_422_720p50.y4m",
// https://media.xiph.org/video/derf/y4m/ducks_take_off_422_720p50.y4m
Url: "https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/ducks_take_off_422_720p50.y4m",
Type: "y4m",
Width: 1280,
Height: 720,
Frames: 500,
ColorSpace: color.MustColorFormatFromString("422p8"),
}
Y4M_Netflix_FoodMarket_2160p60_YUV420_10bit = TestSample{
Path: "testdata/Netflix_FoodMarket_4096x2160_60fps_10bit_420.y4m",
Url: "https://media.xiph.org/video/derf/ElFuente/Netflix_FoodMarket_4096x2160_60fps_10bit_420.y4m",
Type: "y4m",
Width: 4096,
Height: 2160,
Frames: 600,
ColorSpace: color.MustColorFormatFromString("420p10"),
SkipNotFound: true,
}
AV1_Sintel_Trailer_720p24_YUV420_8bit_Low = TestSample{
Path: "testdata/sintel_trailer_2k_720p24_av1_low.ivf",
Url: "https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/sintel_trailer_2k_720p24_av1_low.ivf",
Type: "ivf",
Width: 1280,
Height: 720,
Frames: 1253,
ColorSpace: color.MustColorFormatFromString("420jpeg"),
}
AV1_Netflix_Sol_Levante_2160p24_YUV444_12bit_Lossy = TestSample{
Path: "testdata/netflix_sol_levante_2160p24_12bit_av1_lossy.ivf",
Url: "https://git.gammaspectra.live/S.O.N.G/Video-Samples/media/branch/master/netflix_sol_levante_2160p24_12bit_av1_lossy.ivf",
Type: "ivf",
Width: 3840,
Height: 2160,
Frames: 6313,
ColorSpace: color.MustColorFormatFromString("444p12"),
}
)

View file

@ -19,12 +19,12 @@ func TestVMAFYUV420_8bit(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode")
}
referenceFile, err := os.Open(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit)
referenceFile, err := os.Open(testdata.Y4M_Sintel_Trailer_720p24_YUV420_8bit.Path)
if err != nil {
t.Fatal(err)
}
defer referenceFile.Close()
distortedFile, err := os.Open(testdata.AV1_Sintel_Trailer_720p24_YUV420_8bit_Low)
distortedFile, err := os.Open(testdata.AV1_Sintel_Trailer_720p24_YUV420_8bit_Low.Path)
if err != nil {
t.Fatal(err)
}

39
utilities/settings.go Normal file
View file

@ -0,0 +1,39 @@
package utilities
import (
"strconv"
)
func GetSettingString(m map[string]any, name string, fallback string) string {
v, ok := m[name]
if !ok {
return fallback
}
switch val := v.(type) {
case string:
return val
case bool:
if val {
return "1"
} else {
return "0"
}
case int:
return strconv.FormatInt(int64(val), 10)
case int64:
return strconv.FormatInt(val, 10)
case uint:
return strconv.FormatUint(uint64(val), 10)
case uint64:
return strconv.FormatUint(val, 10)
case float32:
return strconv.FormatFloat(float64(val), 'f', -1, 64)
case float64:
return strconv.FormatFloat(val, 'f', -1, 64)
default:
panic("unknown type")
}
}