Cleanup and add samples for tests, decode .y4m.xz streams
This commit is contained in:
parent
0c4167a1f5
commit
120df4a734
|
@ -1,3 +1,4 @@
|
|||
testdata/*.ivf
|
||||
testdata/*.y4m
|
||||
testdata/*.y4m.xz
|
||||
testdata/testoutput
|
29
README.md
29
README.md
|
@ -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.
|
||||
|
|
|
@ -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" {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
1
go.mod
|
@ -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
2
go.sum
|
@ -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
1
testdata/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
*.y4m
|
||||
*.y4m.xz
|
||||
*.ivf
|
14
testdata/prepare.sh
vendored
14
testdata/prepare.sh
vendored
|
@ -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
84
testdata/testdata.go
vendored
|
@ -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"),
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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
39
utilities/settings.go
Normal 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")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue