commit fc0693be1c3a437369b9c1ca153b3c9ed2aca689 Author: aler9 <46489434+aler9@users.noreply.github.com> Date: Sat Apr 1 10:51:06 2023 +0200 initial commit diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3938344 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/issue-lock.yml b/.github/workflows/issue-lock.yml new file mode 100644 index 0000000..4a95f38 --- /dev/null +++ b/.github/workflows/issue-lock.yml @@ -0,0 +1,50 @@ +name: issue-lock + +on: + schedule: + - cron: '40 15 * * *' + workflow_dispatch: + +jobs: + issue-lock: + runs-on: ubuntu-latest + + steps: + - uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { repo: { owner, repo } } = context; + + const now = new Date(); + + for await (const res of github.paginate.iterator( + github.rest.issues.listForRepo, { + owner, + repo, + state: 'closed', + })) { + for (const issue of res.data) { + if (issue.locked) { + continue; + } + + if ((now - new Date(issue.updated_at)) < 1000*60*60*24*31*6) { + continue; + } + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: issue.number, + body: 'This issue is being locked automatically because it has been closed for more than 6 months.\n' + + 'Please open a new issue in case you encounter a similar problem.', + }); + + github.rest.issues.lock({ + owner, + repo, + issue_number: issue.number, + }); + } + } diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..c875c13 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,36 @@ +name: lint + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + golangci-lint: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-go@v3 + with: + go-version: "1.19" + + - uses: golangci/golangci-lint-action@v3 + with: + version: v1.50.1 + + go-mod-tidy: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-go@v2 + with: + go-version: "1.20" + + - run: | + go mod tidy + git diff --exit-code diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..5f27757 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,30 @@ +name: test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-20.04 + strategy: + matrix: + go: ["1.18", "1.19", "1.20"] + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go }} + + - run: sudo apt update && sudo apt install -y libavformat-dev libswscale-dev + + - run: make test-nodocker + + - if: matrix.go == '1.19' + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1273da7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/coverage*.txt diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..45f0aaa --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,28 @@ +linters: + enable: + - bodyclose + - dupl + - exportloopref + - gochecknoinits + - gocritic + - gofmt + - gofumpt + - misspell + - lll + - prealloc + - revive + - unconvert + - whitespace + disable: + - errcheck + +issues: + exclude-use-default: false + +linters-settings: + govet: + enable-all: true + disable: + - fieldalignment + - reflectvaluecompare + - shadow diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e06e71e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 aler9 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..654d9fc --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +BASE_IMAGE = golang:1.20.1-alpine3.17 +LINT_IMAGE = golangci/golangci-lint:v1.50.1 + +.PHONY: $(shell ls) + +help: + @echo "usage: make [action]" + @echo "" + @echo "available actions:" + @echo "" + @echo " mod-tidy run go mod tidy" + @echo " format format source files" + @echo " test run tests" + @echo " test-highlevel run high-level tests" + @echo " lint run linter" + @echo " bench run benchmarks" + @echo "" + +blank := +define NL + +$(blank) +endef + +include scripts/*.mk diff --git a/README.md b/README.md new file mode 100644 index 0000000..b43da8e --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# mediabase + +[![Test](https://github.com/bluenviron/mediabase/workflows/test/badge.svg)](https://github.com/bluenviron/mediabase/actions?query=workflow:test) +[![Lint](https://github.com/bluenviron/mediabase/workflows/lint/badge.svg)](https://github.com/bluenviron/mediabase/actions?query=workflow:lint) +[![Go Report Card](https://goreportcard.com/badge/github.com/bluenviron/mediabase)](https://goreportcard.com/report/github.com/bluenviron/mediabase) +[![CodeCov](https://codecov.io/gh/bluenviron/mediabase/branch/main/graph/badge.svg)](https://app.codecov.io/gh/bluenviron/mediabase/branch/main) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/bluenviron/mediabase/v3)](https://pkg.go.dev/github.com/bluenviron/mediabase/v3#pkg-index) + +Definitions and functions shared between gortsplib, gohlslib and mediamtx. + +In particular: + +* [Codec definitions](pkg/codecs) +* [Codec utilities](pkg/codecs) +* [Format utilities](pkg/formats) +* [Bit reader and writer](pkg/bits) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..afc9099 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/bluenviron/mediabase + +go 1.18 + +require github.com/stretchr/testify v1.8.2 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6a56e69 --- /dev/null +++ b/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/bits/read.go b/pkg/bits/read.go new file mode 100644 index 0000000..6d925b4 --- /dev/null +++ b/pkg/bits/read.go @@ -0,0 +1,123 @@ +// Package bits contains functions to read/write bits from/to buffers. +package bits + +import ( + "fmt" +) + +// HasSpace checks whether buffer has space for N bits. +func HasSpace(buf []byte, pos int, n int) error { + if n > ((len(buf) * 8) - pos) { + return fmt.Errorf("not enough bits") + } + return nil +} + +// ReadBits reads N bits. +func ReadBits(buf []byte, pos *int, n int) (uint64, error) { + err := HasSpace(buf, *pos, n) + if err != nil { + return 0, err + } + + return ReadBitsUnsafe(buf, pos, n), nil +} + +// ReadBitsUnsafe reads N bits. +func ReadBitsUnsafe(buf []byte, pos *int, n int) uint64 { + v := uint64(0) + + res := 8 - (*pos & 0x07) + if n < res { + v := uint64((buf[*pos>>0x03] >> (res - n)) & (1<>0x03]&(1<= 8 { + v = (v << 8) | uint64(buf[*pos>>0x03]) + *pos += 8 + n -= 8 + } + + if n > 0 { + v = (v << n) | uint64(buf[*pos>>0x03]>>(8-n)) + *pos += n + } + + return v +} + +// ReadGolombUnsigned reads an unsigned golomb-encoded value. +func ReadGolombUnsigned(buf []byte, pos *int) (uint32, error) { + buflen := len(buf) + leadingZeroBits := uint32(0) + + for { + if (buflen*8 - *pos) == 0 { + return 0, fmt.Errorf("not enough bits") + } + + b := (buf[*pos>>0x03] >> (7 - (*pos & 0x07))) & 0x01 + *pos++ + if b != 0 { + break + } + + leadingZeroBits++ + if leadingZeroBits > 32 { + return 0, fmt.Errorf("invalid value") + } + } + + if (buflen*8 - *pos) < int(leadingZeroBits) { + return 0, fmt.Errorf("not enough bits") + } + + codeNum := uint32(0) + + for n := leadingZeroBits; n > 0; n-- { + b := (buf[*pos>>0x03] >> (7 - (*pos & 0x07))) & 0x01 + *pos++ + codeNum |= uint32(b) << (n - 1) + } + + codeNum = (1 << leadingZeroBits) - 1 + codeNum + + return codeNum, nil +} + +// ReadGolombSigned reads a signed golomb-encoded value. +func ReadGolombSigned(buf []byte, pos *int) (int32, error) { + v, err := ReadGolombUnsigned(buf, pos) + if err != nil { + return 0, err + } + + vi := int32(v) + if (vi & 0x01) != 0 { + return (vi + 1) / 2, nil + } + return -vi / 2, nil +} + +// ReadFlag reads a boolean flag. +func ReadFlag(buf []byte, pos *int) (bool, error) { + err := HasSpace(buf, *pos, 1) + if err != nil { + return false, err + } + + return ReadFlagUnsafe(buf, pos), nil +} + +// ReadFlagUnsafe reads a boolean flag. +func ReadFlagUnsafe(buf []byte, pos *int) bool { + b := (buf[*pos>>0x03] >> (7 - (*pos & 0x07))) & 0x01 + *pos++ + return b == 1 +} diff --git a/pkg/bits/read_test.go b/pkg/bits/read_test.go new file mode 100644 index 0000000..6a72c8a --- /dev/null +++ b/pkg/bits/read_test.go @@ -0,0 +1,88 @@ +package bits + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestReadBits(t *testing.T) { + buf := []byte{0xA8, 0xC7, 0xD6, 0xAA, 0xBB, 0x10} + pos := 0 + v, _ := ReadBits(buf, &pos, 6) + require.Equal(t, uint64(0x2a), v) + v, _ = ReadBits(buf, &pos, 6) + require.Equal(t, uint64(0x0c), v) + v, _ = ReadBits(buf, &pos, 6) + require.Equal(t, uint64(0x1f), v) + v, _ = ReadBits(buf, &pos, 8) + require.Equal(t, uint64(0x5a), v) + v, _ = ReadBits(buf, &pos, 20) + require.Equal(t, uint64(0xaaec4), v) +} + +func TestReadBitsError(t *testing.T) { + buf := []byte{0xA8} + pos := 0 + _, err := ReadBits(buf, &pos, 6) + require.NoError(t, err) + _, err = ReadBits(buf, &pos, 6) + require.EqualError(t, err, "not enough bits") +} + +func TestReadGolombUnsigned(t *testing.T) { + buf := []byte{0x38} + pos := 0 + v, _ := ReadGolombUnsigned(buf, &pos) + require.Equal(t, uint32(6), v) +} + +func TestReadGolombUnsignedErrors(t *testing.T) { + buf := []byte{0x00} + pos := 0 + _, err := ReadGolombUnsigned(buf, &pos) + require.EqualError(t, err, "not enough bits") + + buf = []byte{0x00, 0x01} + pos = 0 + _, err = ReadGolombUnsigned(buf, &pos) + require.EqualError(t, err, "not enough bits") + + buf = []byte{0x00, 0x00, 0x00, 0x00, 0x01} + pos = 0 + _, err = ReadGolombUnsigned(buf, &pos) + require.EqualError(t, err, "invalid value") +} + +func TestReadGolombSigned(t *testing.T) { + buf := []byte{0x38} + pos := 0 + v, _ := ReadGolombSigned(buf, &pos) + require.Equal(t, int32(-3), v) + + buf = []byte{0b00100100} + pos = 0 + v, _ = ReadGolombSigned(buf, &pos) + require.Equal(t, int32(2), v) +} + +func TestReadGolombSignedErrors(t *testing.T) { + buf := []byte{0x00} + pos := 0 + _, err := ReadGolombSigned(buf, &pos) + require.EqualError(t, err, "not enough bits") +} + +func TestReadFlag(t *testing.T) { + buf := []byte{0xFF} + pos := 0 + v, _ := ReadFlag(buf, &pos) + require.Equal(t, true, v) +} + +func TestReadFlagError(t *testing.T) { + buf := []byte{} + pos := 0 + _, err := ReadFlag(buf, &pos) + require.EqualError(t, err, "not enough bits") +} diff --git a/pkg/bits/write.go b/pkg/bits/write.go new file mode 100644 index 0000000..4c71275 --- /dev/null +++ b/pkg/bits/write.go @@ -0,0 +1,26 @@ +package bits + +// WriteBits writes N bits. +func WriteBits(buf []byte, pos *int, bits uint64, n int) { + res := 8 - (*pos & 0x07) + if n < res { + buf[*pos>>0x03] |= byte(bits << (res - n)) + *pos += n + return + } + + buf[*pos>>3] |= byte(bits >> (n - res)) + *pos += res + n -= res + + for n >= 8 { + buf[*pos>>3] = byte(bits >> (n - 8)) + *pos += 8 + n -= 8 + } + + if n > 0 { + buf[*pos>>3] = byte((bits & (1<= bl || start >= 4 { + return nil, fmt.Errorf("initial delimiter not found") + } + + switch initZeroCount { + case 0, 1: + if byts[start] != 0 { + return nil, fmt.Errorf("initial delimiter not found") + } + initZeroCount++ + + case 2, 3: + switch byts[start] { + case 1: + start++ + break outer + + case 0: + + default: + return nil, fmt.Errorf("initial delimiter not found") + } + initZeroCount++ + } + + start++ + } + + zeroCount := 0 + n := 0 + + for i := start; i < bl; i++ { + switch byts[i] { + case 0: + zeroCount++ + + case 1: + if zeroCount == 2 || zeroCount == 3 { + n++ + } + zeroCount = 0 + + default: + zeroCount = 0 + } + } + + if (n + 1) > MaxNALUsPerGroup { + return nil, fmt.Errorf("NALU count (%d) exceeds maximum allowed (%d)", + n+1, MaxNALUsPerGroup) + } + + ret := make([][]byte, n+1) + pos := 0 + start = initZeroCount + 1 + zeroCount = 0 + delimStart := 0 + + for i := start; i < bl; i++ { + switch byts[i] { + case 0: + if zeroCount == 0 { + delimStart = i + } + zeroCount++ + + case 1: + if zeroCount == 2 || zeroCount == 3 { + l := delimStart - start + if l == 0 { + return nil, fmt.Errorf("invalid NALU") + } + if l > MaxNALUSize { + return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", l, MaxNALUSize) + } + + ret[pos] = byts[start:delimStart] + pos++ + start = i + 1 + } + zeroCount = 0 + + default: + zeroCount = 0 + } + } + + l := bl - start + if l == 0 { + return nil, fmt.Errorf("invalid NALU") + } + if l > MaxNALUSize { + return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", l, MaxNALUSize) + } + + ret[pos] = byts[start:bl] + + return ret, nil +} + +func annexBMarshalSize(nalus [][]byte) int { + n := 0 + for _, nalu := range nalus { + n += 4 + len(nalu) + } + return n +} + +// AnnexBMarshal encodes NALUs into the Annex-B stream format. +func AnnexBMarshal(nalus [][]byte) ([]byte, error) { + buf := make([]byte, annexBMarshalSize(nalus)) + pos := 0 + + for _, nalu := range nalus { + pos += copy(buf[pos:], []byte{0x00, 0x00, 0x00, 0x01}) + pos += copy(buf[pos:], nalu) + } + + return buf, nil +} diff --git a/pkg/codecs/h264/annexb_test.go b/pkg/codecs/h264/annexb_test.go new file mode 100644 index 0000000..ae9030c --- /dev/null +++ b/pkg/codecs/h264/annexb_test.go @@ -0,0 +1,127 @@ +//go:build go1.18 +// +build go1.18 + +package h264 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var casesAnnexB = []struct { + name string + encin []byte + encout []byte + dec [][]byte +}{ + { + "2 zeros", + []byte{ + 0x00, 0x00, 0x01, 0xaa, 0xbb, 0x00, 0x00, 0x01, + 0xcc, 0xdd, 0x00, 0x00, 0x01, 0xee, 0xff, + }, + []byte{ + 0x00, 0x00, 0x00, 0x01, 0xaa, 0xbb, + 0x00, 0x00, 0x00, 0x01, 0xcc, 0xdd, + 0x00, 0x00, 0x00, 0x01, 0xee, 0xff, + }, + [][]byte{ + {0xaa, 0xbb}, + {0xcc, 0xdd}, + {0xee, 0xff}, + }, + }, + { + "3 zeros", + []byte{ + 0x00, 0x00, 0x00, 0x01, 0xaa, 0xbb, + 0x00, 0x00, 0x00, 0x01, 0xcc, 0xdd, + 0x00, 0x00, 0x00, 0x01, 0xee, 0xff, + }, + []byte{ + 0x00, 0x00, 0x00, 0x01, 0xaa, 0xbb, + 0x00, 0x00, 0x00, 0x01, 0xcc, 0xdd, + 0x00, 0x00, 0x00, 0x01, 0xee, 0xff, + }, + [][]byte{ + {0xaa, 0xbb}, + {0xcc, 0xdd}, + {0xee, 0xff}, + }, + }, + { + // used by Apple inside HLS test streams + "2 or 3 zeros", + []byte{ + 0, 0, 0, 1, 9, 240, + 0, 0, 0, 1, 39, 66, 224, 21, 169, 24, 60, 23, 252, 184, 3, 80, 96, 16, 107, 108, 43, 94, 247, 192, 64, + 0, 0, 0, 1, 40, 222, 9, 200, + 0, 0, 1, 6, 0, 7, 131, 236, 119, 0, 0, 0, 0, 1, 3, 0, 64, 128, + 0, 0, 1, 6, 5, 17, 3, 135, 244, 78, 205, 10, 75, 220, 161, 148, 58, 195, 212, 155, 23, 31, 0, 128, + }, + []byte{ + 0, 0, 0, 1, 9, 240, + 0, 0, 0, 1, 39, 66, 224, 21, 169, 24, 60, 23, 252, 184, 3, 80, 96, 16, 107, 108, 43, 94, 247, 192, 64, + 0, 0, 0, 1, 40, 222, 9, 200, + 0, 0, 0, 1, 6, 0, 7, 131, 236, 119, 0, 0, 0, 0, 1, 3, 0, 64, 128, + 0, 0, 0, 1, 6, 5, 17, 3, 135, 244, 78, 205, 10, 75, 220, 161, 148, 58, 195, 212, 155, 23, 31, 0, 128, + }, + [][]byte{ + {9, 240}, + {39, 66, 224, 21, 169, 24, 60, 23, 252, 184, 3, 80, 96, 16, 107, 108, 43, 94, 247, 192, 64}, + {40, 222, 9, 200}, + {6, 0, 7, 131, 236, 119, 0, 0, 0, 0, 1, 3, 0, 64, 128}, + {6, 5, 17, 3, 135, 244, 78, 205, 10, 75, 220, 161, 148, 58, 195, 212, 155, 23, 31, 0, 128}, + }, + }, +} + +func TestAnnexBUnmarshal(t *testing.T) { + for _, ca := range casesAnnexB { + t.Run(ca.name, func(t *testing.T) { + dec, err := AnnexBUnmarshal(ca.encin) + require.NoError(t, err) + require.Equal(t, ca.dec, dec) + }) + } +} + +func TestAnnexBMarshal(t *testing.T) { + for _, ca := range casesAnnexB { + t.Run(ca.name, func(t *testing.T) { + enc, err := AnnexBMarshal(ca.dec) + require.NoError(t, err) + require.Equal(t, ca.encout, enc) + }) + } +} + +func BenchmarkAnnexBUnmarshal(b *testing.B) { + for i := 0; i < b.N; i++ { + AnnexBUnmarshal([]byte{ + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, + }) + } +} + +func FuzzAnnexBUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + AnnexBUnmarshal(b) + }) +} diff --git a/pkg/codecs/h264/avcc.go b/pkg/codecs/h264/avcc.go new file mode 100644 index 0000000..52afe00 --- /dev/null +++ b/pkg/codecs/h264/avcc.go @@ -0,0 +1,74 @@ +package h264 + +import ( + "fmt" +) + +// AVCCUnmarshal decodes NALUs from the AVCC stream format. +func AVCCUnmarshal(buf []byte) ([][]byte, error) { + bl := len(buf) + pos := 0 + var ret [][]byte + + for { + if (bl - pos) < 4 { + return nil, fmt.Errorf("invalid length") + } + + l := int(uint32(buf[pos])<<24 | uint32(buf[pos+1])<<16 | uint32(buf[pos+2])<<8 | uint32(buf[pos+3])) + pos += 4 + + if l == 0 { + return nil, fmt.Errorf("invalid NALU") + } + + if l > MaxNALUSize { + return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", l, MaxNALUSize) + } + + if (len(ret) + 1) > MaxNALUsPerGroup { + return nil, fmt.Errorf("NALU count (%d) exceeds maximum allowed (%d)", + len(ret)+1, MaxNALUsPerGroup) + } + + if (bl - pos) < l { + return nil, fmt.Errorf("invalid length") + } + + ret = append(ret, buf[pos:pos+l]) + pos += l + + if (bl - pos) == 0 { + break + } + } + + return ret, nil +} + +func avccMarshalSize(nalus [][]byte) int { + n := 0 + for _, nalu := range nalus { + n += 4 + len(nalu) + } + return n +} + +// AVCCMarshal encodes NALUs into the AVCC stream format. +func AVCCMarshal(nalus [][]byte) ([]byte, error) { + buf := make([]byte, avccMarshalSize(nalus)) + pos := 0 + + for _, nalu := range nalus { + naluLen := len(nalu) + buf[pos] = byte(naluLen >> 24) + buf[pos+1] = byte(naluLen >> 16) + buf[pos+2] = byte(naluLen >> 8) + buf[pos+3] = byte(naluLen) + pos += 4 + + pos += copy(buf[pos:], nalu) + } + + return buf, nil +} diff --git a/pkg/codecs/h264/avcc_test.go b/pkg/codecs/h264/avcc_test.go new file mode 100644 index 0000000..8d44337 --- /dev/null +++ b/pkg/codecs/h264/avcc_test.go @@ -0,0 +1,69 @@ +//go:build go1.18 +// +build go1.18 + +package h264 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var casesAVCC = []struct { + name string + enc []byte + dec [][]byte +}{ + { + "single", + []byte{ + 0x00, 0x00, 0x00, 0x03, + 0xaa, 0xbb, 0xcc, + }, + [][]byte{ + {0xaa, 0xbb, 0xcc}, + }, + }, + { + "multiple", + []byte{ + 0x00, 0x00, 0x00, 0x02, + 0xaa, 0xbb, + 0x00, 0x00, 0x00, 0x02, + 0xcc, 0xdd, + 0x00, 0x00, 0x00, 0x02, + 0xee, 0xff, + }, + [][]byte{ + {0xaa, 0xbb}, + {0xcc, 0xdd}, + {0xee, 0xff}, + }, + }, +} + +func TestAVCCUnmarshal(t *testing.T) { + for _, ca := range casesAVCC { + t.Run(ca.name, func(t *testing.T) { + dec, err := AVCCUnmarshal(ca.enc) + require.NoError(t, err) + require.Equal(t, ca.dec, dec) + }) + } +} + +func TestAVCCMarshal(t *testing.T) { + for _, ca := range casesAVCC { + t.Run(ca.name, func(t *testing.T) { + enc, err := AVCCMarshal(ca.dec) + require.NoError(t, err) + require.Equal(t, ca.enc, enc) + }) + } +} + +func FuzzAVCCUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + AVCCUnmarshal(b) + }) +} diff --git a/pkg/codecs/h264/dts_extractor.go b/pkg/codecs/h264/dts_extractor.go new file mode 100644 index 0000000..65ec9b6 --- /dev/null +++ b/pkg/codecs/h264/dts_extractor.go @@ -0,0 +1,193 @@ +package h264 + +import ( + "fmt" + "time" + + "github.com/bluenviron/mediabase/pkg/bits" +) + +func getPictureOrderCount(buf []byte, sps *SPS) (uint32, error) { + if len(buf) < 6 { + return 0, fmt.Errorf("not enough bits") + } + + buf = EmulationPreventionRemove(buf[:6]) + + buf = buf[1:] + pos := 0 + + _, err := bits.ReadGolombUnsigned(buf, &pos) // first_mb_in_slice + if err != nil { + return 0, err + } + + _, err = bits.ReadGolombUnsigned(buf, &pos) // slice_type + if err != nil { + return 0, err + } + + _, err = bits.ReadGolombUnsigned(buf, &pos) // pic_parameter_set_id + if err != nil { + return 0, err + } + + _, err = bits.ReadBits(buf, &pos, int(sps.Log2MaxFrameNumMinus4+4)) // frame_num + if err != nil { + return 0, err + } + + if !sps.FrameMbsOnlyFlag { + return 0, fmt.Errorf("frame_mbs_only_flag = 0 is not supported") + } + + picOrderCntLsb, err := bits.ReadBits(buf, &pos, int(sps.Log2MaxPicOrderCntLsbMinus4+4)) + if err != nil { + return 0, err + } + + return uint32(picOrderCntLsb), nil +} + +func findPictureOrderCount(au [][]byte, sps *SPS) (uint32, error) { + for _, nalu := range au { + typ := NALUType(nalu[0] & 0x1F) + if typ == NALUTypeNonIDR { + poc, err := getPictureOrderCount(nalu, sps) + if err != nil { + return 0, err + } + return poc, nil + } + } + return 0, fmt.Errorf("POC not found") +} + +func getPictureOrderCountDiff(poc1 uint32, poc2 uint32, sps *SPS) int32 { + diff := int32(poc1) - int32(poc2) + switch { + case diff < -((1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 3)) - 1): + diff += (1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 4)) + + case diff > ((1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 3)) - 1): + diff -= (1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 4)) + } + return diff +} + +// DTSExtractor allows to extract DTS from PTS. +type DTSExtractor struct { + spsp *SPS + prevDTSFilled bool + prevDTS time.Duration + expectedPOC uint32 + reorderedFrames int + pauseDTS int + pocIncrement int +} + +// NewDTSExtractor allocates a DTSExtractor. +func NewDTSExtractor() *DTSExtractor { + return &DTSExtractor{ + pocIncrement: 2, + } +} + +func (d *DTSExtractor) extractInner(au [][]byte, pts time.Duration) (time.Duration, error) { + idrPresent := false + + for _, nalu := range au { + typ := NALUType(nalu[0] & 0x1F) + switch typ { + case NALUTypeSPS: + var spsp SPS + err := spsp.Unmarshal(nalu) + if err != nil { + return 0, fmt.Errorf("invalid SPS: %v", err) + } + d.spsp = &spsp + + case NALUTypeIDR: + idrPresent = true + } + } + + if d.spsp == nil { + return 0, fmt.Errorf("SPS not received yet") + } + + if d.spsp.PicOrderCntType == 2 { + return pts, nil + } + + if d.spsp.PicOrderCntType == 1 { + return 0, fmt.Errorf("pic_order_cnt_type = 1 is not supported yet") + } + + if idrPresent { + d.expectedPOC = 0 + d.reorderedFrames = 0 + d.pauseDTS = 0 + d.pocIncrement = 2 + return pts, nil + } + + d.expectedPOC += uint32(d.pocIncrement) + d.expectedPOC &= ((1 << (d.spsp.Log2MaxPicOrderCntLsbMinus4 + 4)) - 1) + + if d.pauseDTS > 0 { + d.pauseDTS-- + return d.prevDTS + 1*time.Millisecond, nil + } + + poc, err := findPictureOrderCount(au, d.spsp) + if err != nil { + return 0, err + } + + if d.pocIncrement == 2 && (poc%2) != 0 { + d.pocIncrement = 1 + d.expectedPOC /= 2 + } + + pocDiff := int(getPictureOrderCountDiff(poc, d.expectedPOC, d.spsp)) + d.reorderedFrames*d.pocIncrement + + if pocDiff < 0 { + return 0, fmt.Errorf("invalid POC") + } + + if pocDiff == 0 { + return pts, nil + } + + reorderedFrames := (pocDiff - d.reorderedFrames*d.pocIncrement) / d.pocIncrement + if reorderedFrames > d.reorderedFrames { + d.pauseDTS = (reorderedFrames - d.reorderedFrames - 1) + d.reorderedFrames = reorderedFrames + return d.prevDTS + 1*time.Millisecond, nil + } + + return d.prevDTS + ((pts - d.prevDTS) * time.Duration(d.pocIncrement) / time.Duration(pocDiff+d.pocIncrement)), nil +} + +// Extract extracts the DTS of a access unit. +func (d *DTSExtractor) Extract(au [][]byte, pts time.Duration) (time.Duration, error) { + dts, err := d.extractInner(au, pts) + if err != nil { + return 0, err + } + + if dts > pts { + return 0, fmt.Errorf("DTS is greater than PTS") + } + + if d.prevDTSFilled && dts <= d.prevDTS { + return 0, fmt.Errorf("DTS is not monotonically increasing, was %v, now is %v", + d.prevDTS, dts) + } + + d.prevDTS = dts + d.prevDTSFilled = true + + return dts, err +} diff --git a/pkg/codecs/h264/dts_extractor_test.go b/pkg/codecs/h264/dts_extractor_test.go new file mode 100644 index 0000000..e5b73f0 --- /dev/null +++ b/pkg/codecs/h264/dts_extractor_test.go @@ -0,0 +1,222 @@ +//go:build go1.18 +// +build go1.18 + +package h264 + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestDTSExtractor(t *testing.T) { + type sequenceSample struct { + nalus [][]byte + dts time.Duration + pts time.Duration + } + + for _, ca := range []struct { + name string + sequence []sequenceSample + }{ + { + "with timing info", + []sequenceSample{ + { + [][]byte{ + { // SPS + 0x67, 0x64, 0x00, 0x28, 0xac, 0xd9, 0x40, 0x78, + 0x02, 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, + 0xc6, 0x58, + }, + { // IDR + 0x65, 0x88, 0x84, 0x00, 0x33, 0xff, + }, + }, + 33333333333 * time.Nanosecond, + 33333333333 * time.Nanosecond, + }, + { + [][]byte{{0x41, 0x9a, 0x21, 0x6c, 0x45, 0xff}}, + 33366666666 * time.Nanosecond, + 33366666666 * time.Nanosecond, + }, + { + [][]byte{{0x41, 0x9a, 0x42, 0x3c, 0x21, 0x93}}, + 33400000000 * time.Nanosecond, + 33400000000 * time.Nanosecond, + }, + { + [][]byte{{0x41, 0x9a, 0x63, 0x49, 0xe1, 0x0f}}, + 33433333333 * time.Nanosecond, + 33433333333 * time.Nanosecond, + }, + { + [][]byte{{0x41, 0x9a, 0x86, 0x49, 0xe1, 0x0f}}, + 33434333333 * time.Nanosecond, + 33533333333 * time.Nanosecond, + }, + { + [][]byte{{0x41, 0x9e, 0xa5, 0x42, 0x7f, 0xf9}}, + 33435333333 * time.Nanosecond, + 33500000000 * time.Nanosecond, + }, + { + [][]byte{{0x01, 0x9e, 0xc4, 0x69, 0x13, 0xff}}, + 33466666666 * time.Nanosecond, + 33466666666 * time.Nanosecond, + }, + { + [][]byte{{0x41, 0x9a, 0xc8, 0x4b, 0xa8, 0x42}}, + 33499999999 * time.Nanosecond, + 33600000000 * time.Nanosecond, + }, + }, + }, + { + "no timing info", + []sequenceSample{ + { + [][]byte{ + { // SPS + 0x27, 0x64, 0x00, 0x20, 0xac, 0x52, 0x18, 0x0f, + 0x01, 0x17, 0xef, 0xff, 0x00, 0x01, 0x00, 0x01, + 0x6a, 0x02, 0x02, 0x03, 0x6d, 0x85, 0x6b, 0xde, + 0xf8, 0x08, + }, + { // IDR + 0x25, 0xb8, 0x08, 0x02, 0x1f, 0xff, + }, + }, + 850000000 * time.Nanosecond, + 850000000 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe1, 0x05, 0xc7, 0x38, 0xbf}}, + 866666667 * time.Nanosecond, + 866666667 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe2, 0x09, 0xa1, 0xce, 0x0b}}, + 883333334 * time.Nanosecond, + 883333334 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe3, 0x0d, 0xb1, 0xce, 0x02}}, + 900000000 * time.Nanosecond, + 900000000 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe4, 0x11, 0x90, 0x73, 0x80}}, + 916666667 * time.Nanosecond, + 916666667 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe5, 0x19, 0x0e, 0x70, 0x01}}, + 917666667 * time.Nanosecond, + 950000000 * time.Nanosecond, + }, + { + [][]byte{{0x01, 0xa9, 0x85, 0x7c, 0x93, 0xff}}, + 933333334 * time.Nanosecond, + 933333334 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe6, 0x1d, 0x0e, 0x70, 0x01}}, + 950000000 * time.Nanosecond, + 966666667 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe7, 0x21, 0x0e, 0x70, 0x01}}, + 966666667 * time.Nanosecond, + 983333334 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe8, 0x25, 0x0e, 0x70, 0x01}}, + 983333333 * time.Nanosecond, + 1000000000 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xe9, 0x29, 0x0e, 0x70, 0x01}}, + 1000000000 * time.Nanosecond, + 1016666667 * time.Nanosecond, + }, + { + [][]byte{{0x21, 0xea, 0x31, 0x0e, 0x70, 0x01}}, + 1016666666 * time.Nanosecond, + 1050000000 * time.Nanosecond, + }, + { + [][]byte{{0x01, 0xaa, 0xcb, 0x7c, 0x93, 0xff}}, + 1033333334 * time.Nanosecond, + 1033333334 * time.Nanosecond, + }, + }, + }, + { + "poc increment = 1", + []sequenceSample{ + { + [][]byte{ + { // SPS + 0x67, 0x64, 0x00, 0x2a, 0xac, 0x2c, 0x6a, 0x81, + 0xe0, 0x08, 0x9f, 0x96, 0x6e, 0x02, 0x02, 0x02, + 0x80, 0x00, 0x03, 0x84, 0x00, 0x00, 0xaf, 0xc8, + 0x02, + }, + { // IDR + 0x65, 0xb8, 0x00, 0x00, 0x0b, 0xc8, + }, + }, + 61 * time.Millisecond, + 61 * time.Millisecond, + }, + { + [][]byte{{0x61, 0xe0, 0x20, 0x00, 0x39, 0x37}}, + 101 * time.Millisecond, + 101 * time.Millisecond, + }, + { + [][]byte{{0x61, 0xe0, 0x40, 0x00, 0x59, 0x37}}, + 141 * time.Millisecond, + 141 * time.Millisecond, + }, + { + [][]byte{{0x61, 0xe0, 0x60, 0x00, 0x79, 0x37}}, + 181 * time.Millisecond, + 181 * time.Millisecond, + }, + }, + }, + } { + t.Run(ca.name, func(t *testing.T) { + ex := NewDTSExtractor() + for _, sample := range ca.sequence { + dts, err := ex.Extract(sample.nalus, sample.pts) + require.NoError(t, err) + require.Equal(t, sample.dts, dts) + } + }) + } +} + +func FuzzDTSExtractor(f *testing.F) { + ex := NewDTSExtractor() + f.Fuzz(func(t *testing.T, b []byte, p uint64) { + if len(b) < 1 { + return + } + ex.Extract([][]byte{ + { // SPS + 0x27, 0x64, 0x00, 0x20, 0xac, 0x52, 0x18, 0x0f, + 0x01, 0x17, 0xef, 0xff, 0x00, 0x01, 0x00, 0x01, + 0x6a, 0x02, 0x02, 0x03, 0x6d, 0x85, 0x6b, 0xde, + 0xf8, 0x08, + }, + b, + }, time.Duration(p)) + }) +} diff --git a/pkg/codecs/h264/emulation_prevention.go b/pkg/codecs/h264/emulation_prevention.go new file mode 100644 index 0000000..611a080 --- /dev/null +++ b/pkg/codecs/h264/emulation_prevention.go @@ -0,0 +1,33 @@ +package h264 + +// EmulationPreventionRemove removes emulation prevention bytes from a NALU. +func EmulationPreventionRemove(nalu []byte) []byte { + // 0x00 0x00 0x03 0x00 -> 0x00 0x00 0x00 + // 0x00 0x00 0x03 0x01 -> 0x00 0x00 0x01 + // 0x00 0x00 0x03 0x02 -> 0x00 0x00 0x02 + // 0x00 0x00 0x03 0x03 -> 0x00 0x00 0x03 + + l := len(nalu) + n := l + + for i := 2; i < l; i++ { + if nalu[i-2] == 0 && nalu[i-1] == 0 && nalu[i] == 3 { + n-- + } + } + + ret := make([]byte, n) + pos := 0 + start := 0 + + for i := 2; i < l; i++ { + if nalu[i-2] == 0 && nalu[i-1] == 0 && nalu[i] == 3 { + pos += copy(ret[pos:], nalu[start:i]) + start = i + 1 + } + } + + copy(ret[pos:], nalu[start:]) + + return ret +} diff --git a/pkg/codecs/h264/emulation_prevention_test.go b/pkg/codecs/h264/emulation_prevention_test.go new file mode 100644 index 0000000..bd54ded --- /dev/null +++ b/pkg/codecs/h264/emulation_prevention_test.go @@ -0,0 +1,65 @@ +//go:build go1.18 +// +build go1.18 + +package h264 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestEmulationPreventionRemove(t *testing.T) { + for _, ca := range []struct { + name string + unproc []byte + proc []byte + }{ + { + "base", + []byte{ + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, + 0x00, 0x00, 0x02, + 0x00, 0x00, 0x03, + }, + []byte{ + 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x03, 0x01, + 0x00, 0x00, 0x03, 0x02, + 0x00, 0x00, 0x03, 0x03, + }, + }, + { + "double emulation byte", + []byte{ + 0x00, 0x00, 0x00, + 0x00, 0x00, + }, + []byte{ + 0x00, 0x00, 0x03, + 0x00, 0x00, 0x03, 0x00, + }, + }, + { + "terminal emulation byte", + []byte{ + 0x00, 0x00, + }, + []byte{ + 0x00, 0x00, 0x03, + }, + }, + } { + t.Run(ca.name, func(t *testing.T) { + unproc := EmulationPreventionRemove(ca.proc) + require.Equal(t, ca.unproc, unproc) + }) + } +} + +func FuzzEmulationPreventionRemove(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + EmulationPreventionRemove(b) + }) +} diff --git a/pkg/codecs/h264/h264.go b/pkg/codecs/h264/h264.go new file mode 100644 index 0000000..e2cf793 --- /dev/null +++ b/pkg/codecs/h264/h264.go @@ -0,0 +1,11 @@ +// Package h264 contains utilities to work with the H264 codec. +package h264 + +const ( + // MaxNALUSize is the maximum size of a NALU. + // with a 250 Mbps H264 video, the maximum NALU size is 2.2MB + MaxNALUSize = 3 * 1024 * 1024 + + // MaxNALUsPerGroup is the maximum number of NALUs per group. + MaxNALUsPerGroup = 20 +) diff --git a/pkg/codecs/h264/idrpresent.go b/pkg/codecs/h264/idrpresent.go new file mode 100644 index 0000000..9c329d4 --- /dev/null +++ b/pkg/codecs/h264/idrpresent.go @@ -0,0 +1,12 @@ +package h264 + +// IDRPresent check if there's an IDR inside provided NALUs. +func IDRPresent(nalus [][]byte) bool { + for _, nalu := range nalus { + typ := NALUType(nalu[0] & 0x1F) + if typ == NALUTypeIDR { + return true + } + } + return false +} diff --git a/pkg/codecs/h264/idrpresent_test.go b/pkg/codecs/h264/idrpresent_test.go new file mode 100644 index 0000000..209f9c8 --- /dev/null +++ b/pkg/codecs/h264/idrpresent_test.go @@ -0,0 +1,17 @@ +package h264 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestIDRPresent(t *testing.T) { + require.Equal(t, true, IDRPresent([][]byte{ + {0x05}, + {0x07}, + })) + require.Equal(t, false, IDRPresent([][]byte{ + {0x01}, + })) +} diff --git a/pkg/codecs/h264/nalu_type.go b/pkg/codecs/h264/nalu_type.go new file mode 100644 index 0000000..5c5a86a --- /dev/null +++ b/pkg/codecs/h264/nalu_type.go @@ -0,0 +1,83 @@ +package h264 + +import ( + "fmt" +) + +// NALUType is the type of a NALU. +type NALUType uint8 + +// NALU types. +const ( + NALUTypeNonIDR NALUType = 1 + NALUTypeDataPartitionA NALUType = 2 + NALUTypeDataPartitionB NALUType = 3 + NALUTypeDataPartitionC NALUType = 4 + NALUTypeIDR NALUType = 5 + NALUTypeSEI NALUType = 6 + NALUTypeSPS NALUType = 7 + NALUTypePPS NALUType = 8 + NALUTypeAccessUnitDelimiter NALUType = 9 + NALUTypeEndOfSequence NALUType = 10 + NALUTypeEndOfStream NALUType = 11 + NALUTypeFillerData NALUType = 12 + NALUTypeSPSExtension NALUType = 13 + NALUTypePrefix NALUType = 14 + NALUTypeSubsetSPS NALUType = 15 + NALUTypeReserved16 NALUType = 16 + NALUTypeReserved17 NALUType = 17 + NALUTypeReserved18 NALUType = 18 + NALUTypeSliceLayerWithoutPartitioning NALUType = 19 + NALUTypeSliceExtension NALUType = 20 + NALUTypeSliceExtensionDepth NALUType = 21 + NALUTypeReserved22 NALUType = 22 + NALUTypeReserved23 NALUType = 23 + + // additional NALU types for RTP/H264 + NALUTypeSTAPA NALUType = 24 + NALUTypeSTAPB NALUType = 25 + NALUTypeMTAP16 NALUType = 26 + NALUTypeMTAP24 NALUType = 27 + NALUTypeFUA NALUType = 28 + NALUTypeFUB NALUType = 29 +) + +var naluTypeLabels = map[NALUType]string{ + NALUTypeNonIDR: "NonIDR", + NALUTypeDataPartitionA: "DataPartitionA", + NALUTypeDataPartitionB: "DataPartitionB", + NALUTypeDataPartitionC: "DataPartitionC", + NALUTypeIDR: "IDR", + NALUTypeSEI: "SEI", + NALUTypeSPS: "SPS", + NALUTypePPS: "PPS", + NALUTypeAccessUnitDelimiter: "AccessUnitDelimiter", + NALUTypeEndOfSequence: "EndOfSequence", + NALUTypeEndOfStream: "EndOfStream", + NALUTypeFillerData: "FillerData", + NALUTypeSPSExtension: "SPSExtension", + NALUTypePrefix: "Prefix", + NALUTypeSubsetSPS: "SubsetSPS", + NALUTypeReserved16: "Reserved16", + NALUTypeReserved17: "Reserved17", + NALUTypeReserved18: "Reserved18", + NALUTypeSliceLayerWithoutPartitioning: "SliceLayerWithoutPartitioning", + NALUTypeSliceExtension: "SliceExtension", + NALUTypeSliceExtensionDepth: "SliceExtensionDepth", + NALUTypeReserved22: "Reserved22", + NALUTypeReserved23: "Reserved23", + NALUTypeSTAPA: "STAP-A", + NALUTypeSTAPB: "STAP-B", + NALUTypeMTAP16: "MTAP-16", + NALUTypeMTAP24: "MTAP-24", + NALUTypeFUA: "FU-A", + NALUTypeFUB: "FU-B", +} + +// String implements fmt.Stringer. +func (nt NALUType) String() string { + if l, ok := naluTypeLabels[nt]; ok { + return l + } + return fmt.Sprintf("unknown (%d)", nt) +} diff --git a/pkg/codecs/h264/nalu_type_test.go b/pkg/codecs/h264/nalu_type_test.go new file mode 100644 index 0000000..8602e0a --- /dev/null +++ b/pkg/codecs/h264/nalu_type_test.go @@ -0,0 +1,13 @@ +package h264 + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNALUType(t *testing.T) { + require.NotEqual(t, true, strings.HasPrefix(NALUType(10).String(), "unknown")) + require.Equal(t, true, strings.HasPrefix(NALUType(50).String(), "unknown")) +} diff --git a/pkg/codecs/h264/sps.go b/pkg/codecs/h264/sps.go new file mode 100644 index 0000000..9fbf3c9 --- /dev/null +++ b/pkg/codecs/h264/sps.go @@ -0,0 +1,728 @@ +package h264 + +import ( + "fmt" + + "github.com/bluenviron/mediabase/pkg/bits" +) + +const ( + maxRefFrames = 255 +) + +func readScalingList(buf []byte, pos *int, size int) ([]int32, bool, error) { + lastScale := int32(8) + nextScale := int32(8) + scalingList := make([]int32, size) + var useDefaultScalingMatrixFlag bool + + for j := 0; j < size; j++ { + if nextScale != 0 { + deltaScale, err := bits.ReadGolombSigned(buf, pos) + if err != nil { + return nil, false, err + } + + nextScale = (lastScale + deltaScale + 256) % 256 + useDefaultScalingMatrixFlag = (j == 0 && nextScale == 0) + } + + if nextScale == 0 { + scalingList[j] = lastScale + } else { + scalingList[j] = nextScale + } + + lastScale = scalingList[j] + } + + return scalingList, useDefaultScalingMatrixFlag, nil +} + +// SPS_HRD is a hypotetical reference decoder. +type SPS_HRD struct { //nolint:revive + CpbCntMinus1 uint32 + BitRateScale uint8 + CpbSizeScale uint8 + BitRateValueMinus1 []uint32 + CpbSizeValueMinus1 []uint32 + CbrFlag []bool + InitialCpbRemovalDelayLengthMinus1 uint8 + CpbRemovalDelayLengthMinus1 uint8 + DpbOutputDelayLengthMinus1 uint8 + TimeOffsetLength uint8 +} + +func (h *SPS_HRD) unmarshal(buf []byte, pos *int) error { + var err error + h.CpbCntMinus1, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + err = bits.HasSpace(buf, *pos, 8) + if err != nil { + return err + } + + h.BitRateScale = uint8(bits.ReadBitsUnsafe(buf, pos, 4)) + h.CpbSizeScale = uint8(bits.ReadBitsUnsafe(buf, pos, 4)) + + for i := uint32(0); i <= h.CpbCntMinus1; i++ { + v, err := bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + h.BitRateValueMinus1 = append(h.BitRateValueMinus1, v) + + v, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + h.CpbSizeValueMinus1 = append(h.CpbSizeValueMinus1, v) + + vb, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + h.CbrFlag = append(h.CbrFlag, vb) + } + + err = bits.HasSpace(buf, *pos, 5+5+5+5) + if err != nil { + return err + } + + h.InitialCpbRemovalDelayLengthMinus1 = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) + h.CpbRemovalDelayLengthMinus1 = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) + h.DpbOutputDelayLengthMinus1 = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) + h.TimeOffsetLength = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) + + return nil +} + +// SPS_TimingInfo is a timing info. +type SPS_TimingInfo struct { //nolint:revive + NumUnitsInTick uint32 + TimeScale uint32 + FixedFrameRateFlag bool +} + +func (t *SPS_TimingInfo) unmarshal(buf []byte, pos *int) error { + err := bits.HasSpace(buf, *pos, 32+32+1) + if err != nil { + return err + } + + t.NumUnitsInTick = uint32(bits.ReadBitsUnsafe(buf, pos, 32)) + t.TimeScale = uint32(bits.ReadBitsUnsafe(buf, pos, 32)) + t.FixedFrameRateFlag = bits.ReadFlagUnsafe(buf, pos) + + return nil +} + +// SPS_BitstreamRestriction are bitstream restriction infos. +type SPS_BitstreamRestriction struct { //nolint:revive + MotionVectorsOverPicBoundariesFlag bool + MaxBytesPerPicDenom uint32 + MaxBitsPerMbDenom uint32 + Log2MaxMvLengthHorizontal uint32 + Log2MaxMvLengthVertical uint32 + MaxNumReorderFrames uint32 + MaxDecFrameBuffering uint32 +} + +func (r *SPS_BitstreamRestriction) unmarshal(buf []byte, pos *int) error { + var err error + r.MotionVectorsOverPicBoundariesFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + r.MaxBytesPerPicDenom, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.MaxBitsPerMbDenom, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.Log2MaxMvLengthHorizontal, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.Log2MaxMvLengthVertical, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.MaxNumReorderFrames, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.MaxDecFrameBuffering, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + return nil +} + +// SPS_VUI is a video usability information. +type SPS_VUI struct { //nolint:revive + AspectRatioInfoPresentFlag bool + + // AspectRatioInfoPresentFlag == true + AspectRatioIdc uint8 + SarWidth uint16 + SarHeight uint16 + + OverscanInfoPresentFlag bool + + // OverscanInfoPresentFlag == true + OverscanAppropriateFlag bool + VideoSignalTypePresentFlag bool + + // VideoSignalTypePresentFlag == true + VideoFormat uint8 + VideoFullRangeFlag bool + ColourDescriptionPresentFlag bool + + // ColourDescriptionPresentFlag == true + ColourPrimaries uint8 + TransferCharacteristics uint8 + MatrixCoefficients uint8 + + ChromaLocInfoPresentFlag bool + + // ChromaLocInfoPresentFlag == true + ChromaSampleLocTypeTopField uint32 + ChromaSampleLocTypeBottomField uint32 + + TimingInfo *SPS_TimingInfo + NalHRD *SPS_HRD + VclHRD *SPS_HRD + + LowDelayHrdFlag bool + PicStructPresentFlag bool + BitstreamRestriction *SPS_BitstreamRestriction +} + +func (v *SPS_VUI) unmarshal(buf []byte, pos *int) error { + var err error + v.AspectRatioInfoPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.AspectRatioInfoPresentFlag { + tmp, err := bits.ReadBits(buf, pos, 8) + if err != nil { + return err + } + v.AspectRatioIdc = uint8(tmp) + + if v.AspectRatioIdc == 255 { // Extended_SAR + err := bits.HasSpace(buf, *pos, 32) + if err != nil { + return err + } + + v.SarWidth = uint16(bits.ReadBitsUnsafe(buf, pos, 16)) + v.SarHeight = uint16(bits.ReadBitsUnsafe(buf, pos, 16)) + } + } + + v.OverscanInfoPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.OverscanInfoPresentFlag { + v.OverscanAppropriateFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + } + + v.VideoSignalTypePresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.VideoSignalTypePresentFlag { + err := bits.HasSpace(buf, *pos, 5) + if err != nil { + return err + } + + v.VideoFormat = uint8(bits.ReadBitsUnsafe(buf, pos, 3)) + v.VideoFullRangeFlag = bits.ReadFlagUnsafe(buf, pos) + v.ColourDescriptionPresentFlag = bits.ReadFlagUnsafe(buf, pos) + + if v.ColourDescriptionPresentFlag { + err := bits.HasSpace(buf, *pos, 24) + if err != nil { + return err + } + + v.ColourPrimaries = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) + v.TransferCharacteristics = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) + v.MatrixCoefficients = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) + } + } + + v.ChromaLocInfoPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.ChromaLocInfoPresentFlag { + v.ChromaSampleLocTypeTopField, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + v.ChromaSampleLocTypeBottomField, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + } + + timingInfoPresentFlag, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if timingInfoPresentFlag { + v.TimingInfo = &SPS_TimingInfo{} + err := v.TimingInfo.unmarshal(buf, pos) + if err != nil { + return err + } + } + + nalHrdParametersPresentFlag, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if nalHrdParametersPresentFlag { + v.NalHRD = &SPS_HRD{} + err := v.NalHRD.unmarshal(buf, pos) + if err != nil { + return err + } + } + + vclHrdParametersPresentFlag, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if vclHrdParametersPresentFlag { + v.VclHRD = &SPS_HRD{} + err := v.VclHRD.unmarshal(buf, pos) + if err != nil { + return err + } + } + + if nalHrdParametersPresentFlag || vclHrdParametersPresentFlag { + v.LowDelayHrdFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + } + + v.PicStructPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + bitstreamRestrictionFlag, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if bitstreamRestrictionFlag { + v.BitstreamRestriction = &SPS_BitstreamRestriction{} + err := v.BitstreamRestriction.unmarshal(buf, pos) + if err != nil { + return err + } + } + + return nil +} + +// SPS_FrameCropping is the frame cropping part of a SPS. +type SPS_FrameCropping struct { //nolint:revive + LeftOffset uint32 + RightOffset uint32 + TopOffset uint32 + BottomOffset uint32 +} + +func (c *SPS_FrameCropping) unmarshal(buf []byte, pos *int) error { + var err error + c.LeftOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + c.RightOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + c.TopOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + c.BottomOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + return nil +} + +// SPS is a H264 sequence parameter set. +type SPS struct { + ProfileIdc uint8 + ConstraintSet0Flag bool + ConstraintSet1Flag bool + ConstraintSet2Flag bool + ConstraintSet3Flag bool + ConstraintSet4Flag bool + ConstraintSet5Flag bool + LevelIdc uint8 + ID uint32 + + // only for selected ProfileIdcs + ChromeFormatIdc uint32 + SeparateColourPlaneFlag bool + BitDepthLumaMinus8 uint32 + BitDepthChromaMinus8 uint32 + QpprimeYZeroTransformBypassFlag bool + + // seqScalingListPresentFlag == true + ScalingList4x4 [][]int32 + UseDefaultScalingMatrix4x4Flag []bool + ScalingList8x8 [][]int32 + UseDefaultScalingMatrix8x8Flag []bool + + Log2MaxFrameNumMinus4 uint32 + PicOrderCntType uint32 + + // PicOrderCntType == 0 + Log2MaxPicOrderCntLsbMinus4 uint32 + + // PicOrderCntType == 1 + DeltaPicOrderAlwaysZeroFlag bool + OffsetForNonRefPic int32 + OffsetForTopToBottomField int32 + OffsetForRefFrames []int32 + + MaxNumRefFrames uint32 + GapsInFrameNumValueAllowedFlag bool + PicWidthInMbsMinus1 uint32 + PicHeightInMapUnitsMinus1 uint32 + FrameMbsOnlyFlag bool + + // FrameMbsOnlyFlag == false + MbAdaptiveFrameFieldFlag bool + + Direct8x8InferenceFlag bool + FrameCropping *SPS_FrameCropping + VUI *SPS_VUI +} + +// Unmarshal decodes a SPS from bytes. +func (s *SPS) Unmarshal(buf []byte) error { + buf = EmulationPreventionRemove(buf) + + if len(buf) < 4 { + return fmt.Errorf("not enough bits") + } + + s.ProfileIdc = buf[1] + s.ConstraintSet0Flag = (buf[2] >> 7) == 1 + s.ConstraintSet1Flag = (buf[2] >> 6 & 0x01) == 1 + s.ConstraintSet2Flag = (buf[2] >> 5 & 0x01) == 1 + s.ConstraintSet3Flag = (buf[2] >> 4 & 0x01) == 1 + s.ConstraintSet4Flag = (buf[2] >> 3 & 0x01) == 1 + s.ConstraintSet5Flag = (buf[2] >> 2 & 0x01) == 1 + s.LevelIdc = buf[3] + + buf = buf[4:] + pos := 0 + + var err error + s.ID, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + switch s.ProfileIdc { + case 100, 110, 122, 244, 44, 83, 86, 118, 128, 138, 139, 134, 135: + s.ChromeFormatIdc, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + if s.ChromeFormatIdc == 3 { + s.SeparateColourPlaneFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + } else { + s.SeparateColourPlaneFlag = false + } + + s.BitDepthLumaMinus8, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.BitDepthChromaMinus8, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.QpprimeYZeroTransformBypassFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + seqScalingMatrixPresentFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if seqScalingMatrixPresentFlag { + var lim int + if s.ChromeFormatIdc != 3 { + lim = 8 + } else { + lim = 12 + } + + for i := 0; i < lim; i++ { + seqScalingListPresentFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if seqScalingListPresentFlag { + if i < 6 { + scalingList, useDefaultScalingMatrixFlag, err := readScalingList(buf, &pos, 16) + if err != nil { + return err + } + + s.ScalingList4x4 = append(s.ScalingList4x4, scalingList) + s.UseDefaultScalingMatrix4x4Flag = append(s.UseDefaultScalingMatrix4x4Flag, + useDefaultScalingMatrixFlag) + } else { + scalingList, useDefaultScalingMatrixFlag, err := readScalingList(buf, &pos, 64) + if err != nil { + return err + } + + s.ScalingList8x8 = append(s.ScalingList8x8, scalingList) + s.UseDefaultScalingMatrix8x8Flag = append(s.UseDefaultScalingMatrix8x8Flag, + useDefaultScalingMatrixFlag) + } + } + } + } + + default: + s.ChromeFormatIdc = 0 + s.SeparateColourPlaneFlag = false + s.BitDepthLumaMinus8 = 0 + s.BitDepthChromaMinus8 = 0 + s.QpprimeYZeroTransformBypassFlag = false + } + + s.Log2MaxFrameNumMinus4, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.PicOrderCntType, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + switch s.PicOrderCntType { + case 0: + s.Log2MaxPicOrderCntLsbMinus4, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.DeltaPicOrderAlwaysZeroFlag = false + s.OffsetForNonRefPic = 0 + s.OffsetForTopToBottomField = 0 + s.OffsetForRefFrames = nil + + case 1: + s.Log2MaxPicOrderCntLsbMinus4 = 0 + + s.DeltaPicOrderAlwaysZeroFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + s.OffsetForNonRefPic, err = bits.ReadGolombSigned(buf, &pos) + if err != nil { + return err + } + + s.OffsetForTopToBottomField, err = bits.ReadGolombSigned(buf, &pos) + if err != nil { + return err + } + + numRefFramesInPicOrderCntCycle, err := bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + if numRefFramesInPicOrderCntCycle > maxRefFrames { + return fmt.Errorf("num_ref_frames_in_pic_order_cnt_cycle exceeds %d", maxRefFrames) + } + + s.OffsetForRefFrames = make([]int32, numRefFramesInPicOrderCntCycle) + for i := uint32(0); i < numRefFramesInPicOrderCntCycle; i++ { + v, err := bits.ReadGolombSigned(buf, &pos) + if err != nil { + return err + } + + s.OffsetForRefFrames[i] = v + } + + case 2: + s.Log2MaxPicOrderCntLsbMinus4 = 0 + s.DeltaPicOrderAlwaysZeroFlag = false + s.OffsetForNonRefPic = 0 + s.OffsetForTopToBottomField = 0 + s.OffsetForRefFrames = nil + + default: + return fmt.Errorf("invalid pic_order_cnt_type: %d", s.PicOrderCntType) + } + + s.MaxNumRefFrames, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.GapsInFrameNumValueAllowedFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + s.PicWidthInMbsMinus1, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.PicHeightInMapUnitsMinus1, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.FrameMbsOnlyFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if !s.FrameMbsOnlyFlag { + s.MbAdaptiveFrameFieldFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + } else { + s.MbAdaptiveFrameFieldFlag = false + } + + s.Direct8x8InferenceFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + frameCroppingFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if frameCroppingFlag { + s.FrameCropping = &SPS_FrameCropping{} + err := s.FrameCropping.unmarshal(buf, &pos) + if err != nil { + return err + } + } else { + s.FrameCropping = nil + } + + vuiParametersPresentFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if vuiParametersPresentFlag { + s.VUI = &SPS_VUI{} + err := s.VUI.unmarshal(buf, &pos) + if err != nil { + return err + } + } else { + s.VUI = nil + } + + return nil +} + +// Width returns the video width. +func (s SPS) Width() int { + if s.FrameCropping != nil { + return int(((s.PicWidthInMbsMinus1 + 1) * 16) - (s.FrameCropping.LeftOffset+s.FrameCropping.RightOffset)*2) + } + + return int((s.PicWidthInMbsMinus1 + 1) * 16) +} + +// Height returns the video height. +func (s SPS) Height() int { + f := uint32(0) + if s.FrameMbsOnlyFlag { + f = 1 + } + + if s.FrameCropping != nil { + return int(((2 - f) * (s.PicHeightInMapUnitsMinus1 + 1) * 16) - + (s.FrameCropping.TopOffset+s.FrameCropping.BottomOffset)*2) + } + + return int((2 - f) * (s.PicHeightInMapUnitsMinus1 + 1) * 16) +} + +// FPS returns the frames per second of the video. +func (s SPS) FPS() float64 { + if s.VUI == nil || s.VUI.TimingInfo == nil { + return 0 + } + + return float64(s.VUI.TimingInfo.TimeScale) / (2 * float64(s.VUI.TimingInfo.NumUnitsInTick)) +} diff --git a/pkg/codecs/h264/sps_test.go b/pkg/codecs/h264/sps_test.go new file mode 100644 index 0000000..0f47e65 --- /dev/null +++ b/pkg/codecs/h264/sps_test.go @@ -0,0 +1,462 @@ +//go:build go1.18 +// +build go1.18 + +package h264 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSPSUnmarshal(t *testing.T) { + for _, ca := range []struct { + name string + byts []byte + sps SPS + width int + height int + fps float64 + }{ + { + "352x288", + []byte{ + 0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0, + 0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, + 0x00, 0x03, 0x00, 0x3d, 0x08, + }, + SPS{ + ProfileIdc: 100, + LevelIdc: 12, + ChromeFormatIdc: 1, + Log2MaxFrameNumMinus4: 6, + PicOrderCntType: 2, + MaxNumRefFrames: 1, + GapsInFrameNumValueAllowedFlag: true, + PicWidthInMbsMinus1: 21, + PicHeightInMapUnitsMinus1: 17, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + VUI: &SPS_VUI{ + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 30, + FixedFrameRateFlag: true, + }, + }, + }, + 352, + 288, + 15, + }, + { + "1280x720", + []byte{ + 0x67, 0x64, 0x00, 0x1f, 0xac, 0xd9, 0x40, 0x50, + 0x05, 0xbb, 0x01, 0x6c, 0x80, 0x00, 0x00, 0x03, + 0x00, 0x80, 0x00, 0x00, 0x1e, 0x07, 0x8c, 0x18, + 0xcb, + }, + SPS{ + ProfileIdc: 100, + LevelIdc: 31, + ChromeFormatIdc: 1, + Log2MaxPicOrderCntLsbMinus4: 2, + MaxNumRefFrames: 4, + PicWidthInMbsMinus1: 79, + PicHeightInMapUnitsMinus1: 44, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + VideoFullRangeFlag: true, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 60, + }, + BitstreamRestriction: &SPS_BitstreamRestriction{ + MotionVectorsOverPicBoundariesFlag: true, + Log2MaxMvLengthHorizontal: 11, + Log2MaxMvLengthVertical: 11, + MaxNumReorderFrames: 2, + MaxDecFrameBuffering: 4, + }, + }, + }, + 1280, + 720, + 30, + }, + { + "1920x1080 baseline", + []byte{ + 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, + 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, 0x20, + }, + SPS{ + ProfileIdc: 66, + ConstraintSet0Flag: true, + ConstraintSet1Flag: true, + LevelIdc: 40, + PicOrderCntType: 2, + MaxNumRefFrames: 3, + PicWidthInMbsMinus1: 119, + PicHeightInMapUnitsMinus1: 67, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + FrameCropping: &SPS_FrameCropping{ + BottomOffset: 4, + }, + VUI: &SPS_VUI{ + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 60, + }, + BitstreamRestriction: &SPS_BitstreamRestriction{ + MotionVectorsOverPicBoundariesFlag: true, + Log2MaxMvLengthHorizontal: 11, + Log2MaxMvLengthVertical: 11, + MaxDecFrameBuffering: 3, + }, + }, + }, + 1920, + 1080, + 30, + }, + { + "1920x1080 nvidia", + []byte{ + 0x67, 0x64, 0x00, 0x28, 0xac, 0xd9, 0x40, 0x78, + 0x02, 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, + 0xc6, 0x58, + }, + SPS{ + ProfileIdc: 100, + LevelIdc: 40, + ChromeFormatIdc: 1, + Log2MaxPicOrderCntLsbMinus4: 2, + MaxNumRefFrames: 4, + PicWidthInMbsMinus1: 119, + PicHeightInMapUnitsMinus1: 67, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + FrameCropping: &SPS_FrameCropping{ + BottomOffset: 4, + }, + VUI: &SPS_VUI{ + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 60, + }, + BitstreamRestriction: &SPS_BitstreamRestriction{ + MotionVectorsOverPicBoundariesFlag: true, + Log2MaxMvLengthHorizontal: 11, + Log2MaxMvLengthVertical: 11, + MaxNumReorderFrames: 2, + MaxDecFrameBuffering: 4, + }, + }, + }, + 1920, + 1080, + 30, + }, + { + "1920x1080", + []byte{ + 0x67, 0x64, 0x00, 0x29, 0xac, 0x13, 0x31, 0x40, + 0x78, 0x04, 0x47, 0xde, 0x03, 0xea, 0x02, 0x02, + 0x03, 0xe0, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, + 0x00, 0x06, 0x52, // 0x80, + }, + SPS{ + ProfileIdc: 100, + LevelIdc: 41, + ChromeFormatIdc: 1, + Log2MaxFrameNumMinus4: 8, + Log2MaxPicOrderCntLsbMinus4: 5, + MaxNumRefFrames: 4, + PicWidthInMbsMinus1: 119, + PicHeightInMapUnitsMinus1: 33, + Direct8x8InferenceFlag: true, + FrameCropping: &SPS_FrameCropping{ + BottomOffset: 2, + }, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + OverscanInfoPresentFlag: true, + OverscanAppropriateFlag: true, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + ChromaLocInfoPresentFlag: true, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 50, + FixedFrameRateFlag: true, + }, + PicStructPresentFlag: true, + }, + }, + 1920, + 1084, + 25, + }, + { + "hikvision", + []byte{103, 100, 0, 32, 172, 23, 42, 1, 64, 30, 104, 64, 0, 1, 194, 0, 0, 87, 228, 33}, + SPS{ + ProfileIdc: 100, + LevelIdc: 32, + ChromeFormatIdc: 1, + Log2MaxPicOrderCntLsbMinus4: 4, + MaxNumRefFrames: 1, + PicWidthInMbsMinus1: 79, + PicHeightInMapUnitsMinus1: 59, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + Log2MaxFrameNumMinus4: 10, + VUI: &SPS_VUI{ + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1800, + TimeScale: 90000, + FixedFrameRateFlag: true, + }, + }, + }, + 1280, + 960, + 25, + }, + { + "scaling matrix", + []byte{ + 103, 100, 0, 50, 173, 132, 1, 12, 32, 8, 97, 0, 67, 8, 2, + 24, 64, 16, 194, 0, 132, 59, 80, 20, 0, 90, 211, + 112, 16, 16, 20, 0, 0, 3, 0, 4, 0, 0, 3, 0, 162, 16, + }, + SPS{ + ProfileIdc: 100, + LevelIdc: 50, + ChromeFormatIdc: 1, + ScalingList4x4: [][]int32{ + { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }, + { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }, + { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }, + { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }, + { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }, + { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }, + }, + UseDefaultScalingMatrix4x4Flag: []bool{ + false, false, false, false, false, false, + }, + Log2MaxFrameNumMinus4: 6, + PicOrderCntType: 2, + MaxNumRefFrames: 1, + GapsInFrameNumValueAllowedFlag: true, + PicWidthInMbsMinus1: 159, + PicHeightInMapUnitsMinus1: 89, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + VUI: &SPS_VUI{ + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + VideoFullRangeFlag: true, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 40, + FixedFrameRateFlag: true, + }, + }, + }, + 2560, + 1440, + 20, + }, + { + "1920x1080 nvenc hrd", + []byte{ + 103, 100, 0, 42, 172, 44, 172, 7, + 128, 34, 126, 92, 5, 168, 8, 8, + 10, 0, 0, 7, 208, 0, 3, 169, + 129, 192, 0, 0, 76, 75, 0, 0, + 38, 37, 173, 222, 92, 20, + }, + SPS{ + ProfileIdc: 100, + LevelIdc: 42, + ChromeFormatIdc: 1, + Log2MaxFrameNumMinus4: 4, + Log2MaxPicOrderCntLsbMinus4: 4, + MaxNumRefFrames: 2, + PicWidthInMbsMinus1: 119, + PicHeightInMapUnitsMinus1: 67, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + FrameCropping: &SPS_FrameCropping{ + BottomOffset: 4, + }, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1000, + TimeScale: 120000, + FixedFrameRateFlag: true, + }, + NalHRD: &SPS_HRD{ + BitRateValueMinus1: []uint32{39061}, + CpbSizeValueMinus1: []uint32{156249}, + CbrFlag: []bool{true}, + InitialCpbRemovalDelayLengthMinus1: 23, + CpbRemovalDelayLengthMinus1: 15, + DpbOutputDelayLengthMinus1: 5, + TimeOffsetLength: 24, + }, + PicStructPresentFlag: true, + }, + }, + 1920, + 1080, + 60, + }, + { + "1920x1080 hikvision nal hrd + vcl hrd", + []byte{ + 103, 77, 0, 41, 154, 100, 3, 192, + 17, 63, 46, 2, 220, 4, 4, 5, + 0, 0, 3, 3, 232, 0, 0, 195, + 80, 232, 96, 0, 186, 180, 0, 2, + 234, 196, 187, 203, 141, 12, 0, 23, + 86, 128, 0, 93, 88, 151, 121, 112, + 160, + }, + SPS{ + ProfileIdc: 77, + LevelIdc: 41, + Log2MaxFrameNumMinus4: 5, + Log2MaxPicOrderCntLsbMinus4: 5, + MaxNumRefFrames: 1, + PicWidthInMbsMinus1: 119, + PicHeightInMapUnitsMinus1: 67, + FrameMbsOnlyFlag: true, + Direct8x8InferenceFlag: true, + FrameCropping: &SPS_FrameCropping{ + BottomOffset: 4, + }, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + VideoFullRangeFlag: true, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1000, + TimeScale: 50000, + FixedFrameRateFlag: true, + }, + NalHRD: &SPS_HRD{ + BitRateScale: 4, + CpbSizeScale: 3, + BitRateValueMinus1: []uint32{11948}, + CpbSizeValueMinus1: []uint32{95585}, + CbrFlag: []bool{false}, + InitialCpbRemovalDelayLengthMinus1: 23, + CpbRemovalDelayLengthMinus1: 15, + DpbOutputDelayLengthMinus1: 5, + TimeOffsetLength: 24, + }, + VclHRD: &SPS_HRD{ + BitRateScale: 4, + CpbSizeScale: 3, + BitRateValueMinus1: []uint32{11948}, + CpbSizeValueMinus1: []uint32{95585}, + CbrFlag: []bool{false}, + InitialCpbRemovalDelayLengthMinus1: 23, + CpbRemovalDelayLengthMinus1: 15, + DpbOutputDelayLengthMinus1: 5, + TimeOffsetLength: 24, + }, + PicStructPresentFlag: true, + }, + }, + 1920, + 1080, + 25, + }, + } { + t.Run(ca.name, func(t *testing.T) { + var sps SPS + err := sps.Unmarshal(ca.byts) + require.NoError(t, err) + require.Equal(t, ca.sps, sps) + require.Equal(t, ca.width, sps.Width()) + require.Equal(t, ca.height, sps.Height()) + require.Equal(t, ca.fps, sps.FPS()) + }) + } +} + +func BenchmarkSPSUnmarshal(b *testing.B) { + for i := 0; i < b.N; i++ { + var sps SPS + sps.Unmarshal([]byte{ + 103, 77, 0, 41, 154, 100, 3, 192, + 17, 63, 46, 2, 220, 4, 4, 5, + 0, 0, 3, 3, 232, 0, 0, 195, + 80, 232, 96, 0, 186, 180, 0, 2, + 234, 196, 187, 203, 141, 12, 0, 23, + 86, 128, 0, 93, 88, 151, 121, 112, + 160, + }) + } +} + +func FuzzSPSUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var sps SPS + sps.Unmarshal(b) + }) +} diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/002e276d0123e6698e29b86a6db8644720a23ad912d7be68bf441e186095f7fe b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/002e276d0123e6698e29b86a6db8644720a23ad912d7be68bf441e186095f7fe new file mode 100644 index 0000000..6dd36a2 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/002e276d0123e6698e29b86a6db8644720a23ad912d7be68bf441e186095f7fe @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x00\x00\x00\x00") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 new file mode 100644 index 0000000..7fd7a20 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/dad1340efc3fed8006eb91c7ec4be5cffca97bbe1c447ed47eda11adfd7ab0cc b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/dad1340efc3fed8006eb91c7ec4be5cffca97bbe1c447ed47eda11adfd7ab0cc new file mode 100644 index 0000000..3252f4a --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAVCCUnmarshal/dad1340efc3fed8006eb91c7ec4be5cffca97bbe1c447ed47eda11adfd7ab0cc @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x000\x00\x00") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/002e276d0123e6698e29b86a6db8644720a23ad912d7be68bf441e186095f7fe b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/002e276d0123e6698e29b86a6db8644720a23ad912d7be68bf441e186095f7fe new file mode 100644 index 0000000..6dd36a2 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/002e276d0123e6698e29b86a6db8644720a23ad912d7be68bf441e186095f7fe @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x00\x00\x00\x00") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/2ce2df4de457e581f3404dedd305e7f281b04eeb75cc2339d58c64d6618e8702 b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/2ce2df4de457e581f3404dedd305e7f281b04eeb75cc2339d58c64d6618e8702 new file mode 100644 index 0000000..40e3823 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/2ce2df4de457e581f3404dedd305e7f281b04eeb75cc2339d58c64d6618e8702 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x00\x000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/f0b7708a3a98029bd20ee500be4f0a4b1969c5386f513788f118019a7e9e32b1 b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/f0b7708a3a98029bd20ee500be4f0a4b1969c5386f513788f118019a7e9e32b1 new file mode 100644 index 0000000..2fc528c --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/f0b7708a3a98029bd20ee500be4f0a4b1969c5386f513788f118019a7e9e32b1 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x00\x00\x01") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/fb2cff69a3eec4b1a50ea017aa5604d9b3910ddfa989bdb6bc7323714fda66b3 b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/fb2cff69a3eec4b1a50ea017aa5604d9b3910ddfa989bdb6bc7323714fda66b3 new file mode 100644 index 0000000..d19fb07 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/fb2cff69a3eec4b1a50ea017aa5604d9b3910ddfa989bdb6bc7323714fda66b3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x00\x00\x01\x00\x00\x01") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/fb5317ecce56275a254428a8267b56951b5b6ec2fa924f1e8d8fcab394abc2d3 b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/fb5317ecce56275a254428a8267b56951b5b6ec2fa924f1e8d8fcab394abc2d3 new file mode 100644 index 0000000..3104422 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzAnnexBUnmarshal/fb5317ecce56275a254428a8267b56951b5b6ec2fa924f1e8d8fcab394abc2d3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x00\x00") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/1222d4cb572fa515ca7b8ba8dc649a0c711445e6307ee02a65b0a4322e758021 b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/1222d4cb572fa515ca7b8ba8dc649a0c711445e6307ee02a65b0a4322e758021 new file mode 100644 index 0000000..5f83259 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/1222d4cb572fa515ca7b8ba8dc649a0c711445e6307ee02a65b0a4322e758021 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("A0\x00\x0000") +uint64(122) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/1223ae83b4925a9f1ade3b85a3b44c94a8135edafbbd664bd8e2eca808ca5ebc b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/1223ae83b4925a9f1ade3b85a3b44c94a8135edafbbd664bd8e2eca808ca5ebc new file mode 100644 index 0000000..486c699 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/1223ae83b4925a9f1ade3b85a3b44c94a8135edafbbd664bd8e2eca808ca5ebc @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("'000\xdc10") +uint64(23) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/262c62a888c4d2e7f51c8ac2c37a8459445dd9279b725d7243c3341e8e5bc746 b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/262c62a888c4d2e7f51c8ac2c37a8459445dd9279b725d7243c3341e8e5bc746 new file mode 100644 index 0000000..793a6b8 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/262c62a888c4d2e7f51c8ac2c37a8459445dd9279b725d7243c3341e8e5bc746 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("A00\x0000") +uint64(122) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/3b9a2adc3e27d7bc69f2eac840715796c9540b4942476167f0b4db164b52ce56 b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/3b9a2adc3e27d7bc69f2eac840715796c9540b4942476167f0b4db164b52ce56 new file mode 100644 index 0000000..d6720e5 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/3b9a2adc3e27d7bc69f2eac840715796c9540b4942476167f0b4db164b52ce56 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("A\x0001\x000") +uint64(188) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/3cb3e1217d3d42a93448aba8877b465cf77c9425c65d3e2cf6f314d6cbd0050e b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/3cb3e1217d3d42a93448aba8877b465cf77c9425c65d3e2cf6f314d6cbd0050e new file mode 100644 index 0000000..f754490 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/3cb3e1217d3d42a93448aba8877b465cf77c9425c65d3e2cf6f314d6cbd0050e @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("A00000") +uint64(122) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/676f114d18955cd69fb374e86badcea42b216770d5fc4629d036eb04cfef9ae7 b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/676f114d18955cd69fb374e86badcea42b216770d5fc4629d036eb04cfef9ae7 new file mode 100644 index 0000000..84f7c33 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/676f114d18955cd69fb374e86badcea42b216770d5fc4629d036eb04cfef9ae7 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("%") +uint64(14) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/b1d032bee609ec2a117b65530fb6f91bc8a0f066193f73e2d2fc35b282b88839 b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/b1d032bee609ec2a117b65530fb6f91bc8a0f066193f73e2d2fc35b282b88839 new file mode 100644 index 0000000..798dfde --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/b1d032bee609ec2a117b65530fb6f91bc8a0f066193f73e2d2fc35b282b88839 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("\x01\f") +uint64(60) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/be0df8dc8259c6db1f7fe9c07d133559251d8a4697da418218cbaf077650f873 b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/be0df8dc8259c6db1f7fe9c07d133559251d8a4697da418218cbaf077650f873 new file mode 100644 index 0000000..2df246f --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/be0df8dc8259c6db1f7fe9c07d133559251d8a4697da418218cbaf077650f873 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("A\x00\x00\x0000") +uint64(70) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/c43c2cabc7b2a36f19a4717161402f7e12129cbe32cf765847b4377867ebc9b5 b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/c43c2cabc7b2a36f19a4717161402f7e12129cbe32cf765847b4377867ebc9b5 new file mode 100644 index 0000000..1c0b9c7 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/c43c2cabc7b2a36f19a4717161402f7e12129cbe32cf765847b4377867ebc9b5 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("A\x0001B0") +uint64(188) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/c624d6d8804714db4b342d59c9e32f26eec2d69bb3aff1746a521786027b732c b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/c624d6d8804714db4b342d59c9e32f26eec2d69bb3aff1746a521786027b732c new file mode 100644 index 0000000..ce8b813 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzDTSExtractor/c624d6d8804714db4b342d59c9e32f26eec2d69bb3aff1746a521786027b732c @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("'000%9000") +uint64(23) diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/01288c9efae1307be2542dbb019dc1ad59d072065ef32935d09b5de28f5d77e0 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/01288c9efae1307be2542dbb019dc1ad59d072065ef32935d09b5de28f5d77e0 new file mode 100644 index 0000000..23ff647 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/01288c9efae1307be2542dbb019dc1ad59d072065ef32935d09b5de28f5d77e0 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 new file mode 100644 index 0000000..7fd7a20 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0af83188e9b1670a268e5a56d5527be7cf004a2b2c42d9299813c7dc88e9bbd2 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0af83188e9b1670a268e5a56d5527be7cf004a2b2c42d9299813c7dc88e9bbd2 new file mode 100644 index 0000000..092d4ef --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0af83188e9b1670a268e5a56d5527be7cf004a2b2c42d9299813c7dc88e9bbd2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\xf31Y08\xf7000000000\xd7") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0be6d2f66de27526159e6e47e60a6c7775cdab6db0e3295029427b18ae2ae747 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0be6d2f66de27526159e6e47e60a6c7775cdab6db0e3295029427b18ae2ae747 new file mode 100644 index 0000000..bab326f --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0be6d2f66de27526159e6e47e60a6c7775cdab6db0e3295029427b18ae2ae747 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A\xff2\xff0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0d87aecf7d4f3648538400e4f1a3ffeacee9738e4c3408a600c24a80de240bac b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0d87aecf7d4f3648538400e4f1a3ffeacee9738e4c3408a600c24a80de240bac new file mode 100644 index 0000000..7aa0164 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0d87aecf7d4f3648538400e4f1a3ffeacee9738e4c3408a600c24a80de240bac @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000B19") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0fb8db11e671e6fa6be3b8c7dbc448244bfd66bb4f85d90722653942fdcb60e4 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0fb8db11e671e6fa6be3b8c7dbc448244bfd66bb4f85d90722653942fdcb60e4 new file mode 100644 index 0000000..648feee --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/0fb8db11e671e6fa6be3b8c7dbc448244bfd66bb4f85d90722653942fdcb60e4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z0010") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/139370ab0793372c99ea8cd88ff2ffdd68dd18d6ca5b1074722884e7d4e4c6a2 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/139370ab0793372c99ea8cd88ff2ffdd68dd18d6ca5b1074722884e7d4e4c6a2 new file mode 100644 index 0000000..4795b88 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/139370ab0793372c99ea8cd88ff2ffdd68dd18d6ca5b1074722884e7d4e4c6a2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf60000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/13b2a92583c8d6ab7b595428ffeb9d6cdb51781f98d2cda015995753a7f716e9 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/13b2a92583c8d6ab7b595428ffeb9d6cdb51781f98d2cda015995753a7f716e9 new file mode 100644 index 0000000..ee7aa5f --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/13b2a92583c8d6ab7b595428ffeb9d6cdb51781f98d2cda015995753a7f716e9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000772.B001") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/1c8bbab9d5312be1b60753343a15d1ea8c4a7baf8b95bdad79903d47a2af568f b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/1c8bbab9d5312be1b60753343a15d1ea8c4a7baf8b95bdad79903d47a2af568f new file mode 100644 index 0000000..40dd932 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/1c8bbab9d5312be1b60753343a15d1ea8c4a7baf8b95bdad79903d47a2af568f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z00002") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/1f21b9a6112f67bc666a661e23922b7370f4b03e776cd4710bb197715d05e106 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/1f21b9a6112f67bc666a661e23922b7370f4b03e776cd4710bb197715d05e106 new file mode 100644 index 0000000..ea01a67 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/1f21b9a6112f67bc666a661e23922b7370f4b03e776cd4710bb197715d05e106 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf6A") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/20599bffc63db3162d9e18b01d25c4d2b9bc91621d5107b91a9ae3ee676b3b69 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/20599bffc63db3162d9e18b01d25c4d2b9bc91621d5107b91a9ae3ee676b3b69 new file mode 100644 index 0000000..dcd59c7 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/20599bffc63db3162d9e18b01d25c4d2b9bc91621d5107b91a9ae3ee676b3b69 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z00$A0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/2113482bfc82431ab4769ff2256411e7c7e865bf4d2fa2417cf15621a0aa6c68 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/2113482bfc82431ab4769ff2256411e7c7e865bf4d2fa2417cf15621a0aa6c68 new file mode 100644 index 0000000..06ab239 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/2113482bfc82431ab4769ff2256411e7c7e865bf4d2fa2417cf15621a0aa6c68 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000017Y1") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/24ee50d0b17798d827100581c3939268fda76b1a29a64b67fa65580babb9f310 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/24ee50d0b17798d827100581c3939268fda76b1a29a64b67fa65580babb9f310 new file mode 100644 index 0000000..ab64a37 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/24ee50d0b17798d827100581c3939268fda76b1a29a64b67fa65580babb9f310 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A10") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/277b8e88b43c52e9676253793c9f06a763063a089bb7c6f5486331ca9426a898 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/277b8e88b43c52e9676253793c9f06a763063a089bb7c6f5486331ca9426a898 new file mode 100644 index 0000000..bf239ee --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/277b8e88b43c52e9676253793c9f06a763063a089bb7c6f5486331ca9426a898 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000777Z\x0e2\x0e000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/28f06b087ff4d71f788eb50d329a844bc5b06ba24530daafe2fb23707ec73f56 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/28f06b087ff4d71f788eb50d329a844bc5b06ba24530daafe2fb23707ec73f56 new file mode 100644 index 0000000..a72a66e --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/28f06b087ff4d71f788eb50d329a844bc5b06ba24530daafe2fb23707ec73f56 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A\xff0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/2ab5ed4810474c02d699123edece8150d02d0f28a7f580c26847d3e6eae19f8e b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/2ab5ed4810474c02d699123edece8150d02d0f28a7f580c26847d3e6eae19f8e new file mode 100644 index 0000000..b3ecbfc --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/2ab5ed4810474c02d699123edece8150d02d0f28a7f580c26847d3e6eae19f8e @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000%0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/368b44f70bb50f9d3c1bc1c5bb714ab20766839e07e11d6e1a2e92d8c70a60a2 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/368b44f70bb50f9d3c1bc1c5bb714ab20766839e07e11d6e1a2e92d8c70a60a2 new file mode 100644 index 0000000..cf007b0 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/368b44f70bb50f9d3c1bc1c5bb714ab20766839e07e11d6e1a2e92d8c70a60a2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z007A") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/3b0f149b796c531a8ae4efdafde531d4280c980c2676ab030e7163f4d618869b b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/3b0f149b796c531a8ae4efdafde531d4280c980c2676ab030e7163f4d618869b new file mode 100644 index 0000000..4d95d66 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/3b0f149b796c531a8ae4efdafde531d4280c980c2676ab030e7163f4d618869b @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000017Y0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/41d70545c8a84390058018aded44531acaea8e1d19f18bd99730de3df81dc2b4 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/41d70545c8a84390058018aded44531acaea8e1d19f18bd99730de3df81dc2b4 new file mode 100644 index 0000000..474090b --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/41d70545c8a84390058018aded44531acaea8e1d19f18bd99730de3df81dc2b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000177A000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/43b8a2672cd59b21a57bdb05a60ccb56dc5bc1db0bae2a12a115443d39d93c6e b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/43b8a2672cd59b21a57bdb05a60ccb56dc5bc1db0bae2a12a115443d39d93c6e new file mode 100644 index 0000000..a809978 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/43b8a2672cd59b21a57bdb05a60ccb56dc5bc1db0bae2a12a115443d39d93c6e @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z007B000000771B$00") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/452e524b55a29f1fe6f448570d1373ce2a6d116dfaa39c1ee11befed0cd82e61 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/452e524b55a29f1fe6f448570d1373ce2a6d116dfaa39c1ee11befed0cd82e61 new file mode 100644 index 0000000..2a33d83 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/452e524b55a29f1fe6f448570d1373ce2a6d116dfaa39c1ee11befed0cd82e61 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000\xff2") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/4a9f730d882605508b45b71ce9339664c952ce93ff20e89aee08b4c432aab3a7 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/4a9f730d882605508b45b71ce9339664c952ce93ff20e89aee08b4c432aab3a7 new file mode 100644 index 0000000..3ce7296 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/4a9f730d882605508b45b71ce9339664c952ce93ff20e89aee08b4c432aab3a7 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000%A") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/50b649fe52d479d41725cdc8c8c532ea89b2ae61816b13f86ea486572215e81d b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/50b649fe52d479d41725cdc8c8c532ea89b2ae61816b13f86ea486572215e81d new file mode 100644 index 0000000..a2806e2 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/50b649fe52d479d41725cdc8c8c532ea89b2ae61816b13f86ea486572215e81d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A\xff2") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/5f47d452162ac208dcb3afd590dd27179dd0760a53aa6ee2a1ea2cb7a42ce506 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/5f47d452162ac208dcb3afd590dd27179dd0760a53aa6ee2a1ea2cb7a42ce506 new file mode 100644 index 0000000..63f6f5a --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/5f47d452162ac208dcb3afd590dd27179dd0760a53aa6ee2a1ea2cb7a42ce506 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf6017") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/641f6b7efc39fdef370a2bcc5038559d6ae38e23c23db2a0d82eca058e125166 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/641f6b7efc39fdef370a2bcc5038559d6ae38e23c23db2a0d82eca058e125166 new file mode 100644 index 0000000..94335c2 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/641f6b7efc39fdef370a2bcc5038559d6ae38e23c23db2a0d82eca058e125166 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z0017") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d new file mode 100644 index 0000000..959401e --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/67be690eb46ab3e15c9e157d0ef76b78172fc99dddd4299e86d13b79b984cb9e b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/67be690eb46ab3e15c9e157d0ef76b78172fc99dddd4299e86d13b79b984cb9e new file mode 100644 index 0000000..b6a3810 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/67be690eb46ab3e15c9e157d0ef76b78172fc99dddd4299e86d13b79b984cb9e @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf61") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/6842f656bc0b9621f03f7e239abd268cf254b3a983a6b7379293611f56ebe74d b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/6842f656bc0b9621f03f7e239abd268cf254b3a983a6b7379293611f56ebe74d new file mode 100644 index 0000000..faa3aa4 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/6842f656bc0b9621f03f7e239abd268cf254b3a983a6b7379293611f56ebe74d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00001\x17\x0000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/6bbb3f597bab8e6e67e8cbd2e1d77b9ed0ab99094562759738971883b12b5ff5 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/6bbb3f597bab8e6e67e8cbd2e1d77b9ed0ab99094562759738971883b12b5ff5 new file mode 100644 index 0000000..8000885 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/6bbb3f597bab8e6e67e8cbd2e1d77b9ed0ab99094562759738971883b12b5ff5 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A\xff0\xff0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/706f49c5b21047ed26fe721ad92e13ad3f99e6ceec8052bfecbee3596422d48a b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/706f49c5b21047ed26fe721ad92e13ad3f99e6ceec8052bfecbee3596422d48a new file mode 100644 index 0000000..1911a8c --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/706f49c5b21047ed26fe721ad92e13ad3f99e6ceec8052bfecbee3596422d48a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z002") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/7fc443da4b835c24546da2a593a050d7f842605f017d5e43a0d31b35e66f28fe b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/7fc443da4b835c24546da2a593a050d7f842605f017d5e43a0d31b35e66f28fe new file mode 100644 index 0000000..7488c6e --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/7fc443da4b835c24546da2a593a050d7f842605f017d5e43a0d31b35e66f28fe @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000X") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/829fde2929450193ab3c21246f4b66a05d5841569f9c5f1a4f19d081050b3747 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/829fde2929450193ab3c21246f4b66a05d5841569f9c5f1a4f19d081050b3747 new file mode 100644 index 0000000..15b5162 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/829fde2929450193ab3c21246f4b66a05d5841569f9c5f1a4f19d081050b3747 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000072") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/8a25aa52c31a312b339dd3f55a2d14c8d4dc2d9a4726c8f7806df12bda102326 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/8a25aa52c31a312b339dd3f55a2d14c8d4dc2d9a4726c8f7806df12bda102326 new file mode 100644 index 0000000..2a95651 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/8a25aa52c31a312b339dd3f55a2d14c8d4dc2d9a4726c8f7806df12bda102326 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000017\xf60") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/9095bee7552e53e949500f0cdf552d94e12df5f835eb9e06e6815957dc2d5fb2 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/9095bee7552e53e949500f0cdf552d94e12df5f835eb9e06e6815957dc2d5fb2 new file mode 100644 index 0000000..e65369c --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/9095bee7552e53e949500f0cdf552d94e12df5f835eb9e06e6815957dc2d5fb2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000017\xf61") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/9bed7ad10156a846b730b66e8f008894ef1b0398cbc1d3d72966d26bed74234b b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/9bed7ad10156a846b730b66e8f008894ef1b0398cbc1d3d72966d26bed74234b new file mode 100644 index 0000000..a79f7d2 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/9bed7ad10156a846b730b66e8f008894ef1b0398cbc1d3d72966d26bed74234b @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000017Y00") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a068243fd4565e08237d9e8a45cb1d387b0a5b3ad6f2cdd861badd887f810b45 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a068243fd4565e08237d9e8a45cb1d387b0a5b3ad6f2cdd861badd887f810b45 new file mode 100644 index 0000000..555f935 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a068243fd4565e08237d9e8a45cb1d387b0a5b3ad6f2cdd861badd887f810b45 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\xf310\xff00007000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a1f57473c1cf3a081b94f3b4a38798ea2c723e1d88ab5fb6e144320b2314d6fe b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a1f57473c1cf3a081b94f3b4a38798ea2c723e1d88ab5fb6e144320b2314d6fe new file mode 100644 index 0000000..8d7e4f0 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a1f57473c1cf3a081b94f3b4a38798ea2c723e1d88ab5fb6e144320b2314d6fe @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf68") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a4c914c327ff2fa03d0bd9650ec9424c1b3b183dea47cea96cb89b3f9fd36986 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a4c914c327ff2fa03d0bd9650ec9424c1b3b183dea47cea96cb89b3f9fd36986 new file mode 100644 index 0000000..770e9cb --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a4c914c327ff2fa03d0bd9650ec9424c1b3b183dea47cea96cb89b3f9fd36986 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000\xff\xff\xff0a1000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a6f6a9bf667499515f0c228a8853d53517cfe49f51dc89f688d445d1265e5d7d b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a6f6a9bf667499515f0c228a8853d53517cfe49f51dc89f688d445d1265e5d7d new file mode 100644 index 0000000..d5ff4cb --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/a6f6a9bf667499515f0c228a8853d53517cfe49f51dc89f688d445d1265e5d7d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A72") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/ac3507052c142f5628eada795764e75469e2585518502b400bfee0afd89b5d15 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/ac3507052c142f5628eada795764e75469e2585518502b400bfee0afd89b5d15 new file mode 100644 index 0000000..27a2027 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/ac3507052c142f5628eada795764e75469e2585518502b400bfee0afd89b5d15 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A\xff2&0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/ac47ca534e00877b146ef2ed9e7162b114412251df6e662ab63a07b1009b5393 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/ac47ca534e00877b146ef2ed9e7162b114412251df6e662ab63a07b1009b5393 new file mode 100644 index 0000000..724b773 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/ac47ca534e00877b146ef2ed9e7162b114412251df6e662ab63a07b1009b5393 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\xf310\xff00007") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/b01759614e8bc591068e73dfdf57dca91dd1a9512911d96d203aa6d135193c07 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/b01759614e8bc591068e73dfdf57dca91dd1a9512911d96d203aa6d135193c07 new file mode 100644 index 0000000..a2eb5ae --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/b01759614e8bc591068e73dfdf57dca91dd1a9512911d96d203aa6d135193c07 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A 0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/b2d4d630d9e57dd4ec6030f3c68480c0e27cc08808b74a1f30d2a39126ad9576 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/b2d4d630d9e57dd4ec6030f3c68480c0e27cc08808b74a1f30d2a39126ad9576 new file mode 100644 index 0000000..0935648 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/b2d4d630d9e57dd4ec6030f3c68480c0e27cc08808b74a1f30d2a39126ad9576 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf67") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/bb0b3e83bb11594f77b10e16cacabdc3b33e8bb1c3090e8da7bf331caf899fad b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/bb0b3e83bb11594f77b10e16cacabdc3b33e8bb1c3090e8da7bf331caf899fad new file mode 100644 index 0000000..b7d74a8 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/bb0b3e83bb11594f77b10e16cacabdc3b33e8bb1c3090e8da7bf331caf899fad @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000177Z100") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/be193709a33faf69c6616e5cb6e9222c1a8c685c578eabe92ddab77a56fbda91 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/be193709a33faf69c6616e5cb6e9222c1a8c685c578eabe92ddab77a56fbda91 new file mode 100644 index 0000000..933fc99 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/be193709a33faf69c6616e5cb6e9222c1a8c685c578eabe92ddab77a56fbda91 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\xf30") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c0cf8af892101f975a635da53f855490a6d93cbb08be7a1f70d7b7f0a237763c b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c0cf8af892101f975a635da53f855490a6d93cbb08be7a1f70d7b7f0a237763c new file mode 100644 index 0000000..7444d5e --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c0cf8af892101f975a635da53f855490a6d93cbb08be7a1f70d7b7f0a237763c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000A78X0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c17af5c152fb10506043072ba67c34539a4cd854b3de89394f8049e27672f7d5 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c17af5c152fb10506043072ba67c34539a4cd854b3de89394f8049e27672f7d5 new file mode 100644 index 0000000..b406413 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c17af5c152fb10506043072ba67c34539a4cd854b3de89394f8049e27672f7d5 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf60") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c1faaebf2f51b9bd7ef64114318381ec19d9aa59a1fff4952c4b6aeb741ba02d b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c1faaebf2f51b9bd7ef64114318381ec19d9aa59a1fff4952c4b6aeb741ba02d new file mode 100644 index 0000000..f42b655 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c1faaebf2f51b9bd7ef64114318381ec19d9aa59a1fff4952c4b6aeb741ba02d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z00d") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c522f0b5427ed0a18a6b692e061280d14af17e8b0075043f1c822533b41ef9ff b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c522f0b5427ed0a18a6b692e061280d14af17e8b0075043f1c822533b41ef9ff new file mode 100644 index 0000000..e85f34f --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/c522f0b5427ed0a18a6b692e061280d14af17e8b0075043f1c822533b41ef9ff @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000070") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/cad20d5efdb493f9d3c53736dde3d97fcda3593310c32dcd8cb6981e36d54538 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/cad20d5efdb493f9d3c53736dde3d97fcda3593310c32dcd8cb6981e36d54538 new file mode 100644 index 0000000..01dfd3f --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/cad20d5efdb493f9d3c53736dde3d97fcda3593310c32dcd8cb6981e36d54538 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000\xff0A0000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/cf3cad2c9f63327a060ace07881bdc20e3f5c473749397a8c84bd168f9ac799d b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/cf3cad2c9f63327a060ace07881bdc20e3f5c473749397a8c84bd168f9ac799d new file mode 100644 index 0000000..fdad433 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/cf3cad2c9f63327a060ace07881bdc20e3f5c473749397a8c84bd168f9ac799d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\xf31") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/d78a814513f866a302c16d387777290f3d60da89055d4df8529dcf6afad9beca b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/d78a814513f866a302c16d387777290f3d60da89055d4df8529dcf6afad9beca new file mode 100644 index 0000000..cda2805 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/d78a814513f866a302c16d387777290f3d60da89055d4df8529dcf6afad9beca @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\xf6\xf60000000001") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/db1c54995fe7b8d0e9628dd1822671be4ac721f297e14dcc4a7900d15c7fff7f b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/db1c54995fe7b8d0e9628dd1822671be4ac721f297e14dcc4a7900d15c7fff7f new file mode 100644 index 0000000..fe874a1 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/db1c54995fe7b8d0e9628dd1822671be4ac721f297e14dcc4a7900d15c7fff7f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00007\xb6\xf6018") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e0636a49e255b40346c2f44bacf15e50903f836d7c550504188c55ab37cfde4f b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e0636a49e255b40346c2f44bacf15e50903f836d7c550504188c55ab37cfde4f new file mode 100644 index 0000000..bfeaab6 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e0636a49e255b40346c2f44bacf15e50903f836d7c550504188c55ab37cfde4f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A\xff20") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e20f6e43de3d954ca5b920a4b039b822e97cd317c07fc97337da68f023d563a2 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e20f6e43de3d954ca5b920a4b039b822e97cd317c07fc97337da68f023d563a2 new file mode 100644 index 0000000..84b31fd --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e20f6e43de3d954ca5b920a4b039b822e97cd317c07fc97337da68f023d563a2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000017\xf6") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e562907a18f4186251820f36d0278039659036029592195e8a9acf94ffd70546 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e562907a18f4186251820f36d0278039659036029592195e8a9acf94ffd70546 new file mode 100644 index 0000000..fff6fdd --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e562907a18f4186251820f36d0278039659036029592195e8a9acf94ffd70546 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e9918f5c3ff4ccead70a7bfe83479d6e5eba77143048cca05f00e56a244a8066 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e9918f5c3ff4ccead70a7bfe83479d6e5eba77143048cca05f00e56a244a8066 new file mode 100644 index 0000000..5b09b3f --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/e9918f5c3ff4ccead70a7bfe83479d6e5eba77143048cca05f00e56a244a8066 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000%\xf6") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f235dbad7715685b1e83484df230fdfbb9ce3abceb662ee5e714a6e1d94ec0ac b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f235dbad7715685b1e83484df230fdfbb9ce3abceb662ee5e714a6e1d94ec0ac new file mode 100644 index 0000000..aefb778 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f235dbad7715685b1e83484df230fdfbb9ce3abceb662ee5e714a6e1d94ec0ac @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\xf6\xf60\xf6000110") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 new file mode 100644 index 0000000..a389d3c --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f351a5a9537462ce1b8d69398f3cfa98589a431137e9dc72ec5a8bb5cc4cd5da b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f351a5a9537462ce1b8d69398f3cfa98589a431137e9dc72ec5a8bb5cc4cd5da new file mode 100644 index 0000000..524e269 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/f351a5a9537462ce1b8d69398f3cfa98589a431137e9dc72ec5a8bb5cc4cd5da @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0z00$002") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/fc7904c804b00a74ab63bacd56f2ebaa77ed1632549d98dd78ee0348f68554b3 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/fc7904c804b00a74ab63bacd56f2ebaa77ed1632549d98dd78ee0348f68554b3 new file mode 100644 index 0000000..8356152 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/fc7904c804b00a74ab63bacd56f2ebaa77ed1632549d98dd78ee0348f68554b3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000A\xff2Z0") diff --git a/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/feba85bf0ea4d5f2e9ba1aca9adc81513ebf3a55d8a8a053ddb5cf87f9f98524 b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/feba85bf0ea4d5f2e9ba1aca9adc81513ebf3a55d8a8a053ddb5cf87f9f98524 new file mode 100644 index 0000000..6feeb59 --- /dev/null +++ b/pkg/codecs/h264/testdata/fuzz/FuzzSPSUnmarshal/feba85bf0ea4d5f2e9ba1aca9adc81513ebf3a55d8a8a053ddb5cf87f9f98524 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000017$") diff --git a/pkg/codecs/h265/dts_extractor.go b/pkg/codecs/h265/dts_extractor.go new file mode 100644 index 0000000..1772b16 --- /dev/null +++ b/pkg/codecs/h265/dts_extractor.go @@ -0,0 +1,242 @@ +package h265 + +import ( + "fmt" + "time" + + "github.com/bluenviron/mediabase/pkg/bits" + "github.com/bluenviron/mediabase/pkg/codecs/h264" +) + +func getPictureOrderCount(buf []byte, sps *SPS, pps *PPS) (uint32, uint32, error) { + if len(buf) < 12 { + return 0, 0, fmt.Errorf("not enough bits") + } + + buf = h264.EmulationPreventionRemove(buf[:12]) + + typ := NALUType((buf[0] >> 1) & 0b111111) + + buf = buf[2:] + pos := 0 + + firstSliceSegmentInPicFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return 0, 0, err + } + + if !firstSliceSegmentInPicFlag { + return 0, 0, fmt.Errorf("first_slice_segment_in_pic_flag = 0 is not supported") + } + + if typ >= NALUType_BLA_W_LP && typ <= NALUType_RSV_IRAP_VCL23 { + _, err := bits.ReadFlag(buf, &pos) // no_output_of_prior_pics_flag + if err != nil { + return 0, 0, err + } + } + + _, err = bits.ReadGolombUnsigned(buf, &pos) // slice_pic_parameter_set_id + if err != nil { + return 0, 0, err + } + + if pps.NumExtraSliceHeaderBits > 0 { + err := bits.HasSpace(buf, pos, int(pps.NumExtraSliceHeaderBits)) + if err != nil { + return 0, 0, err + } + pos += int(pps.NumExtraSliceHeaderBits) + } + + sliceType, err := bits.ReadGolombUnsigned(buf, &pos) // slice_type + if err != nil { + return 0, 0, err + } + + if pps.OutputFlagPresentFlag { + _, err := bits.ReadFlag(buf, &pos) // pic_output_flag + if err != nil { + return 0, 0, err + } + } + + if sps.SeparateColourPlaneFlag { + _, err := bits.ReadBits(buf, &pos, 2) // colour_plane_id + if err != nil { + return 0, 0, err + } + } + + picOrderCntLsb, err := bits.ReadBits(buf, &pos, int(sps.Log2MaxPicOrderCntLsbMinus4+4)) + if err != nil { + return 0, 0, err + } + + shortTermRefPicSetSpsFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return 0, 0, err + } + + if shortTermRefPicSetSpsFlag { + return 0, 0, fmt.Errorf("short_term_ref_pic_set_sps_flag = true is not supported") + } + + var rps SPS_ShortTermRefPicSet + err = rps.unmarshal(buf, &pos, uint32(len(sps.ShortTermRefPicSets)), uint32(len(sps.ShortTermRefPicSets)), nil) + if err != nil { + return 0, 0, err + } + + var v uint32 + + if sliceType == 0 { // B-frame + if typ == NALUType_TRAIL_N || typ == NALUType_RASL_N { + v = sps.MaxNumReorderPics[0] - uint32(len(rps.DeltaPocS1Minus1)) + } else if typ == NALUType_TRAIL_R || typ == NALUType_RASL_R { + if len(rps.DeltaPocS0Minus1) == 0 { + return 0, 0, fmt.Errorf("invalid delta_poc_s0_minus1") + } + v = rps.DeltaPocS0Minus1[0] + sps.MaxNumReorderPics[0] - 1 + } + } else { // I or P-frame + if len(rps.DeltaPocS0Minus1) == 0 { + return 0, 0, fmt.Errorf("invalid delta_poc_s0_minus1") + } + v = rps.DeltaPocS0Minus1[0] + sps.MaxNumReorderPics[0] + } + + dtsPOC := uint32(picOrderCntLsb) - v + dtsPOC &= ((1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 4)) - 1) + + return uint32(picOrderCntLsb), dtsPOC, nil +} + +func findPictureOrderCount(au [][]byte, sps *SPS, pps *PPS) (uint32, uint32, error) { + for _, nalu := range au { + typ := NALUType((nalu[0] >> 1) & 0b111111) + switch typ { + case NALUType_TRAIL_N, NALUType_TRAIL_R, NALUType_CRA_NUT, NALUType_RASL_N, NALUType_RASL_R: + poc, dtsPOC, err := getPictureOrderCount(nalu, sps, pps) + if err != nil { + return 0, 0, err + } + return poc, dtsPOC, nil + } + } + return 0, 0, fmt.Errorf("POC not found") +} + +func getPictureOrderCountDiff(poc1 uint32, poc2 uint32, sps *SPS) int32 { + diff := int32(poc1) - int32(poc2) + switch { + case diff < -((1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 3)) - 1): + diff += (1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 4)) + + case diff > ((1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 3)) - 1): + diff -= (1 << (sps.Log2MaxPicOrderCntLsbMinus4 + 4)) + } + return diff +} + +// DTSExtractor allows to extract DTS from PTS. +type DTSExtractor struct { + spsp *SPS + ppsp *PPS + prevDTSFilled bool + prevDTS time.Duration +} + +// NewDTSExtractor allocates a DTSExtractor. +func NewDTSExtractor() *DTSExtractor { + return &DTSExtractor{} +} + +func (d *DTSExtractor) extractInner(au [][]byte, pts time.Duration) (time.Duration, error) { + idrPresent := false + + for _, nalu := range au { + typ := NALUType((nalu[0] >> 1) & 0b111111) + + switch typ { + case NALUType_SPS_NUT: + var spsp SPS + err := spsp.Unmarshal(nalu) + if err != nil { + return 0, fmt.Errorf("invalid SPS: %v", err) + } + d.spsp = &spsp + + case NALUType_PPS_NUT: + var ppsp PPS + err := ppsp.Unmarshal(nalu) + if err != nil { + return 0, fmt.Errorf("invalid PPS: %v", err) + } + d.ppsp = &ppsp + + case NALUType_IDR_W_RADL, NALUType_IDR_N_LP: + idrPresent = true + } + } + + if d.spsp == nil { + return 0, fmt.Errorf("SPS not received yet") + } + + if d.ppsp == nil { + return 0, fmt.Errorf("PPS not received yet") + } + + if len(d.spsp.MaxNumReorderPics) != 1 || d.spsp.MaxNumReorderPics[0] == 0 { + return pts, nil + } + + if d.spsp.VUI == nil || d.spsp.VUI.TimingInfo == nil { + return pts, nil + } + + var poc uint32 + var dtsPOC uint32 + + if idrPresent { + poc = 0 + dtsPOC = poc - 2 + dtsPOC &= ((1 << (d.spsp.Log2MaxPicOrderCntLsbMinus4 + 4)) - 1) + } else { + var err error + poc, dtsPOC, err = findPictureOrderCount(au, d.spsp, d.ppsp) + if err != nil { + return 0, err + } + } + + pocDiff := getPictureOrderCountDiff(poc, dtsPOC, d.spsp) + timeDiff := time.Duration(pocDiff) * time.Second * + time.Duration(d.spsp.VUI.TimingInfo.NumUnitsInTick) / time.Duration(d.spsp.VUI.TimingInfo.TimeScale) + dts := pts - timeDiff + + return dts, nil +} + +// Extract extracts the DTS of a access unit. +func (d *DTSExtractor) Extract(au [][]byte, pts time.Duration) (time.Duration, error) { + dts, err := d.extractInner(au, pts) + if err != nil { + return 0, err + } + + if dts > pts { + return 0, fmt.Errorf("DTS is greater than PTS") + } + + if d.prevDTSFilled && dts <= d.prevDTS { + return 0, fmt.Errorf("DTS is not monotonically increasing, was %v, now is %v", + d.prevDTS, dts) + } + + d.prevDTSFilled = true + d.prevDTS = dts + + return dts, err +} diff --git a/pkg/codecs/h265/dts_extractor_test.go b/pkg/codecs/h265/dts_extractor_test.go new file mode 100644 index 0000000..bd3e0d2 --- /dev/null +++ b/pkg/codecs/h265/dts_extractor_test.go @@ -0,0 +1,84 @@ +//go:build go1.18 +// +build go1.18 + +package h265 + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestDTSExtractor(t *testing.T) { + type sequenceSample struct { + nalus [][]byte + pts time.Duration + dts time.Duration + } + + for _, ca := range []struct { + name string + sequence []sequenceSample + }{ + { + "no timing info", + []sequenceSample{ + { + [][]byte{ + { // SPS + 0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 0x00, 0x03, + 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 0x88, 0x7d, + 0xb6, 0x71, 0x8b, 0x92, 0x44, 0x80, 0x53, 0x88, + 0x88, 0x92, 0xcf, 0x24, 0xa6, 0x92, 0x72, 0xc9, + 0x12, 0x49, 0x22, 0xdc, 0x91, 0xaa, 0x48, 0xfc, + 0xa2, 0x23, 0xff, 0x00, 0x01, 0x00, 0x01, 0x6a, + 0x02, 0x02, 0x02, 0x01, + }, + { // PPS + 0x44, 0x01, 0xc0, 0x25, 0x2f, 0x05, 0x32, 0x40, + }, + { + byte(NALUType_CRA_NUT) << 1, + }, + }, + 1 * time.Second, + 1 * time.Second, + }, + }, + }, + } { + t.Run(ca.name, func(t *testing.T) { + ex := NewDTSExtractor() + for _, sample := range ca.sequence { + dts, err := ex.Extract(sample.nalus, sample.pts) + require.NoError(t, err) + require.Equal(t, sample.dts, dts) + } + }) + } +} + +func FuzzDTSExtractor(f *testing.F) { + sps := []byte{ + 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, + 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x10, 0xe5, + 0x96, 0x66, 0x69, 0x24, 0xca, 0xe0, 0x10, 0x00, + 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x01, + 0xe0, 0x80, + } + + pps := []byte{ + 0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62, 0x40, + } + + ex := NewDTSExtractor() + f.Fuzz(func(t *testing.T, b []byte, p uint64) { + if len(b) < 1 { + return + } + ex.Extract([][]byte{sps, pps, b}, time.Duration(p)) + }) +} diff --git a/pkg/codecs/h265/h265.go b/pkg/codecs/h265/h265.go new file mode 100644 index 0000000..6e06e5c --- /dev/null +++ b/pkg/codecs/h265/h265.go @@ -0,0 +1,11 @@ +// Package h265 contains utilities to work with the H265 codec. +package h265 + +const ( + // MaxNALUSize is the maximum size of a NALU. + // with a 250 Mbps H265 video, the maximum NALU size is 2.2MB + MaxNALUSize = 3 * 1024 * 1024 + + // MaxNALUsPerGroup is the maximum number of NALUs per group. + MaxNALUsPerGroup = 20 +) diff --git a/pkg/codecs/h265/nalu_type.go b/pkg/codecs/h265/nalu_type.go new file mode 100644 index 0000000..87b705a --- /dev/null +++ b/pkg/codecs/h265/nalu_type.go @@ -0,0 +1,99 @@ +package h265 + +import ( + "fmt" +) + +// NALUType is the type of a NALU. +type NALUType uint8 + +// NALU types. +const ( + NALUType_TRAIL_N NALUType = 0 //nolint:revive + NALUType_TRAIL_R NALUType = 1 //nolint:revive + NALUType_TSA_N NALUType = 2 //nolint:revive + NALUType_TSA_R NALUType = 3 //nolint:revive + NALUType_STSA_N NALUType = 4 //nolint:revive + NALUType_STSA_R NALUType = 5 //nolint:revive + NALUType_RADL_N NALUType = 6 //nolint:revive + NALUType_RADL_R NALUType = 7 //nolint:revive + NALUType_RASL_N NALUType = 8 //nolint:revive + NALUType_RASL_R NALUType = 9 //nolint:revive + NALUType_RSV_VCL_N10 NALUType = 10 //nolint:revive + NALUType_RSV_VCL_N12 NALUType = 12 //nolint:revive + NALUType_RSV_VCL_N14 NALUType = 14 //nolint:revive + NALUType_RSV_VCL_R11 NALUType = 11 //nolint:revive + NALUType_RSV_VCL_R13 NALUType = 13 //nolint:revive + NALUType_RSV_VCL_R15 NALUType = 15 //nolint:revive + NALUType_BLA_W_LP NALUType = 16 //nolint:revive + NALUType_BLA_W_RADL NALUType = 17 //nolint:revive + NALUType_BLA_N_LP NALUType = 18 //nolint:revive + NALUType_IDR_W_RADL NALUType = 19 //nolint:revive + NALUType_IDR_N_LP NALUType = 20 //nolint:revive + NALUType_CRA_NUT NALUType = 21 //nolint:revive + NALUType_RSV_IRAP_VCL22 NALUType = 22 //nolint:revive + NALUType_RSV_IRAP_VCL23 NALUType = 23 //nolint:revive + NALUType_VPS_NUT NALUType = 32 //nolint:revive + NALUType_SPS_NUT NALUType = 33 //nolint:revive + NALUType_PPS_NUT NALUType = 34 //nolint:revive + NALUType_AUD_NUT NALUType = 35 //nolint:revive + NALUType_EOS_NUT NALUType = 36 //nolint:revive + NALUType_EOB_NUT NALUType = 37 //nolint:revive + NALUType_FD_NUT NALUType = 38 //nolint:revive + NALUType_PREFIX_SEI_NUT NALUType = 39 //nolint:revive + NALUType_SUFFIX_SEI_NUT NALUType = 40 //nolint:revive + + // additional NALU types for RTP/H265 + NALUType_AggregationUnit NALUType = 48 //nolint:revive + NALUType_FragmentationUnit NALUType = 49 //nolint:revive + NALUType_PACI NALUType = 50 //nolint:revive +) + +var naluTypeLabels = map[NALUType]string{ + NALUType_TRAIL_N: "TRAIL_N", + NALUType_TRAIL_R: "TRAIL_R", + NALUType_TSA_N: "TSA_N", + NALUType_TSA_R: "TSA_R", + NALUType_STSA_N: "STSA_N", + NALUType_STSA_R: "STSA_R:", + NALUType_RADL_N: "RADL_N", + NALUType_RADL_R: "RADL_R", + NALUType_RASL_N: "RASL_N", + NALUType_RASL_R: "RASL_R", + NALUType_RSV_VCL_N10: "RSV_VCL_N10", + NALUType_RSV_VCL_N12: "RSV_VCL_N12", + NALUType_RSV_VCL_N14: "RSV_VCL_N14", + NALUType_RSV_VCL_R11: "RSV_VCL_R11", + NALUType_RSV_VCL_R13: "RSV_VCL_R13", + NALUType_RSV_VCL_R15: "RSV_VCL_R15", + NALUType_BLA_W_LP: "BLA_W_LP", + NALUType_BLA_W_RADL: "BLA_W_RADL", + NALUType_BLA_N_LP: "BLA_N_LP", + NALUType_IDR_W_RADL: "IDR_W_RADL", + NALUType_IDR_N_LP: "IDR_N_LP", + NALUType_CRA_NUT: "CRA_NUT", + NALUType_RSV_IRAP_VCL22: "RSV_IRAP_VCL22", + NALUType_RSV_IRAP_VCL23: "RSV_IRAP_VCL23", + NALUType_VPS_NUT: "VPS_NUT", + NALUType_SPS_NUT: "SPS_NUT", + NALUType_PPS_NUT: "PPS_NUT", + NALUType_AUD_NUT: "AUD_NUT", + NALUType_EOS_NUT: "EOS_NUT", + NALUType_EOB_NUT: "EOB_NUT", + NALUType_FD_NUT: "FD_NUT", + NALUType_PREFIX_SEI_NUT: "PrefixSEINUT", + NALUType_SUFFIX_SEI_NUT: "SuffixSEINUT", + + // additional NALU types for RTP/H265 + NALUType_AggregationUnit: "AggregationUnit", + NALUType_FragmentationUnit: "FragmentationUnit", + NALUType_PACI: "PACI", +} + +// String implements fmt.Stringer. +func (nt NALUType) String() string { + if l, ok := naluTypeLabels[nt]; ok { + return l + } + return fmt.Sprintf("unknown (%d)", nt) +} diff --git a/pkg/codecs/h265/nalu_type_test.go b/pkg/codecs/h265/nalu_type_test.go new file mode 100644 index 0000000..3255ff7 --- /dev/null +++ b/pkg/codecs/h265/nalu_type_test.go @@ -0,0 +1,13 @@ +package h265 + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNALUType(t *testing.T) { + require.NotEqual(t, true, strings.HasPrefix(NALUType(10).String(), "unknown")) + require.Equal(t, true, strings.HasPrefix(NALUType(60).String(), "unknown")) +} diff --git a/pkg/codecs/h265/pps.go b/pkg/codecs/h265/pps.go new file mode 100644 index 0000000..33bd09d --- /dev/null +++ b/pkg/codecs/h265/pps.go @@ -0,0 +1,51 @@ +package h265 + +import ( + "fmt" + + "github.com/bluenviron/mediabase/pkg/bits" + "github.com/bluenviron/mediabase/pkg/codecs/h264" +) + +// PPS is a H265 picture parameter set. +type PPS struct { + ID uint32 + SPSID uint32 + DependentSliceSegmentsEnabledFlag bool + OutputFlagPresentFlag bool + NumExtraSliceHeaderBits uint8 +} + +// Unmarshal decodes a PPS. +func (p *PPS) Unmarshal(buf []byte) error { + if len(buf) < 2 { + return fmt.Errorf("not enough bits") + } + + buf = h264.EmulationPreventionRemove(buf) + + buf = buf[2:] + pos := 0 + + var err error + p.ID, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + p.SPSID, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + err = bits.HasSpace(buf, pos, 5) + if err != nil { + return err + } + + p.DependentSliceSegmentsEnabledFlag = bits.ReadFlagUnsafe(buf, &pos) + p.OutputFlagPresentFlag = bits.ReadFlagUnsafe(buf, &pos) + p.NumExtraSliceHeaderBits = uint8(bits.ReadBitsUnsafe(buf, &pos, 3)) + + return nil +} diff --git a/pkg/codecs/h265/pps_test.go b/pkg/codecs/h265/pps_test.go new file mode 100644 index 0000000..d6de60a --- /dev/null +++ b/pkg/codecs/h265/pps_test.go @@ -0,0 +1,40 @@ +//go:build go1.18 +// +build go1.18 + +package h265 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPPSUnmarshal(t *testing.T) { + for _, ca := range []struct { + name string + byts []byte + pps PPS + }{ + { + "default", + []byte{ + 0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62, 0x40, + }, + PPS{}, + }, + } { + t.Run(ca.name, func(t *testing.T) { + var pps PPS + err := pps.Unmarshal(ca.byts) + require.NoError(t, err) + require.Equal(t, ca.pps, pps) + }) + } +} + +func FuzzPPSUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var pps PPS + pps.Unmarshal(b) + }) +} diff --git a/pkg/codecs/h265/sps.go b/pkg/codecs/h265/sps.go new file mode 100644 index 0000000..0c185dc --- /dev/null +++ b/pkg/codecs/h265/sps.go @@ -0,0 +1,861 @@ +package h265 + +import ( + "fmt" + + "github.com/bluenviron/mediabase/pkg/bits" + "github.com/bluenviron/mediabase/pkg/codecs/h264" +) + +const ( + maxNegativePics = 255 + maxPositivePics = 255 + maxShortTermRefPics = 64 +) + +var subWidthC = []uint32{ + 1, + 2, + 2, + 1, +} + +var subHeightC = []uint32{ + 1, + 2, + 1, + 1, +} + +// SPS_DefaultDisplayWindow is a default display window. +type SPS_DefaultDisplayWindow struct { //nolint:revive + LeftOffset uint32 + RightOffset uint32 + TopOffset uint32 + BottomOffset uint32 +} + +func (w *SPS_DefaultDisplayWindow) unmarshal(buf []byte, pos *int) error { + var err error + w.LeftOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + w.RightOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + w.TopOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + w.BottomOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + return nil +} + +// SPS_TimingInfo is a timing info. +type SPS_TimingInfo struct { //nolint:revive + NumUnitsInTick uint32 + TimeScale uint32 + POCProportionalToTimingFlag bool + + // POCProportionalToTimingFlag == true + NumTicksPOCDiffOneMinus1 uint32 +} + +func (t *SPS_TimingInfo) unmarshal(buf []byte, pos *int) error { + err := bits.HasSpace(buf, *pos, 32+32+1) + if err != nil { + return err + } + + t.NumUnitsInTick = uint32(bits.ReadBitsUnsafe(buf, pos, 32)) + t.TimeScale = uint32(bits.ReadBitsUnsafe(buf, pos, 32)) + t.POCProportionalToTimingFlag = bits.ReadFlagUnsafe(buf, pos) + + if t.POCProportionalToTimingFlag { + t.NumTicksPOCDiffOneMinus1, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + } + + return nil +} + +// SPS_VUI is a video usability information. +type SPS_VUI struct { //nolint:revive + AspectRatioInfoPresentFlag bool + + // AspectRatioInfoPresentFlag == true + AspectRatioIdc uint8 + SarWidth uint16 + SarHeight uint16 + + OverscanInfoPresentFlag bool + + // OverscanInfoPresentFlag == true + OverscanAppropriateFlag bool + VideoSignalTypePresentFlag bool + + // VideoSignalTypePresentFlag == true + VideoFormat uint8 + VideoFullRangeFlag bool + ColourDescriptionPresentFlag bool + + // ColourDescriptionPresentFlag == true + ColourPrimaries uint8 + TransferCharacteristics uint8 + MatrixCoefficients uint8 + + ChromaLocInfoPresentFlag bool + + // ChromaLocInfoPresentFlag == true + ChromaSampleLocTypeTopField uint32 + ChromaSampleLocTypeBottomField uint32 + + NeutralChromaIndicationFlag bool + FieldSeqFlag bool + FrameFieldInfoPresentFlag bool + DefaultDisplayWindow *SPS_DefaultDisplayWindow + TimingInfo *SPS_TimingInfo +} + +func (v *SPS_VUI) unmarshal(buf []byte, pos *int) error { + var err error + v.AspectRatioInfoPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.AspectRatioInfoPresentFlag { + tmp, err := bits.ReadBits(buf, pos, 8) + if err != nil { + return err + } + v.AspectRatioIdc = uint8(tmp) + + if v.AspectRatioIdc == 255 { // EXTENDED_SAR + err := bits.HasSpace(buf, *pos, 32) + if err != nil { + return err + } + + v.SarWidth = uint16(bits.ReadBitsUnsafe(buf, pos, 16)) + v.SarHeight = uint16(bits.ReadBitsUnsafe(buf, pos, 16)) + } + } + + v.OverscanInfoPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.OverscanInfoPresentFlag { + v.OverscanAppropriateFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + } + + v.VideoSignalTypePresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.VideoSignalTypePresentFlag { + err := bits.HasSpace(buf, *pos, 5) + if err != nil { + return err + } + + v.VideoFormat = uint8(bits.ReadBitsUnsafe(buf, pos, 3)) + v.VideoFullRangeFlag = bits.ReadFlagUnsafe(buf, pos) + v.ColourDescriptionPresentFlag = bits.ReadFlagUnsafe(buf, pos) + + if v.ColourDescriptionPresentFlag { + err := bits.HasSpace(buf, *pos, 24) + if err != nil { + return err + } + + v.ColourPrimaries = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) + v.TransferCharacteristics = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) + v.MatrixCoefficients = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) + } + } + + v.ChromaLocInfoPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if v.ChromaLocInfoPresentFlag { + v.ChromaSampleLocTypeTopField, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + v.ChromaSampleLocTypeBottomField, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + } + + v.NeutralChromaIndicationFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + v.FieldSeqFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + v.FrameFieldInfoPresentFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + defaultDisplayWindowFlag, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if defaultDisplayWindowFlag { + v.DefaultDisplayWindow = &SPS_DefaultDisplayWindow{} + err := v.DefaultDisplayWindow.unmarshal(buf, pos) + if err != nil { + return err + } + } else { + v.DefaultDisplayWindow = nil + } + + timingInfoPresentFlag, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if timingInfoPresentFlag { + v.TimingInfo = &SPS_TimingInfo{} + err := v.TimingInfo.unmarshal(buf, pos) + if err != nil { + return err + } + } else { + v.TimingInfo = nil + } + + return nil +} + +// SPS_ProfileTierLevel is a profile level tier of a SPS. +type SPS_ProfileTierLevel struct { //nolint:revive + GeneralProfileSpace uint8 + GeneralTierFlag uint8 + GeneralProfileIdc uint8 + GeneralProfileCompatibilityFlag [32]bool + GeneralProgressiveSourceFlag bool + GeneralInterlacedSourceFlag bool + GeneralNonPackedConstraintFlag bool + GeneralFrameOnlyConstraintFlag bool + GeneralMax12bitConstraintFlag bool + GeneralMax10bitConstraintFlag bool + GeneralMax8bitConstraintFlag bool + GeneralMax422ChromeConstraintFlag bool + GeneralMax420ChromaConstraintFlag bool + GeneralMaxMonochromeConstraintFlag bool + GeneralIntraConstraintFlag bool + GeneralOnePictureOnlyConstraintFlag bool + GeneralLowerBitRateConstraintFlag bool + GeneralMax14BitConstraintFlag bool + GeneralLevelIdc uint8 + SubLayerProfilePresentFlag []bool + SubLayerLevelPresentFlag []bool +} + +func (p *SPS_ProfileTierLevel) unmarshal(buf []byte, pos *int, maxSubLayersMinus1 uint8) error { + err := bits.HasSpace(buf, *pos, 8+32+12+34+8) + if err != nil { + return err + } + + p.GeneralProfileSpace = uint8(bits.ReadBitsUnsafe(buf, pos, 2)) + p.GeneralTierFlag = uint8(bits.ReadBitsUnsafe(buf, pos, 1)) + p.GeneralProfileIdc = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) + + for j := 0; j < 32; j++ { + p.GeneralProfileCompatibilityFlag[j] = bits.ReadFlagUnsafe(buf, pos) + } + + p.GeneralProgressiveSourceFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralInterlacedSourceFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralNonPackedConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralFrameOnlyConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralMax12bitConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralMax10bitConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralMax8bitConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralMax422ChromeConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralMax420ChromaConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralMaxMonochromeConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralIntraConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralOnePictureOnlyConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + p.GeneralLowerBitRateConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + + if p.GeneralProfileIdc == 5 || + p.GeneralProfileIdc == 9 || + p.GeneralProfileIdc == 10 || + p.GeneralProfileIdc == 11 || + p.GeneralProfileCompatibilityFlag[5] || + p.GeneralProfileCompatibilityFlag[9] || + p.GeneralProfileCompatibilityFlag[10] || + p.GeneralProfileCompatibilityFlag[11] { + p.GeneralMax14BitConstraintFlag = bits.ReadFlagUnsafe(buf, pos) + *pos += 34 + } else { + *pos += 35 + } + + p.GeneralLevelIdc = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) + + if maxSubLayersMinus1 > 0 { + p.SubLayerProfilePresentFlag = make([]bool, maxSubLayersMinus1) + p.SubLayerLevelPresentFlag = make([]bool, maxSubLayersMinus1) + + err := bits.HasSpace(buf, *pos, int(2*maxSubLayersMinus1)) + if err != nil { + return err + } + + for j := uint8(0); j < maxSubLayersMinus1; j++ { + p.SubLayerProfilePresentFlag[j] = bits.ReadFlagUnsafe(buf, pos) + p.SubLayerLevelPresentFlag[j] = bits.ReadFlagUnsafe(buf, pos) + } + } + + if maxSubLayersMinus1 > 0 { + err := bits.HasSpace(buf, *pos, int(8-maxSubLayersMinus1)*2) + if err != nil { + return err + } + + *pos += int(8-maxSubLayersMinus1) * 2 + } + + for i := uint8(0); i < maxSubLayersMinus1; i++ { + if p.SubLayerProfilePresentFlag[i] { + return fmt.Errorf("SubLayerProfilePresentFlag not supported yet") + } + + if p.SubLayerLevelPresentFlag[i] { + return fmt.Errorf("SubLayerLevelPresentFlag not supported yet") + } + } + + return nil +} + +// SPS_ConformanceWindow is a conformance window of a SPS. +type SPS_ConformanceWindow struct { //nolint:revive + LeftOffset uint32 + RightOffset uint32 + TopOffset uint32 + BottomOffset uint32 +} + +func (c *SPS_ConformanceWindow) unmarshal(buf []byte, pos *int) error { + var err error + c.LeftOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + c.RightOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + c.TopOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + c.BottomOffset, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + return nil +} + +// SPS_ShortTermRefPicSet is a short-term reference picture set. +type SPS_ShortTermRefPicSet struct { //nolint:revive + InterRefPicSetPredictionFlag bool + DeltaIdxMinus1 uint32 + DeltaRpsSign bool + AbsDeltaRpsMinus1 uint32 + NumNegativePics uint32 + NumPositivePics uint32 + DeltaPocS0Minus1 []uint32 + UsedByCurrPicS0Flag []bool + DeltaPocS1Minus1 []uint32 + UsedByCurrPicS1Flag []bool +} + +func (r *SPS_ShortTermRefPicSet) unmarshal(buf []byte, pos *int, stRpsIdx uint32, + numShortTermRefPicSets uint32, shortTermRefPicSets []*SPS_ShortTermRefPicSet, +) error { + var err error + + if stRpsIdx != 0 { + r.InterRefPicSetPredictionFlag, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + } + + if r.InterRefPicSetPredictionFlag { + if stRpsIdx == numShortTermRefPicSets { + r.DeltaIdxMinus1, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + } + + r.DeltaRpsSign, err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + r.AbsDeltaRpsMinus1, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + refRpsIdx := stRpsIdx - (r.DeltaIdxMinus1 + 1) + numDeltaPocs := shortTermRefPicSets[refRpsIdx].NumNegativePics + shortTermRefPicSets[refRpsIdx].NumPositivePics + + for j := uint32(0); j <= numDeltaPocs; j++ { + usedByCurrPicFlag, err := bits.ReadFlag(buf, pos) + if err != nil { + return err + } + + if usedByCurrPicFlag { + _, err := bits.ReadGolombUnsigned(buf, pos) // use_delta_flag + if err != nil { + return err + } + } + } + } else { + r.NumNegativePics, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.NumPositivePics, err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + if r.NumNegativePics > 0 { + if r.NumNegativePics > maxNegativePics { + return fmt.Errorf("num_negative_pics exceeds %d", maxNegativePics) + } + + r.DeltaPocS0Minus1 = make([]uint32, r.NumNegativePics) + r.UsedByCurrPicS0Flag = make([]bool, r.NumNegativePics) + + for i := uint32(0); i < r.NumNegativePics; i++ { + r.DeltaPocS0Minus1[i], err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.UsedByCurrPicS0Flag[i], err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + } + } + + if r.NumPositivePics > 0 { + if r.NumPositivePics > maxPositivePics { + return fmt.Errorf("num_positive_pics exceeds %d", maxPositivePics) + } + + r.DeltaPocS1Minus1 = make([]uint32, r.NumPositivePics) + r.UsedByCurrPicS1Flag = make([]bool, r.NumPositivePics) + + for i := uint32(0); i < r.NumPositivePics; i++ { + r.DeltaPocS1Minus1[i], err = bits.ReadGolombUnsigned(buf, pos) + if err != nil { + return err + } + + r.UsedByCurrPicS1Flag[i], err = bits.ReadFlag(buf, pos) + if err != nil { + return err + } + } + } + } + + return nil +} + +// SPS is a H265 sequence parameter set. +type SPS struct { + VPSID uint8 + MaxSubLayersMinus1 uint8 + TemporalIDNestingFlag bool + ProfileTierLevel SPS_ProfileTierLevel + ID uint8 + ChromaFormatIdc uint32 + SeparateColourPlaneFlag bool + PicWidthInLumaSamples uint32 + PicHeightInLumaSamples uint32 + ConformanceWindow *SPS_ConformanceWindow + BitDepthLumaMinus8 uint32 + BitDepthChromaMinus8 uint32 + Log2MaxPicOrderCntLsbMinus4 uint32 + SubLayerOrderingInfoPresentFlag bool + MaxDecPicBufferingMinus1 []uint32 + MaxNumReorderPics []uint32 + MaxLatencyIncreasePlus1 []uint32 + Log2MinLumaCodingBlockSizeMinus3 uint32 + Log2DiffMaxMinLumaCodingBlockSize uint32 + Log2MinLumaTransformBlockSizeMinus2 uint32 + Log2DiffMaxMinLumaTransformBlockSize uint32 + MaxTransformHierarchyDepthInter uint32 + MaxTransformHierarchyDepthIntra uint32 + ScalingListEnabledFlag bool + ScalingListDataPresentFlag bool + AmpEnabledFlag bool + SampleAdaptiveOffsetEnabledFlag bool + PcmEnabledFlag bool + + // PcmEnabledFlag == true + PcmSampleBitDepthLumaMinus1 uint8 + PcmSampleBitDepthChromaMinus1 uint8 + Log2MinPcmLumaCodingBlockSizeMinus3 uint32 + Log2DiffMaxMinPcmLumaCodingBlockSize uint32 + PcmLoopFilterDisabledFlag bool + + ShortTermRefPicSets []*SPS_ShortTermRefPicSet + LongTermRefPicsPresentFlag bool + TemporalMvpEnabledFlag bool + StrongIntraSmoothingEnabledFlag bool + VUI *SPS_VUI +} + +// Unmarshal decodes a SPS from bytes. +func (s *SPS) Unmarshal(buf []byte) error { + buf = h264.EmulationPreventionRemove(buf) + + if len(buf) < 2 { + return fmt.Errorf("not enough bits") + } + + buf = buf[2:] + pos := 0 + + err := bits.HasSpace(buf, pos, 8) + if err != nil { + return err + } + + s.VPSID = uint8(bits.ReadBitsUnsafe(buf, &pos, 4)) + s.MaxSubLayersMinus1 = uint8(bits.ReadBitsUnsafe(buf, &pos, 3)) + s.TemporalIDNestingFlag = bits.ReadFlagUnsafe(buf, &pos) + + err = s.ProfileTierLevel.unmarshal(buf, &pos, s.MaxSubLayersMinus1) + if err != nil { + return err + } + + tmp2, err := bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + s.ID = uint8(tmp2) + + s.ChromaFormatIdc, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + if s.ChromaFormatIdc == 3 { + s.SeparateColourPlaneFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + } + + s.PicWidthInLumaSamples, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.PicHeightInLumaSamples, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + conformanceWindowFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if conformanceWindowFlag { + s.ConformanceWindow = &SPS_ConformanceWindow{} + err := s.ConformanceWindow.unmarshal(buf, &pos) + if err != nil { + return err + } + } else { + s.ConformanceWindow = nil + } + + s.BitDepthLumaMinus8, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.BitDepthChromaMinus8, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.Log2MaxPicOrderCntLsbMinus4, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.SubLayerOrderingInfoPresentFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + var start uint8 + if s.SubLayerOrderingInfoPresentFlag { + start = 0 + } else { + start = s.MaxSubLayersMinus1 + } + + s.MaxDecPicBufferingMinus1 = make([]uint32, s.MaxSubLayersMinus1+1) + s.MaxNumReorderPics = make([]uint32, s.MaxSubLayersMinus1+1) + s.MaxLatencyIncreasePlus1 = make([]uint32, s.MaxSubLayersMinus1+1) + + for i := start; i <= s.MaxSubLayersMinus1; i++ { + s.MaxDecPicBufferingMinus1[i], err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.MaxNumReorderPics[i], err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.MaxLatencyIncreasePlus1[i], err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + } + + s.Log2MinLumaCodingBlockSizeMinus3, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.Log2DiffMaxMinLumaCodingBlockSize, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.Log2MinLumaTransformBlockSizeMinus2, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.Log2DiffMaxMinLumaTransformBlockSize, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.MaxTransformHierarchyDepthInter, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.MaxTransformHierarchyDepthIntra, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.ScalingListEnabledFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if s.ScalingListEnabledFlag { + s.ScalingListDataPresentFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if s.ScalingListDataPresentFlag { + return fmt.Errorf("ScalingListDataPresentFlag not supported yet") + } + } + + s.AmpEnabledFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + s.SampleAdaptiveOffsetEnabledFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + s.PcmEnabledFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if s.PcmEnabledFlag { + err := bits.HasSpace(buf, pos, 8) + if err != nil { + return err + } + + s.PcmSampleBitDepthLumaMinus1 = uint8(bits.ReadBitsUnsafe(buf, &pos, 4)) + s.PcmSampleBitDepthChromaMinus1 = uint8(bits.ReadBitsUnsafe(buf, &pos, 4)) + + s.Log2MinPcmLumaCodingBlockSizeMinus3, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.Log2DiffMaxMinPcmLumaCodingBlockSize, err = bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + s.PcmLoopFilterDisabledFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + } + + numShortTermRefPicSets, err := bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + if numShortTermRefPicSets > 0 { + if numShortTermRefPicSets > maxShortTermRefPics { + return fmt.Errorf("num_short_term_ref_pic_sets exceeds %d", maxShortTermRefPics) + } + + s.ShortTermRefPicSets = make([]*SPS_ShortTermRefPicSet, numShortTermRefPicSets) + + for i := uint32(0); i < numShortTermRefPicSets; i++ { + s.ShortTermRefPicSets[i] = &SPS_ShortTermRefPicSet{} + err := s.ShortTermRefPicSets[i].unmarshal(buf, &pos, i, numShortTermRefPicSets, s.ShortTermRefPicSets) + if err != nil { + return err + } + } + } else { + s.ShortTermRefPicSets = nil + } + + s.LongTermRefPicsPresentFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if s.LongTermRefPicsPresentFlag { + numLongTermRefPicsSPS, err := bits.ReadGolombUnsigned(buf, &pos) + if err != nil { + return err + } + + if numLongTermRefPicsSPS > 0 { + return fmt.Errorf("long term ref pics inside SPS are not supported yet") + } + } + + s.TemporalMvpEnabledFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + s.StrongIntraSmoothingEnabledFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + vuiParametersPresentFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if vuiParametersPresentFlag { + s.VUI = &SPS_VUI{} + err := s.VUI.unmarshal(buf, &pos) + if err != nil { + return err + } + } else { + s.VUI = nil + } + + return nil +} + +// Width returns the video width. +func (s SPS) Width() int { + width := s.PicWidthInLumaSamples + + if s.ConformanceWindow != nil { + cropUnitX := subWidthC[s.ChromaFormatIdc] + width -= (s.ConformanceWindow.LeftOffset + s.ConformanceWindow.RightOffset) * cropUnitX + } + + return int(width) +} + +// Height returns the video height. +func (s SPS) Height() int { + height := s.PicHeightInLumaSamples + + if s.ConformanceWindow != nil { + cropUnitY := subHeightC[s.ChromaFormatIdc] + height -= (s.ConformanceWindow.TopOffset + s.ConformanceWindow.BottomOffset) * cropUnitY + } + + return int(height) +} + +// FPS returns the frames per second of the video. +func (s SPS) FPS() float64 { + if s.VUI == nil || s.VUI.TimingInfo == nil { + return 0 + } + + return float64(s.VUI.TimingInfo.TimeScale) / float64(s.VUI.TimingInfo.NumUnitsInTick) +} diff --git a/pkg/codecs/h265/sps_test.go b/pkg/codecs/h265/sps_test.go new file mode 100644 index 0000000..eac88c1 --- /dev/null +++ b/pkg/codecs/h265/sps_test.go @@ -0,0 +1,446 @@ +//go:build go1.18 +// +build go1.18 + +package h265 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSPSUnmarshal(t *testing.T) { + for _, ca := range []struct { + name string + byts []byte + sps SPS + width int + height int + fps float64 + }{ + { + "1920x1080", + []byte{ + 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, + 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x10, 0xe5, + 0x96, 0x66, 0x69, 0x24, 0xca, 0xe0, 0x10, 0x00, + 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x01, + 0xe0, 0x80, + }, + SPS{ + TemporalIDNestingFlag: true, + ProfileTierLevel: SPS_ProfileTierLevel{ + GeneralProfileIdc: 1, + GeneralProfileCompatibilityFlag: [32]bool{ + false, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + }, + GeneralProgressiveSourceFlag: true, + GeneralFrameOnlyConstraintFlag: true, + GeneralLevelIdc: 120, + }, + ChromaFormatIdc: 1, + PicWidthInLumaSamples: 1920, + PicHeightInLumaSamples: 1080, + Log2MaxPicOrderCntLsbMinus4: 4, + SubLayerOrderingInfoPresentFlag: true, + MaxDecPicBufferingMinus1: []uint32{5}, + MaxNumReorderPics: []uint32{2}, + MaxLatencyIncreasePlus1: []uint32{5}, + Log2DiffMaxMinLumaCodingBlockSize: 3, + Log2DiffMaxMinLumaTransformBlockSize: 3, + SampleAdaptiveOffsetEnabledFlag: true, + TemporalMvpEnabledFlag: true, + StrongIntraSmoothingEnabledFlag: true, + VUI: &SPS_VUI{ + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 30, + }, + }, + }, + 1920, + 1080, + 30, + }, + { + "1920x800", + []byte{ + 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, + 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x32, 0x16, + 0x59, 0x59, 0xa4, 0x93, 0x2b, 0xc0, 0x5a, 0x80, + 0x80, 0x80, 0x82, 0x00, 0x00, 0x07, 0xd2, 0x00, + 0x00, 0xbb, 0x80, 0x10, + }, + SPS{ + TemporalIDNestingFlag: true, + ProfileTierLevel: SPS_ProfileTierLevel{ + GeneralProfileIdc: 1, + GeneralProfileCompatibilityFlag: [32]bool{ + false, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + }, + GeneralProgressiveSourceFlag: true, + GeneralFrameOnlyConstraintFlag: true, + GeneralLevelIdc: 120, + }, + ChromaFormatIdc: 1, + PicWidthInLumaSamples: 1920, + PicHeightInLumaSamples: 800, + Log2MaxPicOrderCntLsbMinus4: 4, + SubLayerOrderingInfoPresentFlag: true, + MaxDecPicBufferingMinus1: []uint32{4}, + MaxNumReorderPics: []uint32{2}, + MaxLatencyIncreasePlus1: []uint32{5}, + Log2DiffMaxMinLumaCodingBlockSize: 3, + Log2DiffMaxMinLumaTransformBlockSize: 3, + SampleAdaptiveOffsetEnabledFlag: true, + TemporalMvpEnabledFlag: true, + StrongIntraSmoothingEnabledFlag: true, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1001, + TimeScale: 24000, + }, + }, + }, + 1920, + 800, + 23.976023976023978, + }, + { + "1280x720", + []byte{ + 0x42, 0x01, 0x01, 0x04, 0x08, 0x00, 0x00, 0x03, + 0x00, 0x98, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x5d, 0x90, 0x00, 0x50, 0x10, 0x05, 0xa2, 0x29, + 0x4b, 0x74, 0x94, 0x98, 0x5f, 0xfe, 0x00, 0x02, + 0x00, 0x02, 0xd4, 0x04, 0x04, 0x04, 0x10, 0x00, + 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x01, + 0xe0, 0x80, + }, + SPS{ + TemporalIDNestingFlag: true, + ProfileTierLevel: SPS_ProfileTierLevel{ + GeneralProfileIdc: 4, + GeneralProfileCompatibilityFlag: [32]bool{ + false, false, false, false, true, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + }, + GeneralProgressiveSourceFlag: true, + GeneralFrameOnlyConstraintFlag: true, + GeneralMax12bitConstraintFlag: true, + GeneralLowerBitRateConstraintFlag: true, + GeneralLevelIdc: 93, + }, + ChromaFormatIdc: 3, + PicWidthInLumaSamples: 1280, + PicHeightInLumaSamples: 720, + BitDepthLumaMinus8: 4, + BitDepthChromaMinus8: 4, + Log2MaxPicOrderCntLsbMinus4: 4, + SubLayerOrderingInfoPresentFlag: true, + MaxDecPicBufferingMinus1: []uint32{2}, + MaxNumReorderPics: []uint32{0}, + MaxLatencyIncreasePlus1: []uint32{1}, + Log2MinLumaCodingBlockSizeMinus3: 1, + Log2DiffMaxMinLumaCodingBlockSize: 1, + Log2DiffMaxMinLumaTransformBlockSize: 3, + TemporalMvpEnabledFlag: true, + StrongIntraSmoothingEnabledFlag: true, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 255, + SarWidth: 1, + SarHeight: 1, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 30, + }, + }, + }, + 1280, + 720, + 30, + }, + { + "10 bit", + []byte{ + 0x42, 0x01, 0x01, 0x22, 0x20, 0x00, 0x00, 0x03, + 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x10, 0xe4, + 0xd9, 0x66, 0x66, 0x92, 0x4c, 0xaf, 0x01, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x64, 0x00, 0x00, 0x0b, + 0xb5, 0x08, + }, + SPS{ + TemporalIDNestingFlag: true, + ProfileTierLevel: SPS_ProfileTierLevel{ + GeneralTierFlag: 1, + GeneralProfileIdc: 2, + GeneralProfileCompatibilityFlag: [32]bool{ + false, false, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + }, + GeneralProgressiveSourceFlag: true, + GeneralFrameOnlyConstraintFlag: true, + GeneralLevelIdc: 120, + }, + ChromaFormatIdc: 1, + PicWidthInLumaSamples: 1920, + PicHeightInLumaSamples: 1080, + BitDepthLumaMinus8: 2, + BitDepthChromaMinus8: 2, + Log2MaxPicOrderCntLsbMinus4: 4, + SubLayerOrderingInfoPresentFlag: true, + MaxDecPicBufferingMinus1: []uint32{5}, + MaxNumReorderPics: []uint32{2}, + MaxLatencyIncreasePlus1: []uint32{5}, + Log2DiffMaxMinLumaCodingBlockSize: 3, + Log2DiffMaxMinLumaTransformBlockSize: 3, + SampleAdaptiveOffsetEnabledFlag: true, + TemporalMvpEnabledFlag: true, + StrongIntraSmoothingEnabledFlag: true, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 100, + TimeScale: 2997, + }, + }, + }, + 1920, + 1080, + 29.97, + }, + { + "nvenc", + []byte{ + 0x42, 0x01, 0x01, 0x01, 0x40, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x03, 0x00, 0x7b, 0xa0, 0x03, 0xc0, 0x80, 0x11, + 0x07, 0xcb, 0x96, 0xb4, 0xa4, 0x25, 0x92, 0xe3, + 0x01, 0x6a, 0x02, 0x02, 0x02, 0x08, 0x00, 0x00, + 0x03, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0xe3, + 0x00, 0x2e, 0xf2, 0x88, 0x00, 0x07, 0x27, 0x0c, + 0x00, 0x00, 0x98, 0x96, 0x82, + }, + SPS{ + TemporalIDNestingFlag: true, + ProfileTierLevel: SPS_ProfileTierLevel{ + GeneralProfileIdc: 1, + GeneralProfileCompatibilityFlag: [32]bool{ + false, true, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + }, + GeneralLevelIdc: 123, + }, + ChromaFormatIdc: 1, + PicWidthInLumaSamples: 1920, + PicHeightInLumaSamples: 1088, + ConformanceWindow: &SPS_ConformanceWindow{ + BottomOffset: 4, + }, + Log2MaxPicOrderCntLsbMinus4: 4, + SubLayerOrderingInfoPresentFlag: true, + MaxDecPicBufferingMinus1: []uint32{1}, + MaxNumReorderPics: []uint32{0}, + MaxLatencyIncreasePlus1: []uint32{0}, + Log2MinLumaCodingBlockSizeMinus3: 1, + Log2DiffMaxMinLumaCodingBlockSize: 1, + Log2DiffMaxMinLumaTransformBlockSize: 3, + MaxTransformHierarchyDepthInter: 3, + AmpEnabledFlag: true, + SampleAdaptiveOffsetEnabledFlag: true, + ShortTermRefPicSets: []*SPS_ShortTermRefPicSet{{ + NumNegativePics: 1, + DeltaPocS0Minus1: []uint32{0}, + UsedByCurrPicS0Flag: []bool{true}, + }}, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 60, + }, + }, + }, + 1920, + 1080, + 60, + }, + { + "avigilon", + []byte{ + 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, + 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x96, 0xa0, 0x01, 0x80, 0x20, 0x06, 0xc1, + 0xfe, 0x36, 0xbb, 0xb5, 0x37, 0x77, 0x25, 0xd6, + 0x02, 0xdc, 0x04, 0x04, 0x04, 0x10, 0x00, 0x00, + 0x3e, 0x80, 0x00, 0x04, 0x26, 0x87, 0x21, 0xde, + 0xe5, 0x10, 0x01, 0x6e, 0x20, 0x00, 0x66, 0xff, + 0x00, 0x0b, 0x71, 0x00, 0x03, 0x37, 0xf8, 0x80, + }, + SPS{ + TemporalIDNestingFlag: true, + ProfileTierLevel: SPS_ProfileTierLevel{ + GeneralProfileIdc: 1, + GeneralProfileCompatibilityFlag: [32]bool{ + false, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + }, + GeneralProgressiveSourceFlag: true, + GeneralLevelIdc: 150, + }, + ChromaFormatIdc: 1, + PicWidthInLumaSamples: 3072, + PicHeightInLumaSamples: 1728, + ConformanceWindow: &SPS_ConformanceWindow{}, + Log2MaxPicOrderCntLsbMinus4: 12, + SubLayerOrderingInfoPresentFlag: true, + MaxDecPicBufferingMinus1: []uint32{1}, + MaxNumReorderPics: []uint32{0}, + MaxLatencyIncreasePlus1: []uint32{0}, + Log2DiffMaxMinLumaCodingBlockSize: 2, + SampleAdaptiveOffsetEnabledFlag: true, + PcmEnabledFlag: true, + PcmSampleBitDepthLumaMinus1: 7, + PcmSampleBitDepthChromaMinus1: 7, + Log2DiffMaxMinLumaTransformBlockSize: 2, + MaxTransformHierarchyDepthInter: 1, + Log2MinPcmLumaCodingBlockSizeMinus3: 2, + ShortTermRefPicSets: []*SPS_ShortTermRefPicSet{ + { + NumNegativePics: 1, + DeltaPocS0Minus1: []uint32{0}, + UsedByCurrPicS0Flag: []bool{true}, + }, + }, + TemporalMvpEnabledFlag: true, + VUI: &SPS_VUI{ + AspectRatioInfoPresentFlag: true, + AspectRatioIdc: 1, + VideoSignalTypePresentFlag: true, + VideoFormat: 5, + VideoFullRangeFlag: true, + ColourDescriptionPresentFlag: true, + ColourPrimaries: 1, + TransferCharacteristics: 1, + MatrixCoefficients: 1, + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1000, + TimeScale: 17000, + }, + }, + }, + 3072, + 1728, + 17, + }, + { + "long_term_ref_pics_present_flag", + []byte{ + 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, + 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x5d, 0xa0, 0x02, 0x80, 0x80, 0x2d, 0x16, + 0x36, 0xb9, 0x24, 0xcb, 0xf0, 0x08, 0x00, 0x00, + 0x03, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x95, + 0x08, + }, + SPS{ + TemporalIDNestingFlag: true, + ProfileTierLevel: SPS_ProfileTierLevel{ + GeneralProfileIdc: 1, + GeneralProfileCompatibilityFlag: [32]bool{ + false, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + }, + GeneralProgressiveSourceFlag: true, + GeneralNonPackedConstraintFlag: true, + GeneralFrameOnlyConstraintFlag: true, + GeneralLevelIdc: 93, + }, + ChromaFormatIdc: 1, + PicWidthInLumaSamples: 1280, + PicHeightInLumaSamples: 720, + Log2MaxPicOrderCntLsbMinus4: 12, + SubLayerOrderingInfoPresentFlag: true, + MaxDecPicBufferingMinus1: []uint32{1}, + MaxNumReorderPics: []uint32{0}, + MaxLatencyIncreasePlus1: []uint32{0}, + Log2DiffMaxMinLumaCodingBlockSize: 3, + Log2DiffMaxMinLumaTransformBlockSize: 3, + SampleAdaptiveOffsetEnabledFlag: true, + LongTermRefPicsPresentFlag: true, + TemporalMvpEnabledFlag: true, + StrongIntraSmoothingEnabledFlag: true, + VUI: &SPS_VUI{ + TimingInfo: &SPS_TimingInfo{ + NumUnitsInTick: 1, + TimeScale: 50, + POCProportionalToTimingFlag: true, + NumTicksPOCDiffOneMinus1: 1, + }, + }, + }, + 1280, + 720, + 50, + }, + } { + t.Run(ca.name, func(t *testing.T) { + var sps SPS + err := sps.Unmarshal(ca.byts) + require.NoError(t, err) + require.Equal(t, ca.sps, sps) + require.Equal(t, ca.width, sps.Width()) + require.Equal(t, ca.height, sps.Height()) + require.Equal(t, ca.fps, sps.FPS()) + }) + } +} + +func FuzzSPSUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var sps SPS + sps.Unmarshal(b) + }) +} diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/0e888f462a3598bba3429e3c26cda412817aa65ef38cdeb3aaed76db1c0379a4 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/0e888f462a3598bba3429e3c26cda412817aa65ef38cdeb3aaed76db1c0379a4 new file mode 100644 index 0000000..8ca4d7c --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/0e888f462a3598bba3429e3c26cda412817aa65ef38cdeb3aaed76db1c0379a4 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*0\xc6000000000") +uint64(87) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/1c4d7707525a482640e7c5090e339b08e446b5f9e4f7fff7e448ae377664edb0 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/1c4d7707525a482640e7c5090e339b08e446b5f9e4f7fff7e448ae377664edb0 new file mode 100644 index 0000000..eaa28f7 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/1c4d7707525a482640e7c5090e339b08e446b5f9e4f7fff7e448ae377664edb0 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*0\x80\x00\x00\x00\x0000000") +uint64(2) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/355f66d5cd294d34483b9be09cb55a3a35b9dd081ab4959ba7a35d04c5f91cb8 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/355f66d5cd294d34483b9be09cb55a3a35b9dd081ab4959ba7a35d04c5f91cb8 new file mode 100644 index 0000000..cee8eb1 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/355f66d5cd294d34483b9be09cb55a3a35b9dd081ab4959ba7a35d04c5f91cb8 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("0") +uint64(0) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/3c6b851fbf8b3435e3757b3fd9ec0f57bfe84533014a058f89ed320caceb13a9 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/3c6b851fbf8b3435e3757b3fd9ec0f57bfe84533014a058f89ed320caceb13a9 new file mode 100644 index 0000000..2022191 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/3c6b851fbf8b3435e3757b3fd9ec0f57bfe84533014a058f89ed320caceb13a9 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("\x000\x920!0000000") +uint64(156) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/53955e13efd39f08be15944b872ad99a77e5d04e1472db9455c4b1b5bd8b7073 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/53955e13efd39f08be15944b872ad99a77e5d04e1472db9455c4b1b5bd8b7073 new file mode 100644 index 0000000..39b9df0 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/53955e13efd39f08be15944b872ad99a77e5d04e1472db9455c4b1b5bd8b7073 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*") +uint64(34) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/6004440a439db44ebabbaee8a166e7a25bbaa5d4431a3900f509c70b756a06fb b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/6004440a439db44ebabbaee8a166e7a25bbaa5d4431a3900f509c70b756a06fb new file mode 100644 index 0000000..69daea5 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/6004440a439db44ebabbaee8a166e7a25bbaa5d4431a3900f509c70b756a06fb @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*0\x80\x00\x00\x000000 0") +uint64(3) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/8bf21706c418e930c7b972e6fff78d2fcadf6942a62141398df17b6cbe61f0b7 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/8bf21706c418e930c7b972e6fff78d2fcadf6942a62141398df17b6cbe61f0b7 new file mode 100644 index 0000000..fba610d --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/8bf21706c418e930c7b972e6fff78d2fcadf6942a62141398df17b6cbe61f0b7 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*0\xc6A00000000") +uint64(130) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/8e78b3e3511102b0b24e8f88b42b4e913a44408f4dfb4e496550c34cb92c93fc b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/8e78b3e3511102b0b24e8f88b42b4e913a44408f4dfb4e496550c34cb92c93fc new file mode 100644 index 0000000..0a7d5d1 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/8e78b3e3511102b0b24e8f88b42b4e913a44408f4dfb4e496550c34cb92c93fc @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("\x000\xb3000000000") +uint64(18) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/b467576cf8e0115542bddaece5f2d2bce19860a7c060445225adcf3dab189bc4 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/b467576cf8e0115542bddaece5f2d2bce19860a7c060445225adcf3dab189bc4 new file mode 100644 index 0000000..f093f29 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/b467576cf8e0115542bddaece5f2d2bce19860a7c060445225adcf3dab189bc4 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*0\x80\x00\x00\x000000$0") +uint64(9) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/f45d427ed4a5ea4af4846b4aeaf70d8194277f53bc68eb6255f52278d879d48c b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/f45d427ed4a5ea4af4846b4aeaf70d8194277f53bc68eb6255f52278d879d48c new file mode 100644 index 0000000..8d9c858 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/f45d427ed4a5ea4af4846b4aeaf70d8194277f53bc68eb6255f52278d879d48c @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*00000000000") +uint64(6) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/f6aa371594073591a2888e9cff0054b22899ced04b7aa1fddf0c96c76937d0fd b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/f6aa371594073591a2888e9cff0054b22899ced04b7aa1fddf0c96c76937d0fd new file mode 100644 index 0000000..45ffc85 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/f6aa371594073591a2888e9cff0054b22899ced04b7aa1fddf0c96c76937d0fd @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("0") +uint64(200) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/fd6f09d0654e93abb8d685f39f20a5ddcdb857a09391b3e18e55376b8155e3a8 b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/fd6f09d0654e93abb8d685f39f20a5ddcdb857a09391b3e18e55376b8155e3a8 new file mode 100644 index 0000000..ea4f9f8 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzDTSExtractor/fd6f09d0654e93abb8d685f39f20a5ddcdb857a09391b3e18e55376b8155e3a8 @@ -0,0 +1,3 @@ +go test fuzz v1 +[]byte("*0\x80\x00\x00\x000000A0") +uint64(18) diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 new file mode 100644 index 0000000..7fd7a20 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/06ba4bdb19de593e669c642987e270fe2488d4d58ecd712db136a3e011071253 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/76c06f7399f3b1781289b37c42f3dbe1518bc2481859740855ab13d8abdd88b1 b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/76c06f7399f3b1781289b37c42f3dbe1518bc2481859740855ab13d8abdd88b1 new file mode 100644 index 0000000..7c93803 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/76c06f7399f3b1781289b37c42f3dbe1518bc2481859740855ab13d8abdd88b1 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("007") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c new file mode 100644 index 0000000..e8000f3 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 new file mode 100644 index 0000000..ef9f9d4 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzPPSUnmarshal/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/00d6da076abf399523d37cc5d1385a967f0634a2573162c00ba67a01fd806919 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/00d6da076abf399523d37cc5d1385a967f0634a2573162c00ba67a01fd806919 new file mode 100644 index 0000000..a33f390 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/00d6da076abf399523d37cc5d1385a967f0634a2573162c00ba67a01fd806919 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/019839a18a6e47ed73c11a7503859a5680dfceb99c4fb98344d87f884ef731ba b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/019839a18a6e47ed73c11a7503859a5680dfceb99c4fb98344d87f884ef731ba new file mode 100644 index 0000000..a9b9365 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/019839a18a6e47ed73c11a7503859a5680dfceb99c4fb98344d87f884ef731ba @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000007808000000000000ZCz700") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/039e575e749a676e0037b8aa9d28d80a409c350d4900c88ab2647be4492f25ee b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/039e575e749a676e0037b8aa9d28d80a409c350d4900c88ab2647be4492f25ee new file mode 100644 index 0000000..0842b2a --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/039e575e749a676e0037b8aa9d28d80a409c350d4900c88ab2647be4492f25ee @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000002111007000000a00000017ZZZZ\xf9000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/05c89dc905ecc2ca9fc8fa08e0e0d56b83156fd4d8de02c03bda9a96b85679e0 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/05c89dc905ecc2ca9fc8fa08e0e0d56b83156fd4d8de02c03bda9a96b85679e0 new file mode 100644 index 0000000..a26d294 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/05c89dc905ecc2ca9fc8fa08e0e0d56b83156fd4d8de02c03bda9a96b85679e0 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000C11110010000\x00000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/0f8f18804076a2178ba242cfc92d30a0fd17a6f4aa63a8005253a16205b4e3c6 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/0f8f18804076a2178ba242cfc92d30a0fd17a6f4aa63a8005253a16205b4e3c6 new file mode 100644 index 0000000..7c50150 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/0f8f18804076a2178ba242cfc92d30a0fd17a6f4aa63a8005253a16205b4e3c6 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000\xf571*07") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/123492a203ec37c506b8768bd1b55bf7bc54ee36279dc9f09567d675c044d58f b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/123492a203ec37c506b8768bd1b55bf7bc54ee36279dc9f09567d675c044d58f new file mode 100644 index 0000000..6616d84 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/123492a203ec37c506b8768bd1b55bf7bc54ee36279dc9f09567d675c044d58f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000y710") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/182a4fb401185659940bf9a2589536a695487fba02686e2130ed0a5b880d52dc b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/182a4fb401185659940bf9a2589536a695487fba02686e2130ed0a5b880d52dc new file mode 100644 index 0000000..291cec8 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/182a4fb401185659940bf9a2589536a695487fba02686e2130ed0a5b880d52dc @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/1ced60e9d7b0105858590098640e83c09fecc453519c426cc0b446d43a1cbd73 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/1ced60e9d7b0105858590098640e83c09fecc453519c426cc0b446d43a1cbd73 new file mode 100644 index 0000000..de09603 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/1ced60e9d7b0105858590098640e83c09fecc453519c426cc0b446d43a1cbd73 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000077y2B000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/20c0dd82574437b8f5caaac5f38a1199e9777ffe846bba3468737defafd094e7 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/20c0dd82574437b8f5caaac5f38a1199e9777ffe846bba3468737defafd094e7 new file mode 100644 index 0000000..b081058 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/20c0dd82574437b8f5caaac5f38a1199e9777ffe846bba3468737defafd094e7 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000170") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/27052827203b64be7e464d07f815b5af2a08d4e6406f173702c88b6a86862437 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/27052827203b64be7e464d07f815b5af2a08d4e6406f173702c88b6a86862437 new file mode 100644 index 0000000..4e6a55e --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/27052827203b64be7e464d07f815b5af2a08d4e6406f173702c88b6a86862437 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000\xf571707\x80\x00\x00\x00\xea\xea\xea\xea\xea\xea0") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/2d13274250a51272648fb79aee956d40195ff289a44da3296d0c88ac02fc67bc b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/2d13274250a51272648fb79aee956d40195ff289a44da3296d0c88ac02fc67bc new file mode 100644 index 0000000..4583c5a --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/2d13274250a51272648fb79aee956d40195ff289a44da3296d0c88ac02fc67bc @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000007100\xf8A102") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 new file mode 100644 index 0000000..3d32e14 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3067c11d51b8a2666368161328eb2c82c55cb593824ddfe49742696889e520d5 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3067c11d51b8a2666368161328eb2c82c55cb593824ddfe49742696889e520d5 new file mode 100644 index 0000000..f1e39d7 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3067c11d51b8a2666368161328eb2c82c55cb593824ddfe49742696889e520d5 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000017") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/343dd7a6b769cfbc11b8ffd2162c9c6aac1e8bf42d252c18b6f766ec1858aaff b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/343dd7a6b769cfbc11b8ffd2162c9c6aac1e8bf42d252c18b6f766ec1858aaff new file mode 100644 index 0000000..503702f --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/343dd7a6b769cfbc11b8ffd2162c9c6aac1e8bf42d252c18b6f766ec1858aaff @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3742076c487d68aab77f194af476bb9fa1d01a47a46bed9bae42c10b18e21594 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3742076c487d68aab77f194af476bb9fa1d01a47a46bed9bae42c10b18e21594 new file mode 100644 index 0000000..2ad014b --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3742076c487d68aab77f194af476bb9fa1d01a47a46bed9bae42c10b18e21594 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000012Z") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3765cdec1f28e3f1f6f3f32d5f9c0d4cb61ea2d4533f554abd52b0df93bbbc4a b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3765cdec1f28e3f1f6f3f32d5f9c0d4cb61ea2d4533f554abd52b0df93bbbc4a new file mode 100644 index 0000000..48e4760 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3765cdec1f28e3f1f6f3f32d5f9c0d4cb61ea2d4533f554abd52b0df93bbbc4a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000077y2B0C") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/38f534b19ae62787a091d045d10ea3068aa66a765d26b383f9848a4881c6c170 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/38f534b19ae62787a091d045d10ea3068aa66a765d26b383f9848a4881c6c170 new file mode 100644 index 0000000..9c1c38a --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/38f534b19ae62787a091d045d10ea3068aa66a765d26b383f9848a4881c6c170 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000070A\xfdv\xad100") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3aaf3f930d2b6f555533d7ee1833e960dc84706396c38db6be2c71c772230bf3 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3aaf3f930d2b6f555533d7ee1833e960dc84706396c38db6be2c71c772230bf3 new file mode 100644 index 0000000..bd9e18b --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3aaf3f930d2b6f555533d7ee1833e960dc84706396c38db6be2c71c772230bf3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000711720A") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3dc305666b84e8f7b04c66b69b6cc79e8df25b2ae99c5caf497906ea47c87401 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3dc305666b84e8f7b04c66b69b6cc79e8df25b2ae99c5caf497906ea47c87401 new file mode 100644 index 0000000..d763cb7 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/3dc305666b84e8f7b04c66b69b6cc79e8df25b2ae99c5caf497906ea47c87401 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000A00807XG0") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/40ea349cafd1592da4cd915eb8f86e8dcfe862c5cd7d187c082598daaba1c047 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/40ea349cafd1592da4cd915eb8f86e8dcfe862c5cd7d187c082598daaba1c047 new file mode 100644 index 0000000..1e4ca77 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/40ea349cafd1592da4cd915eb8f86e8dcfe862c5cd7d187c082598daaba1c047 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000071172X7") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4205343f82a7d78102d7bcfeeae612a8916981964640a34384b1ade4316e8038 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4205343f82a7d78102d7bcfeeae612a8916981964640a34384b1ade4316e8038 new file mode 100644 index 0000000..505fda8 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4205343f82a7d78102d7bcfeeae612a8916981964640a34384b1ade4316e8038 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000071717000\x111") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/458604b691a14a0f80c142b495b99b128071c41b8527d5e3dbaab0fa75aa703f b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/458604b691a14a0f80c142b495b99b128071c41b8527d5e3dbaab0fa75aa703f new file mode 100644 index 0000000..a71665b --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/458604b691a14a0f80c142b495b99b128071c41b8527d5e3dbaab0fa75aa703f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000011170B0927$") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/475bdf3daec7839816b18b486c43e23d21d3d1709f5d6e909f809e316eef3ad0 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/475bdf3daec7839816b18b486c43e23d21d3d1709f5d6e909f809e316eef3ad0 new file mode 100644 index 0000000..37aeb09 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/475bdf3daec7839816b18b486c43e23d21d3d1709f5d6e909f809e316eef3ad0 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000711720\xcb") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4a3b46c8074373cb032eadcea909e28289cca73cd868ab29f13674040fbc6744 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4a3b46c8074373cb032eadcea909e28289cca73cd868ab29f13674040fbc6744 new file mode 100644 index 0000000..fcac589 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4a3b46c8074373cb032eadcea909e28289cca73cd868ab29f13674040fbc6744 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4d32bcb6507cca15717e5d30bae3c6d948e0abe6541fd423fdc4415f863329a8 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4d32bcb6507cca15717e5d30bae3c6d948e0abe6541fd423fdc4415f863329a8 new file mode 100644 index 0000000..bf66123 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/4d32bcb6507cca15717e5d30bae3c6d948e0abe6541fd423fdc4415f863329a8 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000y7100") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/547803e15ea20edd45d87377b5a21ace6348d0ab462a9bd03318f936ec14cf9c b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/547803e15ea20edd45d87377b5a21ace6348d0ab462a9bd03318f936ec14cf9c new file mode 100644 index 0000000..5bf1504 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/547803e15ea20edd45d87377b5a21ace6348d0ab462a9bd03318f936ec14cf9c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000010\xcb") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/60d5d2f797c1cc11b7698f694b8ae1044f19e4d98d2048c1aefa8efd2d61658b b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/60d5d2f797c1cc11b7698f694b8ae1044f19e4d98d2048c1aefa8efd2d61658b new file mode 100644 index 0000000..1b09a3e --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/60d5d2f797c1cc11b7698f694b8ae1044f19e4d98d2048c1aefa8efd2d61658b @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000002007\xffA0200771") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/615cfc8866bc1a828694f072286c58d406629607f197524d518d77ba7f8f9b54 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/615cfc8866bc1a828694f072286c58d406629607f197524d518d77ba7f8f9b54 new file mode 100644 index 0000000..49ee93e --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/615cfc8866bc1a828694f072286c58d406629607f197524d518d77ba7f8f9b54 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000002111007B71BC0000007") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/649679f2d355f61f168ec2ba9b37e5295eda2a415d5a61533385124723c2e9db b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/649679f2d355f61f168ec2ba9b37e5295eda2a415d5a61533385124723c2e9db new file mode 100644 index 0000000..ba4fe29 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/649679f2d355f61f168ec2ba9b37e5295eda2a415d5a61533385124723c2e9db @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000071717000$X") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/653a4111f80a68c2f197f0add573756caf6da8dd8aeb7051bc88bc3e954f2901 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/653a4111f80a68c2f197f0add573756caf6da8dd8aeb7051bc88bc3e954f2901 new file mode 100644 index 0000000..c615203 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/653a4111f80a68c2f197f0add573756caf6da8dd8aeb7051bc88bc3e954f2901 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000070000000000000,1\x0007") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/6f82af969dfcb94acaf2cfd6c35a75cc7c744b63b33f37286bc716604e68ce45 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/6f82af969dfcb94acaf2cfd6c35a75cc7c744b63b33f37286bc716604e68ce45 new file mode 100644 index 0000000..44021d0 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/6f82af969dfcb94acaf2cfd6c35a75cc7c744b63b33f37286bc716604e68ce45 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000070000007\xc1002") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/6f8f56484ea8b20c24fe9dc371865fb09f7c7a27d7a2cd40809060e804600dc9 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/6f8f56484ea8b20c24fe9dc371865fb09f7c7a27d7a2cd40809060e804600dc9 new file mode 100644 index 0000000..9f8eb6b --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/6f8f56484ea8b20c24fe9dc371865fb09f7c7a27d7a2cd40809060e804600dc9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000A\xfdya00") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/766677dfa01586ac8ad7954a627f3b900ee7248a10ebd94afec3bbaa59022126 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/766677dfa01586ac8ad7954a627f3b900ee7248a10ebd94afec3bbaa59022126 new file mode 100644 index 0000000..7c6f728 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/766677dfa01586ac8ad7954a627f3b900ee7248a10ebd94afec3bbaa59022126 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000y1000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/7b6521a56664b1cbb97f5073269d7275bdd943870b45d5737a04da49f394c31f b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/7b6521a56664b1cbb97f5073269d7275bdd943870b45d5737a04da49f394c31f new file mode 100644 index 0000000..1eee4c7 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/7b6521a56664b1cbb97f5073269d7275bdd943870b45d5737a04da49f394c31f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000C2\xc77\xc71") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/7c9233ac7979facf283efce144f2c1deeed8fa10349a851b491ccae0e134ffd1 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/7c9233ac7979facf283efce144f2c1deeed8fa10349a851b491ccae0e134ffd1 new file mode 100644 index 0000000..36c244a --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/7c9233ac7979facf283efce144f2c1deeed8fa10349a851b491ccae0e134ffd1 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000B2700100020A") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8281575bdc3265faffed6f7963cb1ea96e1cb9c3656e1c9b694d58227f4d168a b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8281575bdc3265faffed6f7963cb1ea96e1cb9c3656e1c9b694d58227f4d168a new file mode 100644 index 0000000..9f9a7b9 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8281575bdc3265faffed6f7963cb1ea96e1cb9c3656e1c9b694d58227f4d168a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("002000000000000002Y7$") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/863c5cc1f718d5d6e39c6f0eda93b678543c653946f0e4c5205a9a6e688b6aa3 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/863c5cc1f718d5d6e39c6f0eda93b678543c653946f0e4c5205a9a6e688b6aa3 new file mode 100644 index 0000000..1663e76 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/863c5cc1f718d5d6e39c6f0eda93b678543c653946f0e4c5205a9a6e688b6aa3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000711720B") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8703c0328c7aa4fe9e463dc9ec11a112f9530cf5b7c018987e1e56d0cb32e364 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8703c0328c7aa4fe9e463dc9ec11a112f9530cf5b7c018987e1e56d0cb32e364 new file mode 100644 index 0000000..51a6628 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8703c0328c7aa4fe9e463dc9ec11a112f9530cf5b7c018987e1e56d0cb32e364 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000007171708A") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c new file mode 100644 index 0000000..e8000f3 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8b8a68c6d9b801391c5df3d5f6fafc362a71d1b716bc02d268998df08364ac37 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8b8a68c6d9b801391c5df3d5f6fafc362a71d1b716bc02d268998df08364ac37 new file mode 100644 index 0000000..a2fe629 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8b8a68c6d9b801391c5df3d5f6fafc362a71d1b716bc02d268998df08364ac37 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000017") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8ba5fa6497afeb040d96665f4fba0037165933ebe9e760a70b1de81b23aadc4a b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8ba5fa6497afeb040d96665f4fba0037165933ebe9e760a70b1de81b23aadc4a new file mode 100644 index 0000000..7810146 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8ba5fa6497afeb040d96665f4fba0037165933ebe9e760a70b1de81b23aadc4a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000717170002X") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8bb95d053ae9f84b2bc99c9c488cb91c7451ec0b22ab74c64548531f5d6633c9 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8bb95d053ae9f84b2bc99c9c488cb91c7451ec0b22ab74c64548531f5d6633c9 new file mode 100644 index 0000000..f6515cd --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/8bb95d053ae9f84b2bc99c9c488cb91c7451ec0b22ab74c64548531f5d6633c9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000071717000\x118") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/93e3bc3735a837c70603d7f0bb7ec05fb087fd4db33e0ee855d9b225ca8f2511 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/93e3bc3735a837c70603d7f0bb7ec05fb087fd4db33e0ee855d9b225ca8f2511 new file mode 100644 index 0000000..896722f --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/93e3bc3735a837c70603d7f0bb7ec05fb087fd4db33e0ee855d9b225ca8f2511 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/943e3fb12606845898909ba86991f4b3a9d92f038aae8a9341a41fda80f92af5 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/943e3fb12606845898909ba86991f4b3a9d92f038aae8a9341a41fda80f92af5 new file mode 100644 index 0000000..0042af0 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/943e3fb12606845898909ba86991f4b3a9d92f038aae8a9341a41fda80f92af5 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000070A\xfdv\xad0") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9450509d117f96d6008adb21a4027055e3ba59c25615a5e96165c0bbb36b33bb b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9450509d117f96d6008adb21a4027055e3ba59c25615a5e96165c0bbb36b33bb new file mode 100644 index 0000000..b7d773b --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9450509d117f96d6008adb21a4027055e3ba59c25615a5e96165c0bbb36b33bb @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000017") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/94e4dcd86c2e09aac9c790086b9e76dc2b02e9bc964370d3106dbaef5aa6d37a b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/94e4dcd86c2e09aac9c790086b9e76dc2b02e9bc964370d3106dbaef5aa6d37a new file mode 100644 index 0000000..7b86d64 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/94e4dcd86c2e09aac9c790086b9e76dc2b02e9bc964370d3106dbaef5aa6d37a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000077y2B0C0") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9c6e2641e293d6bffef8b06b9e36b2cf5ecacc6d3ad9d926ab5ec64ecdad7b96 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9c6e2641e293d6bffef8b06b9e36b2cf5ecacc6d3ad9d926ab5ec64ecdad7b96 new file mode 100644 index 0000000..0c2a90d --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9c6e2641e293d6bffef8b06b9e36b2cf5ecacc6d3ad9d926ab5ec64ecdad7b96 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000077y2B\xff\xff") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9d560010faa7ada26ac70ae189fc384bd323efd7280990a5ecd6516cacd4cf61 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9d560010faa7ada26ac70ae189fc384bd323efd7280990a5ecd6516cacd4cf61 new file mode 100644 index 0000000..b91ea1c --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9d560010faa7ada26ac70ae189fc384bd323efd7280990a5ecd6516cacd4cf61 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000127001000A") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9d9abe934c8d92838c18705f3e298f34ca63022bd4010acb6635278bc742398a b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9d9abe934c8d92838c18705f3e298f34ca63022bd4010acb6635278bc742398a new file mode 100644 index 0000000..f62bc1d --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/9d9abe934c8d92838c18705f3e298f34ca63022bd4010acb6635278bc742398a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("002000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/a35edfe853b408a7c225af5012d1df6b6197436ce860641d55e275cc228da321 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/a35edfe853b408a7c225af5012d1df6b6197436ce860641d55e275cc228da321 new file mode 100644 index 0000000..6e4c427 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/a35edfe853b408a7c225af5012d1df6b6197436ce860641d55e275cc228da321 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000077y2B070") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/a5d467a1921f1f1395d0bc1574ea92274cb4a498b3c7cb1189a419d2ba7f1ead b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/a5d467a1921f1f1395d0bc1574ea92274cb4a498b3c7cb1189a419d2ba7f1ead new file mode 100644 index 0000000..f526e98 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/a5d467a1921f1f1395d0bc1574ea92274cb4a498b3c7cb1189a419d2ba7f1ead @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000011$0071110") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ab559ccd961e02992fd953c92eec4f50a828baecca4c6fffde8522632e90f847 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ab559ccd961e02992fd953c92eec4f50a828baecca4c6fffde8522632e90f847 new file mode 100644 index 0000000..37439c6 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ab559ccd961e02992fd953c92eec4f50a828baecca4c6fffde8522632e90f847 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000B27001000210") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/acf6271d3e87a7fc18dc947a460823559d30cdd652309d2002ba745ae6bca0f1 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/acf6271d3e87a7fc18dc947a460823559d30cdd652309d2002ba745ae6bca0f1 new file mode 100644 index 0000000..d15a96f --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/acf6271d3e87a7fc18dc947a460823559d30cdd652309d2002ba745ae6bca0f1 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000002Wy2B00000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ada5d60ffad1e135ecbc4f08322871d93f995b41a108e987151365c3924b6372 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ada5d60ffad1e135ecbc4f08322871d93f995b41a108e987151365c3924b6372 new file mode 100644 index 0000000..cf66e3e --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ada5d60ffad1e135ecbc4f08322871d93f995b41a108e987151365c3924b6372 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000B270010007") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/afb972a0b1cfbd4181a062bd143cf2da5b1e1c9d921c0410faae807f3360caa2 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/afb972a0b1cfbd4181a062bd143cf2da5b1e1c9d921c0410faae807f3360caa2 new file mode 100644 index 0000000..baf9614 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/afb972a0b1cfbd4181a062bd143cf2da5b1e1c9d921c0410faae807f3360caa2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000020A\xd5Y8G0x") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/b3b203da514589b7cc4ed7d18c13cdabc383fa5bae32cc853a1b3224893458ce b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/b3b203da514589b7cc4ed7d18c13cdabc383fa5bae32cc853a1b3224893458ce new file mode 100644 index 0000000..bfa4e18 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/b3b203da514589b7cc4ed7d18c13cdabc383fa5bae32cc853a1b3224893458ce @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0020000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/bfdfa1a6e4892d045614bd28d441737cc637962c2d057a5647bd4d4174c657c6 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/bfdfa1a6e4892d045614bd28d441737cc637962c2d057a5647bd4d4174c657c6 new file mode 100644 index 0000000..5cf2fec --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/bfdfa1a6e4892d045614bd28d441737cc637962c2d057a5647bd4d4174c657c6 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000001872c0") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 new file mode 100644 index 0000000..ef9f9d4 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/c3d5e611c2447ae2d18cf179ce268a18421e73253c9f97cce75e02466a475d6a b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/c3d5e611c2447ae2d18cf179ce268a18421e73253c9f97cce75e02466a475d6a new file mode 100644 index 0000000..493a56c --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/c3d5e611c2447ae2d18cf179ce268a18421e73253c9f97cce75e02466a475d6a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000120A27") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/cd4f7e682b02a30bc433044498e9124c6b1459802c7de9dcf18ad058a1688bb9 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/cd4f7e682b02a30bc433044498e9124c6b1459802c7de9dcf18ad058a1688bb9 new file mode 100644 index 0000000..19ce95b --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/cd4f7e682b02a30bc433044498e9124c6b1459802c7de9dcf18ad058a1688bb9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000070A\xfdv\xad10000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/cd939a83576d663b9de5c75da5b33dda1692c8289162a1e61d5764dee9ba5344 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/cd939a83576d663b9de5c75da5b33dda1692c8289162a1e61d5764dee9ba5344 new file mode 100644 index 0000000..c3ceb41 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/cd939a83576d663b9de5c75da5b33dda1692c8289162a1e61d5764dee9ba5344 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000y720") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ceb8cba9187af176dab482e8571748c8293bff3c37419ec4f86e0f93b5c6f7ce b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ceb8cba9187af176dab482e8571748c8293bff3c37419ec4f86e0f93b5c6f7ce new file mode 100644 index 0000000..a3160d9 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ceb8cba9187af176dab482e8571748c8293bff3c37419ec4f86e0f93b5c6f7ce @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000071717000\x112") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d09dfd7e6702ed14f3d16dc88c0beebc915cd3c7ed985106c7274dd6bf601991 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d09dfd7e6702ed14f3d16dc88c0beebc915cd3c7ed985106c7274dd6bf601991 new file mode 100644 index 0000000..73e0691 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d09dfd7e6702ed14f3d16dc88c0beebc915cd3c7ed985106c7274dd6bf601991 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000011100101177") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d2b8f6ff13c57a6493cc417708863c7edb8fa90b6973c421b32e45df6e98c897 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d2b8f6ff13c57a6493cc417708863c7edb8fa90b6973c421b32e45df6e98c897 new file mode 100644 index 0000000..8bb7738 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d2b8f6ff13c57a6493cc417708863c7edb8fa90b6973c421b32e45df6e98c897 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000$") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d3c6efd87c63850e112528d39bb792d28fb9d23bfbf5b241a62a63ebeb36b591 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d3c6efd87c63850e112528d39bb792d28fb9d23bfbf5b241a62a63ebeb36b591 new file mode 100644 index 0000000..2b1733f --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d3c6efd87c63850e112528d39bb792d28fb9d23bfbf5b241a62a63ebeb36b591 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000007100\xf8A100") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d8729013defaf4cf5833f86bef44bf6bcda1265ee9e83adb021dd883717e44ff b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d8729013defaf4cf5833f86bef44bf6bcda1265ee9e83adb021dd883717e44ff new file mode 100644 index 0000000..fe4fd54 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d8729013defaf4cf5833f86bef44bf6bcda1265ee9e83adb021dd883717e44ff @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d9f26138c54e610b9535ad32fa4fc65e7ee28921fd808119a9350650c2889fbb b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d9f26138c54e610b9535ad32fa4fc65e7ee28921fd808119a9350650c2889fbb new file mode 100644 index 0000000..c813945 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/d9f26138c54e610b9535ad32fa4fc65e7ee28921fd808119a9350650c2889fbb @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000007") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/dc2a4cb2325c492ca2a0787f03f4a64a9673fcbabcfd3d8b831163cf26e08257 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/dc2a4cb2325c492ca2a0787f03f4a64a9673fcbabcfd3d8b831163cf26e08257 new file mode 100644 index 0000000..845edc6 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/dc2a4cb2325c492ca2a0787f03f4a64a9673fcbabcfd3d8b831163cf26e08257 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000020A\xd5Y8G07") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e1d156e4fa7380afa414b12ae9aefa295debe1f892fe6bae3538651459654512 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e1d156e4fa7380afa414b12ae9aefa295debe1f892fe6bae3538651459654512 new file mode 100644 index 0000000..bda271e --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e1d156e4fa7380afa414b12ae9aefa295debe1f892fe6bae3538651459654512 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000\x00\x040$") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e4a6272c0ccae23d9ff40b63a3526fd967ee0df216749b9ef13ed0fd5041b2b4 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e4a6272c0ccae23d9ff40b63a3526fd967ee0df216749b9ef13ed0fd5041b2b4 new file mode 100644 index 0000000..5587c6e --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e4a6272c0ccae23d9ff40b63a3526fd967ee0df216749b9ef13ed0fd5041b2b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000071717000$A") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e6a754dcc2747eb5e3225d7ce2b3ab19075eeda630aa67817acd128712faf440 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e6a754dcc2747eb5e3225d7ce2b3ab19075eeda630aa67817acd128712faf440 new file mode 100644 index 0000000..98661f0 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e6a754dcc2747eb5e3225d7ce2b3ab19075eeda630aa67817acd128712faf440 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000B27001000X") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e7020cfc8cfc8a340f41aafbc157c0cdb2ecfc1a41b2b0c2b2f0adeb78a33412 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e7020cfc8cfc8a340f41aafbc157c0cdb2ecfc1a41b2b0c2b2f0adeb78a33412 new file mode 100644 index 0000000..3fa85f2 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e7020cfc8cfc8a340f41aafbc157c0cdb2ecfc1a41b2b0c2b2f0adeb78a33412 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000A177\xb3011") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e80085c26c10f735691d6790897e25ffbc50c2a2beafe1a090fd5059936f3a44 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e80085c26c10f735691d6790897e25ffbc50c2a2beafe1a090fd5059936f3a44 new file mode 100644 index 0000000..4762d3d --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/e80085c26c10f735691d6790897e25ffbc50c2a2beafe1a090fd5059936f3a44 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000007") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ed6952414b61c4c80820200ed4cfa0c873900d9311619e6590fa18cf8b28ef04 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ed6952414b61c4c80820200ed4cfa0c873900d9311619e6590fa18cf8b28ef04 new file mode 100644 index 0000000..f89ca5c --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ed6952414b61c4c80820200ed4cfa0c873900d9311619e6590fa18cf8b28ef04 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000%00000000A$0") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f6872527132c3a2c994316a511af6fb98889143acd71e18ff6adfca0aa3054cf b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f6872527132c3a2c994316a511af6fb98889143acd71e18ff6adfca0aa3054cf new file mode 100644 index 0000000..a996363 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f6872527132c3a2c994316a511af6fb98889143acd71e18ff6adfca0aa3054cf @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000120A7") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f7ffd151838837c215f9bcbdfb3f39bfd2105a931ef0118b72eb1eca4aeddad9 b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f7ffd151838837c215f9bcbdfb3f39bfd2105a931ef0118b72eb1eca4aeddad9 new file mode 100644 index 0000000..7e9923a --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f7ffd151838837c215f9bcbdfb3f39bfd2105a931ef0118b72eb1eca4aeddad9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f9043ef7bfaf2fdebf518743f1f81a2a50d46036a1da3d5844117036f78416ab b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f9043ef7bfaf2fdebf518743f1f81a2a50d46036a1da3d5844117036f78416ab new file mode 100644 index 0000000..0d05751 --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/f9043ef7bfaf2fdebf518743f1f81a2a50d46036a1da3d5844117036f78416ab @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000071717000\x110") diff --git a/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ff354e5d8975a43060c65913848811b2a66fea56a377d3aea5a0a7ffb53952ba b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ff354e5d8975a43060c65913848811b2a66fea56a377d3aea5a0a7ffb53952ba new file mode 100644 index 0000000..30a4c0f --- /dev/null +++ b/pkg/codecs/h265/testdata/fuzz/FuzzSPSUnmarshal/ff354e5d8975a43060c65913848811b2a66fea56a377d3aea5a0a7ffb53952ba @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000001Y7") diff --git a/pkg/codecs/jpeg/define_huffman_table.go b/pkg/codecs/jpeg/define_huffman_table.go new file mode 100644 index 0000000..bc46dac --- /dev/null +++ b/pkg/codecs/jpeg/define_huffman_table.go @@ -0,0 +1,20 @@ +package jpeg + +// DefineHuffmanTable is a DHT marker. +type DefineHuffmanTable struct { + Codes []byte + Symbols []byte + TableNumber int + TableClass int +} + +// Marshal encodes the marker. +func (m DefineHuffmanTable) Marshal(buf []byte) []byte { + buf = append(buf, []byte{0xFF, MarkerDefineHuffmanTable}...) + s := 3 + len(m.Codes) + len(m.Symbols) + buf = append(buf, []byte{byte(s >> 8), byte(s)}...) // length + buf = append(buf, []byte{byte(m.TableClass<<4) | byte(m.TableNumber)}...) + buf = append(buf, m.Codes...) + buf = append(buf, m.Symbols...) + return buf +} diff --git a/pkg/codecs/jpeg/define_huffman_table_test.go b/pkg/codecs/jpeg/define_huffman_table_test.go new file mode 100644 index 0000000..b00a640 --- /dev/null +++ b/pkg/codecs/jpeg/define_huffman_table_test.go @@ -0,0 +1,35 @@ +package jpeg + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var casesDefineHuffmanTable = []struct { + name string + enc []byte + dec DefineHuffmanTable +}{ + { + "base", + []byte{ + 0xff, 0xc4, 0x0, 0x7, 0x43, 0x1, 0x2, 0x3, 0x4, + }, + DefineHuffmanTable{ + Codes: []byte{0x01, 0x02}, + Symbols: []byte{0x03, 0x04}, + TableNumber: 3, + TableClass: 4, + }, + }, +} + +func TestDefineHuffmanTableMarshal(t *testing.T) { + for _, ca := range casesDefineHuffmanTable { + t.Run(ca.name, func(t *testing.T) { + byts := ca.dec.Marshal(nil) + require.Equal(t, ca.enc, byts) + }) + } +} diff --git a/pkg/codecs/jpeg/define_quantization_table.go b/pkg/codecs/jpeg/define_quantization_table.go new file mode 100644 index 0000000..b141fc6 --- /dev/null +++ b/pkg/codecs/jpeg/define_quantization_table.go @@ -0,0 +1,61 @@ +package jpeg + +import ( + "fmt" +) + +// QuantizationTable is a DQT quantization table. +type QuantizationTable struct { + ID uint8 + Precision uint8 + Data []byte +} + +// DefineQuantizationTable is a DQT marker. +type DefineQuantizationTable struct { + Tables []QuantizationTable +} + +// Unmarshal decodes the marker. +func (m *DefineQuantizationTable) Unmarshal(buf []byte) error { + for len(buf) != 0 { + id := buf[0] & 0x0F + precision := buf[0] >> 4 + buf = buf[1:] + if precision != 0 { + return fmt.Errorf("Precision %d is not supported", precision) + } + + if len(buf) < 64 { + return fmt.Errorf("image is too short") + } + + m.Tables = append(m.Tables, QuantizationTable{ + ID: id, + Precision: precision, + Data: buf[:64], + }) + buf = buf[64:] + } + + return nil +} + +// Marshal encodes the marker. +func (m DefineQuantizationTable) Marshal(buf []byte) []byte { + buf = append(buf, []byte{0xFF, MarkerDefineQuantizationTable}...) + + // length + s := 2 + for _, t := range m.Tables { + s += 1 + len(t.Data) + } + buf = append(buf, []byte{byte(s >> 8), byte(s)}...) + + for _, t := range m.Tables { + buf = append(buf, []byte{(t.ID)}...) + buf = append(buf, t.Data...) + } + + return buf +} diff --git a/pkg/codecs/jpeg/define_quantization_table_test.go b/pkg/codecs/jpeg/define_quantization_table_test.go new file mode 100644 index 0000000..d081017 --- /dev/null +++ b/pkg/codecs/jpeg/define_quantization_table_test.go @@ -0,0 +1,79 @@ +//go:build go1.18 +// +build go1.18 + +package jpeg + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +var casesDefineQuantizationTable = []struct { + name string + enc []byte + dec DefineQuantizationTable +}{ + { + "base", + []byte{ + 0xff, 0xdb, 0x0, 0x84, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x1, 0x2, 0x3, + 0x4, 0x1, 0x2, 0x3, 0x4, 0x5, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, 0x5, 0x6, + 0x7, 0x8, 0x5, 0x6, 0x7, 0x8, + }, + DefineQuantizationTable{ + Tables: []QuantizationTable{ + { + ID: 4, + Data: bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 64/4), + }, + { + ID: 5, + Data: bytes.Repeat([]byte{0x05, 0x06, 0x07, 0x08}, 64/4), + }, + }, + }, + }, +} + +func TestDefineQuantizationTableUnmarshal(t *testing.T) { + for _, ca := range casesDefineQuantizationTable { + t.Run(ca.name, func(t *testing.T) { + var h DefineQuantizationTable + err := h.Unmarshal(ca.enc[4:]) + require.NoError(t, err) + require.Equal(t, ca.dec, h) + }) + } +} + +func TestDefineQuantizationTableMarshal(t *testing.T) { + for _, ca := range casesDefineQuantizationTable { + t.Run(ca.name, func(t *testing.T) { + byts := ca.dec.Marshal(nil) + require.Equal(t, ca.enc, byts) + }) + } +} + +func FuzzDefineQuantizationTableUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var h DefineQuantizationTable + h.Unmarshal(b) + }) +} diff --git a/pkg/codecs/jpeg/define_restart_interval.go b/pkg/codecs/jpeg/define_restart_interval.go new file mode 100644 index 0000000..50a3026 --- /dev/null +++ b/pkg/codecs/jpeg/define_restart_interval.go @@ -0,0 +1,20 @@ +package jpeg + +import ( + "fmt" +) + +// DefineRestartInterval is a DRI marker. +type DefineRestartInterval struct { + Interval uint16 +} + +// Unmarshal decodes the marker. +func (m *DefineRestartInterval) Unmarshal(buf []byte) error { + if len(buf) != 2 { + return fmt.Errorf("unsupported DRI size of %d", len(buf)) + } + + m.Interval = uint16(buf[0])<<8 | uint16(buf[1]) + return nil +} diff --git a/pkg/codecs/jpeg/define_restart_interval_test.go b/pkg/codecs/jpeg/define_restart_interval_test.go new file mode 100644 index 0000000..35251c8 --- /dev/null +++ b/pkg/codecs/jpeg/define_restart_interval_test.go @@ -0,0 +1,44 @@ +//go:build go1.18 +// +build go1.18 + +package jpeg + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var casesDefineRestartInterval = []struct { + name string + enc []byte + dec DefineRestartInterval +}{ + { + "base", + []byte{ + 0xff, MarkerDefineRestartInterval, 0x00, 0x04, 0xd0, 0xc7, + }, + DefineRestartInterval{ + Interval: 53447, + }, + }, +} + +func TestDefineRestartIntervalUnmarshal(t *testing.T) { + for _, ca := range casesDefineRestartInterval { + t.Run(ca.name, func(t *testing.T) { + var h DefineRestartInterval + err := h.Unmarshal(ca.enc[4:]) + require.NoError(t, err) + require.Equal(t, ca.dec, h) + }) + } +} + +func FuzzDefineRestartIntervalUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var h DefineRestartInterval + h.Unmarshal(b) + }) +} diff --git a/pkg/codecs/jpeg/jpeg.go b/pkg/codecs/jpeg/jpeg.go new file mode 100644 index 0000000..db62667 --- /dev/null +++ b/pkg/codecs/jpeg/jpeg.go @@ -0,0 +1,14 @@ +// Package jpeg contains JPEG/JFIF markers. +package jpeg + +// standard JPEG markers. +const ( + MarkerStartOfImage = 0xD8 + MarkerDefineQuantizationTable = 0xDB + MarkerDefineHuffmanTable = 0xC4 + MarkerDefineRestartInterval = 0xDD + MarkerStartOfFrame1 = 0xC0 + MarkerStartOfScan = 0xDA + MarkerEndOfImage = 0xD9 + MarkerComment = 0xFE +) diff --git a/pkg/codecs/jpeg/start_of_frame1.go b/pkg/codecs/jpeg/start_of_frame1.go new file mode 100644 index 0000000..8eb2a25 --- /dev/null +++ b/pkg/codecs/jpeg/start_of_frame1.go @@ -0,0 +1,83 @@ +package jpeg + +import ( + "fmt" +) + +// StartOfFrame1 is a SOF1 marker. +type StartOfFrame1 struct { + Type uint8 + Width int + Height int + QuantizationTableCount uint8 // write only +} + +// Unmarshal decodes the marker. +func (m *StartOfFrame1) Unmarshal(buf []byte) error { + if len(buf) != 15 { + return fmt.Errorf("unsupported SOF size of %d", len(buf)) + } + + precision := buf[0] + if precision != 8 { + return fmt.Errorf("precision %d is not supported", precision) + } + + m.Height = int(buf[1])<<8 | int(buf[2]) + m.Width = int(buf[3])<<8 | int(buf[4]) + + components := buf[5] + if components != 3 { + return fmt.Errorf("number of components = %d is not supported", components) + } + + samp0 := buf[7] + switch samp0 { + case 0x21: + m.Type = 0 + + case 0x22: + m.Type = 1 + + default: + return fmt.Errorf("samp0 %x is not supported", samp0) + } + + samp1 := buf[10] + if samp1 != 0x11 { + return fmt.Errorf("samp1 %x is not supported", samp1) + } + + samp2 := buf[13] + if samp2 != 0x11 { + return fmt.Errorf("samp2 %x is not supported", samp2) + } + + return nil +} + +// Marshal encodes the marker. +func (m StartOfFrame1) Marshal(buf []byte) []byte { + buf = append(buf, []byte{0xFF, MarkerStartOfFrame1}...) + buf = append(buf, []byte{0, 17}...) // length + buf = append(buf, []byte{8}...) // precision + buf = append(buf, []byte{byte(m.Height >> 8), byte(m.Height)}...) // height + buf = append(buf, []byte{byte(m.Width >> 8), byte(m.Width)}...) // width + buf = append(buf, []byte{3}...) // components + if (m.Type & 0x3f) == 0 { // component 0 + buf = append(buf, []byte{0x00, 0x21, 0}...) + } else { + buf = append(buf, []byte{0x00, 0x22, 0}...) + } + + var secondQuantizationTable byte + if m.QuantizationTableCount == 2 { + secondQuantizationTable = 1 + } else { + secondQuantizationTable = 0 + } + + buf = append(buf, []byte{1, 0x11, secondQuantizationTable}...) // component 1 + buf = append(buf, []byte{2, 0x11, secondQuantizationTable}...) // component 2 + return buf +} diff --git a/pkg/codecs/jpeg/start_of_frame1_test.go b/pkg/codecs/jpeg/start_of_frame1_test.go new file mode 100644 index 0000000..56ff313 --- /dev/null +++ b/pkg/codecs/jpeg/start_of_frame1_test.go @@ -0,0 +1,59 @@ +//go:build go1.18 +// +build go1.18 + +package jpeg + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var casesStartOfFrame1 = []struct { + name string + enc []byte + dec StartOfFrame1 +}{ + { + "base", + []byte{ + 0xff, 0xc0, 0x0, 0x11, 0x8, 0x2, 0x58, 0x3, + 0x20, 0x3, 0x0, 0x22, 0x0, 0x1, 0x11, 0x1, + 0x2, 0x11, 0x1, + }, + StartOfFrame1{ + Type: 1, + Width: 800, + Height: 600, + QuantizationTableCount: 2, + }, + }, +} + +func TestStartOfFrame1Unmarshal(t *testing.T) { + for _, ca := range casesStartOfFrame1 { + t.Run(ca.name, func(t *testing.T) { + var h StartOfFrame1 + err := h.Unmarshal(ca.enc[4:]) + require.NoError(t, err) + h.QuantizationTableCount = 2 + require.Equal(t, ca.dec, h) + }) + } +} + +func TestStartOfFrame1Marshal(t *testing.T) { + for _, ca := range casesStartOfFrame1 { + t.Run(ca.name, func(t *testing.T) { + byts := ca.dec.Marshal(nil) + require.Equal(t, ca.enc, byts) + }) + } +} + +func FuzzStartOfFrame1Unmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var h StartOfFrame1 + h.Unmarshal(b) + }) +} diff --git a/pkg/codecs/jpeg/start_of_image.go b/pkg/codecs/jpeg/start_of_image.go new file mode 100644 index 0000000..9a6ea7a --- /dev/null +++ b/pkg/codecs/jpeg/start_of_image.go @@ -0,0 +1,10 @@ +package jpeg + +// StartOfImage is a SOI marker. +type StartOfImage struct{} + +// Marshal encodes the marker. +func (StartOfImage) Marshal(buf []byte) []byte { + buf = append(buf, []byte{0xFF, MarkerStartOfImage}...) + return buf +} diff --git a/pkg/codecs/jpeg/start_of_image_test.go b/pkg/codecs/jpeg/start_of_image_test.go new file mode 100644 index 0000000..070cf15 --- /dev/null +++ b/pkg/codecs/jpeg/start_of_image_test.go @@ -0,0 +1,12 @@ +package jpeg + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestStartOfImageMarshal(t *testing.T) { + buf := StartOfImage{}.Marshal(nil) + require.Equal(t, []byte{0xff, 0xd8}, buf) +} diff --git a/pkg/codecs/jpeg/start_of_scan.go b/pkg/codecs/jpeg/start_of_scan.go new file mode 100644 index 0000000..da78cb7 --- /dev/null +++ b/pkg/codecs/jpeg/start_of_scan.go @@ -0,0 +1,28 @@ +package jpeg + +import ( + "fmt" +) + +// StartOfScan is a SOS marker. +type StartOfScan struct{} + +// Unmarshal decodes the marker. +func (StartOfScan) Unmarshal(buf []byte) error { + if len(buf) != 10 { + return fmt.Errorf("unsupported SOS size of %d", len(buf)) + } + return nil +} + +// Marshal encodes the marker. +func (StartOfScan) Marshal(buf []byte) []byte { + buf = append(buf, []byte{0xFF, MarkerStartOfScan}...) + buf = append(buf, []byte{0, 12}...) // length + buf = append(buf, []byte{3}...) // components + buf = append(buf, []byte{0, 0}...) // component 0 + buf = append(buf, []byte{1, 0x11}...) // component 1 + buf = append(buf, []byte{2, 0x11}...) // component 2 + buf = append(buf, []byte{0, 63, 0}...) + return buf +} diff --git a/pkg/codecs/jpeg/start_of_scan_test.go b/pkg/codecs/jpeg/start_of_scan_test.go new file mode 100644 index 0000000..1910ddd --- /dev/null +++ b/pkg/codecs/jpeg/start_of_scan_test.go @@ -0,0 +1,52 @@ +//go:build go1.18 +// +build go1.18 + +package jpeg + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var casesStartOfScan = []struct { + name string + enc []byte + dec StartOfScan +}{ + { + "base", + []byte{ + 0xff, 0xda, 0x0, 0xc, 0x3, 0x0, 0x0, 0x1, + 0x11, 0x2, 0x11, 0x0, 0x3f, 0x0, + }, + StartOfScan{}, + }, +} + +func TestStartOfScanUnmarshal(t *testing.T) { + for _, ca := range casesStartOfScan { + t.Run(ca.name, func(t *testing.T) { + var h StartOfScan + err := h.Unmarshal(ca.enc[4:]) + require.NoError(t, err) + require.Equal(t, ca.dec, h) + }) + } +} + +func TestStartOfScanMarshal(t *testing.T) { + for _, ca := range casesStartOfScan { + t.Run(ca.name, func(t *testing.T) { + byts := ca.dec.Marshal(nil) + require.Equal(t, ca.enc, byts) + }) + } +} + +func FuzzStartOfScanUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var h StartOfScan + h.Unmarshal(b) + }) +} diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineQuantizationTableUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineQuantizationTableUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineQuantizationTableUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineQuantizationTableUnmarshal/97dc7172b48e6ffd89dfa34cfaac68bab4e2c2a4c5a0ab953e27ba6b006ffd56 b/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineQuantizationTableUnmarshal/97dc7172b48e6ffd89dfa34cfaac68bab4e2c2a4c5a0ab953e27ba6b006ffd56 new file mode 100644 index 0000000..4fbe416 --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineQuantizationTableUnmarshal/97dc7172b48e6ffd89dfa34cfaac68bab4e2c2a4c5a0ab953e27ba6b006ffd56 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x01") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineRestartIntervalUnmarshal/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 b/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineRestartIntervalUnmarshal/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 new file mode 100644 index 0000000..67322c7 --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzDefineRestartIntervalUnmarshal/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/04069695460a25181d94bba1342df84c161a53135a7a8e93511489e6b51c0afe b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/04069695460a25181d94bba1342df84c161a53135a7a8e93511489e6b51c0afe new file mode 100644 index 0000000..98474d5 --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/04069695460a25181d94bba1342df84c161a53135a7a8e93511489e6b51c0afe @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\b0000\x030!00\x110000") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/52bcb082e28f6e0e4007bae9ef0f4984e89ae5c891d08a2ad3c917fe77b94408 b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/52bcb082e28f6e0e4007bae9ef0f4984e89ae5c891d08a2ad3c917fe77b94408 new file mode 100644 index 0000000..c0bab18 --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/52bcb082e28f6e0e4007bae9ef0f4984e89ae5c891d08a2ad3c917fe77b94408 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\b0000\x030!0000000") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/93e3bc3735a837c70603d7f0bb7ec05fb087fd4db33e0ee855d9b225ca8f2511 b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/93e3bc3735a837c70603d7f0bb7ec05fb087fd4db33e0ee855d9b225ca8f2511 new file mode 100644 index 0000000..896722f --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/93e3bc3735a837c70603d7f0bb7ec05fb087fd4db33e0ee855d9b225ca8f2511 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/9aaf79656de4e8166797e57c7ea359c531218826a6db07cf1a68e91f15b540c8 b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/9aaf79656de4e8166797e57c7ea359c531218826a6db07cf1a68e91f15b540c8 new file mode 100644 index 0000000..83a124d --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/9aaf79656de4e8166797e57c7ea359c531218826a6db07cf1a68e91f15b540c8 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\b0000\x03000000000") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/f032221efa2df5f3a4eedd5bad24c2bc0283177676e17ac5abeb131a80a38ef5 b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/f032221efa2df5f3a4eedd5bad24c2bc0283177676e17ac5abeb131a80a38ef5 new file mode 100644 index 0000000..9bda36b --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfFrame1Unmarshal/f032221efa2df5f3a4eedd5bad24c2bc0283177676e17ac5abeb131a80a38ef5 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\b00000000000000") diff --git a/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfScanUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfScanUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/jpeg/testdata/fuzz/FuzzStartOfScanUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/mpeg4audio/adts.go b/pkg/codecs/mpeg4audio/adts.go new file mode 100644 index 0000000..8922991 --- /dev/null +++ b/pkg/codecs/mpeg4audio/adts.go @@ -0,0 +1,147 @@ +package mpeg4audio + +import ( + "fmt" +) + +// ADTSPacket is an ADTS packet. +type ADTSPacket struct { + Type ObjectType + SampleRate int + ChannelCount int + AU []byte +} + +// ADTSPackets is a group od ADTS packets. +type ADTSPackets []*ADTSPacket + +// Unmarshal decodes an ADTS stream into ADTS packets. +func (ps *ADTSPackets) Unmarshal(buf []byte) error { + // refs: https://wiki.multimedia.cx/index.php/ADTS + + bl := len(buf) + pos := 0 + + for { + if (bl - pos) < 8 { + return fmt.Errorf("invalid length") + } + + syncWord := (uint16(buf[pos]) << 4) | (uint16(buf[pos+1]) >> 4) + if syncWord != 0xfff { + return fmt.Errorf("invalid syncword") + } + + protectionAbsent := buf[pos+1] & 0x01 + if protectionAbsent != 1 { + return fmt.Errorf("CRC is not supported") + } + + pkt := &ADTSPacket{} + + pkt.Type = ObjectType((buf[pos+2] >> 6) + 1) + switch pkt.Type { + case ObjectTypeAACLC: + default: + return fmt.Errorf("unsupported audio type: %d", pkt.Type) + } + + sampleRateIndex := (buf[pos+2] >> 2) & 0x0F + switch { + case sampleRateIndex <= 12: + pkt.SampleRate = sampleRates[sampleRateIndex] + + default: + return fmt.Errorf("invalid sample rate index: %d", sampleRateIndex) + } + + channelConfig := ((buf[pos+2] & 0x01) << 2) | ((buf[pos+3] >> 6) & 0x03) + switch { + case channelConfig >= 1 && channelConfig <= 6: + pkt.ChannelCount = int(channelConfig) + + case channelConfig == 7: + pkt.ChannelCount = 8 + + default: + return fmt.Errorf("invalid channel configuration: %d", channelConfig) + } + + frameLen := int(((uint16(buf[pos+3])&0x03)<<11)| + (uint16(buf[pos+4])<<3)| + ((uint16(buf[pos+5])>>5)&0x07)) - 7 + if frameLen > MaxAccessUnitSize { + return fmt.Errorf("AU size (%d) is too big (maximum is %d)", frameLen, MaxAccessUnitSize) + } + + frameCount := buf[pos+6] & 0x03 + if frameCount != 0 { + return fmt.Errorf("frame count greater than 1 is not supported") + } + + if len(buf[pos+7:]) < frameLen { + return fmt.Errorf("invalid frame length") + } + + pkt.AU = buf[pos+7 : pos+7+frameLen] + pos += 7 + frameLen + + *ps = append(*ps, pkt) + + if (bl - pos) == 0 { + break + } + } + + return nil +} + +func (ps ADTSPackets) marshalSize() int { + n := 0 + for _, pkt := range ps { + n += 7 + len(pkt.AU) + } + return n +} + +// Marshal encodes ADTS packets into an ADTS stream. +func (ps ADTSPackets) Marshal() ([]byte, error) { + buf := make([]byte, ps.marshalSize()) + pos := 0 + + for _, pkt := range ps { + sampleRateIndex, ok := reverseSampleRates[pkt.SampleRate] + if !ok { + return nil, fmt.Errorf("invalid sample rate: %d", pkt.SampleRate) + } + + var channelConfig int + switch { + case pkt.ChannelCount >= 1 && pkt.ChannelCount <= 6: + channelConfig = pkt.ChannelCount + + case pkt.ChannelCount == 8: + channelConfig = 7 + + default: + return nil, fmt.Errorf("invalid channel count (%d)", pkt.ChannelCount) + } + + frameLen := len(pkt.AU) + 7 + + fullness := 0x07FF // like ffmpeg does + + buf[pos+0] = 0xFF + buf[pos+1] = 0xF1 + buf[pos+2] = uint8((int(pkt.Type-1) << 6) | (sampleRateIndex << 2) | ((channelConfig >> 2) & 0x01)) + buf[pos+3] = uint8((channelConfig&0x03)<<6 | (frameLen>>11)&0x03) + buf[pos+4] = uint8((frameLen >> 3) & 0xFF) + buf[pos+5] = uint8((frameLen&0x07)<<5 | ((fullness >> 6) & 0x1F)) + buf[pos+6] = uint8((fullness & 0x3F) << 2) + pos += 7 + + pos += copy(buf[pos:], pkt.AU) + } + + return buf, nil +} diff --git a/pkg/codecs/mpeg4audio/adts_test.go b/pkg/codecs/mpeg4audio/adts_test.go new file mode 100644 index 0000000..c2212c1 --- /dev/null +++ b/pkg/codecs/mpeg4audio/adts_test.go @@ -0,0 +1,124 @@ +package mpeg4audio + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var casesADTS = []struct { + name string + byts []byte + pkts ADTSPackets +}{ + { + "single", + []byte{0xff, 0xf1, 0x4c, 0x80, 0x1, 0x3f, 0xfc, 0xaa, 0xbb}, + ADTSPackets{ + { + Type: ObjectTypeAACLC, + SampleRate: 48000, + ChannelCount: 2, + AU: []byte{0xaa, 0xbb}, + }, + }, + }, + { + "multiple", + []byte{ + 0xff, 0xf1, 0x50, 0x40, 0x1, 0x3f, 0xfc, 0xaa, + 0xbb, 0xff, 0xf1, 0x4c, 0x80, 0x1, 0x3f, 0xfc, + 0xcc, 0xdd, + }, + ADTSPackets{ + { + Type: ObjectTypeAACLC, + SampleRate: 44100, + ChannelCount: 1, + AU: []byte{0xaa, 0xbb}, + }, + { + Type: ObjectTypeAACLC, + SampleRate: 48000, + ChannelCount: 2, + AU: []byte{0xcc, 0xdd}, + }, + }, + }, +} + +func TestADTSUnmarshal(t *testing.T) { + for _, ca := range casesADTS { + t.Run(ca.name, func(t *testing.T) { + var pkts ADTSPackets + err := pkts.Unmarshal(ca.byts) + require.NoError(t, err) + require.Equal(t, ca.pkts, pkts) + }) + } +} + +func TestADTSMarshal(t *testing.T) { + for _, ca := range casesADTS { + t.Run(ca.name, func(t *testing.T) { + byts, err := ca.pkts.Marshal() + require.NoError(t, err) + require.Equal(t, ca.byts, byts) + }) + } +} + +func TestADTSUnmarshalErrors(t *testing.T) { + for _, ca := range []struct { + name string + byts []byte + err string + }{ + { + "invalid length", + []byte{0x01}, + "invalid length", + }, + { + "invalid syncword", + []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + "invalid syncword", + }, + { + "crc", + []byte{0xff, 0xF0, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + "CRC is not supported", + }, + { + "invalid audio type", + []byte{0xff, 0xf1, 0x8c, 0x80, 0x1, 0x3f, 0xfc, 0xaa}, + "unsupported audio type: 3", + }, + { + "invalid sample rate index", + []byte{0xff, 0xf1, 0x74, 0x80, 0x1, 0x3f, 0xfc, 0xaa}, + "invalid sample rate index: 13", + }, + { + "invalid channel configuration", + []byte{0xff, 0xf1, 0x4c, 0x00, 0x1, 0x3f, 0xfc, 0xaa}, + "invalid channel configuration: 0", + }, + { + "multiple frame count", + []byte{0xff, 0xf1, 0x4c, 0x80, 0x1, 0x3f, 0xfd, 0xaa}, + "frame count greater than 1 is not supported", + }, + { + "invalid frame length", + []byte{0xff, 0xf1, 0x4c, 0x80, 0x1, 0x3f, 0xfc, 0xaa}, + "invalid frame length", + }, + } { + t.Run(ca.name, func(t *testing.T) { + var pkts ADTSPackets + err := pkts.Unmarshal(ca.byts) + require.EqualError(t, err, ca.err) + }) + } +} diff --git a/pkg/codecs/mpeg4audio/config.go b/pkg/codecs/mpeg4audio/config.go new file mode 100644 index 0000000..6ec3742 --- /dev/null +++ b/pkg/codecs/mpeg4audio/config.go @@ -0,0 +1,235 @@ +package mpeg4audio + +import ( + "fmt" + + "github.com/bluenviron/mediabase/pkg/bits" +) + +// Config is a MPEG-4 Audio configuration. +type Config struct { + Type ObjectType + SampleRate int + ChannelCount int + + // SBR / PS specific + ExtensionType ObjectType + ExtensionSampleRate int + + // AAC-LC specific + FrameLengthFlag bool + DependsOnCoreCoder bool + CoreCoderDelay uint16 +} + +// Unmarshal decodes a Config. +func (c *Config) Unmarshal(buf []byte) error { + pos := 0 + + tmp, err := bits.ReadBits(buf, &pos, 5) + if err != nil { + return err + } + c.Type = ObjectType(tmp) + + switch c.Type { + case ObjectTypeAACLC: + case ObjectTypeSBR: + case ObjectTypePS: + default: + return fmt.Errorf("unsupported object type: %d", c.Type) + } + + sampleRateIndex, err := bits.ReadBits(buf, &pos, 4) + if err != nil { + return err + } + + switch { + case sampleRateIndex <= 12: + c.SampleRate = sampleRates[sampleRateIndex] + + case sampleRateIndex == 0x0F: + tmp, err := bits.ReadBits(buf, &pos, 24) + if err != nil { + return err + } + c.SampleRate = int(tmp) + + default: + return fmt.Errorf("invalid sample rate index (%d)", sampleRateIndex) + } + + channelConfig, err := bits.ReadBits(buf, &pos, 4) + if err != nil { + return err + } + + switch { + case channelConfig == 0: + return fmt.Errorf("not yet supported") + + case channelConfig >= 1 && channelConfig <= 6: + c.ChannelCount = int(channelConfig) + + case channelConfig == 7: + c.ChannelCount = 8 + + default: + return fmt.Errorf("invalid channel configuration (%d)", channelConfig) + } + + if c.Type == ObjectTypeSBR || c.Type == ObjectTypePS { + c.ExtensionType = c.Type + extensionSamplingFrequencyIndex, err := bits.ReadBits(buf, &pos, 4) + if err != nil { + return err + } + + switch { + case extensionSamplingFrequencyIndex <= 12: + c.ExtensionSampleRate = sampleRates[extensionSamplingFrequencyIndex] + + case extensionSamplingFrequencyIndex == 0x0F: + tmp, err := bits.ReadBits(buf, &pos, 24) + if err != nil { + return err + } + c.ExtensionSampleRate = int(tmp) + + default: + return fmt.Errorf("invalid extension sample rate index (%d)", extensionSamplingFrequencyIndex) + } + + tmp, err = bits.ReadBits(buf, &pos, 5) + if err != nil { + return err + } + c.Type = ObjectType(tmp) + + if c.Type != ObjectTypeAACLC { + return fmt.Errorf("unsupported object type: %d", c.Type) + } + } + + c.FrameLengthFlag, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + c.DependsOnCoreCoder, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if c.DependsOnCoreCoder { + tmp, err := bits.ReadBits(buf, &pos, 14) + if err != nil { + return err + } + c.CoreCoderDelay = uint16(tmp) + } + + extensionFlag, err := bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if extensionFlag { + return fmt.Errorf("unsupported") + } + + return nil +} + +func (c Config) marshalSize() int { + n := 5 + 4 + 3 + + _, ok := reverseSampleRates[c.SampleRate] + if !ok { + n += 28 + } else { + n += 4 + } + + if c.ExtensionType == ObjectTypeSBR || c.ExtensionType == ObjectTypePS { + _, ok := reverseSampleRates[c.ExtensionSampleRate] + if !ok { + n += 28 + } else { + n += 4 + } + n += 5 + } else if c.DependsOnCoreCoder { + n += 14 + } + + ret := n / 8 + if (n % 8) != 0 { + ret++ + } + + return ret +} + +// Marshal encodes a Config. +func (c Config) Marshal() ([]byte, error) { + buf := make([]byte, c.marshalSize()) + pos := 0 + + if c.ExtensionType == ObjectTypeSBR || c.ExtensionType == ObjectTypePS { + bits.WriteBits(buf, &pos, uint64(c.ExtensionType), 5) + } else { + bits.WriteBits(buf, &pos, uint64(c.Type), 5) + } + + sampleRateIndex, ok := reverseSampleRates[c.SampleRate] + if !ok { + bits.WriteBits(buf, &pos, uint64(15), 4) + bits.WriteBits(buf, &pos, uint64(c.SampleRate), 24) + } else { + bits.WriteBits(buf, &pos, uint64(sampleRateIndex), 4) + } + + var channelConfig int + switch { + case c.ChannelCount >= 1 && c.ChannelCount <= 6: + channelConfig = c.ChannelCount + + case c.ChannelCount == 8: + channelConfig = 7 + + default: + return nil, fmt.Errorf("invalid channel count (%d)", c.ChannelCount) + } + bits.WriteBits(buf, &pos, uint64(channelConfig), 4) + + if c.ExtensionType == ObjectTypeSBR || c.ExtensionType == ObjectTypePS { + sampleRateIndex, ok := reverseSampleRates[c.ExtensionSampleRate] + if !ok { + bits.WriteBits(buf, &pos, uint64(0x0F), 4) + bits.WriteBits(buf, &pos, uint64(c.ExtensionSampleRate), 24) + } else { + bits.WriteBits(buf, &pos, uint64(sampleRateIndex), 4) + } + bits.WriteBits(buf, &pos, uint64(c.Type), 5) + } else { + if c.FrameLengthFlag { + bits.WriteBits(buf, &pos, 1, 1) + } else { + bits.WriteBits(buf, &pos, 0, 1) + } + + if c.DependsOnCoreCoder { + bits.WriteBits(buf, &pos, 1, 1) + } else { + bits.WriteBits(buf, &pos, 0, 1) + } + + if c.DependsOnCoreCoder { + bits.WriteBits(buf, &pos, uint64(c.CoreCoderDelay), 14) + } + } + + return buf, nil +} diff --git a/pkg/codecs/mpeg4audio/config_test.go b/pkg/codecs/mpeg4audio/config_test.go new file mode 100644 index 0000000..d6c01ff --- /dev/null +++ b/pkg/codecs/mpeg4audio/config_test.go @@ -0,0 +1,166 @@ +//go:build go1.18 +// +build go1.18 + +package mpeg4audio + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var configCases = []struct { + name string + enc []byte + dec Config +}{ + { + "aac-lc 16khz mono", + []byte{0x14, 0x08}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 16000, + ChannelCount: 1, + }, + }, + { + "aac-lc 44.1khz mono", + []byte{0x12, 0x08}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 44100, + ChannelCount: 1, + }, + }, + { + "aac-lc 44.1khz 5.1", + []byte{0x12, 0x30}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 44100, + ChannelCount: 6, + }, + }, + { + "aac-lc 48khz stereo", + []byte{17, 144}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 48000, + ChannelCount: 2, + }, + }, + { + "aac-lc 53khz stereo", + []byte{0x17, 0x80, 0x67, 0x84, 0x10}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 53000, + ChannelCount: 2, + }, + }, + { + "aac-lc 96khz stereo delay", + []byte{0x10, 0x12, 0x0c, 0x08}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 96000, + ChannelCount: 2, + DependsOnCoreCoder: true, + CoreCoderDelay: 385, + }, + }, + { + "aac-lc 44.1khz 8 chans", + []byte{0x12, 0x38}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 44100, + ChannelCount: 8, + }, + }, + { + "sbr (he-aac v1) 44.1khz mono", + []byte{0x2b, 0x8a, 0x08, 0x00}, + Config{ + Type: ObjectTypeAACLC, + SampleRate: 22050, + ChannelCount: 1, + ExtensionSampleRate: 44100, + ExtensionType: ObjectTypeSBR, + }, + }, + { + "sbr (he-aac v1) 44.1khz stereo", + []byte{0x2b, 0x92, 0x08, 0x00}, // the data from fdk_aac + Config{ + Type: ObjectTypeAACLC, + SampleRate: 22050, + ChannelCount: 2, + ExtensionSampleRate: 44100, + ExtensionType: ObjectTypeSBR, + }, + }, + { + "ps (he-aac v2) 48khz stereo", + []byte{0xeb, 0x09, 0x88, 0x00}, // the data from fdk_aac + Config{ + Type: ObjectTypeAACLC, + SampleRate: 24000, + ChannelCount: 1, // for he_aac v2, ChannelCount only set to 1 ? + ExtensionSampleRate: 48000, + ExtensionType: ObjectTypePS, + }, + }, +} + +func TestConfigUnmarshal(t *testing.T) { + for _, ca := range configCases { + t.Run(ca.name, func(t *testing.T) { + var dec Config + err := dec.Unmarshal(ca.enc) + require.NoError(t, err) + require.Equal(t, ca.dec, dec) + }) + } +} + +func TestConfigMarshal(t *testing.T) { + for _, ca := range configCases { + t.Run(ca.name, func(t *testing.T) { + enc, err := ca.dec.Marshal() + require.NoError(t, err) + require.Equal(t, ca.enc, enc) + }) + } +} + +func TestConfigMarshalErrors(t *testing.T) { + for _, ca := range []struct { + name string + conf Config + err string + }{ + { + "invalid channel config", + Config{ + Type: ObjectTypeAACLC, + SampleRate: 44100, + ChannelCount: 0, + }, + "invalid channel count (0)", + }, + } { + t.Run(ca.name, func(t *testing.T) { + _, err := ca.conf.Marshal() + require.EqualError(t, err, ca.err) + }) + } +} + +func FuzzConfigUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + var conf Config + conf.Unmarshal(b) + }) +} diff --git a/pkg/codecs/mpeg4audio/mpeg4audio.go b/pkg/codecs/mpeg4audio/mpeg4audio.go new file mode 100644 index 0000000..6226118 --- /dev/null +++ b/pkg/codecs/mpeg4audio/mpeg4audio.go @@ -0,0 +1,10 @@ +// Package mpeg4audio contains utilities to work with MPEG-4 audio codecs. +package mpeg4audio + +const ( + // MaxAccessUnitSize is the maximum size of an Access Unit (AU). + MaxAccessUnitSize = 5 * 1024 + + // SamplesPerAccessUnit is the number of samples contained by a single AAC AU. + SamplesPerAccessUnit = 1024 +) diff --git a/pkg/codecs/mpeg4audio/object_type.go b/pkg/codecs/mpeg4audio/object_type.go new file mode 100644 index 0000000..7051c7f --- /dev/null +++ b/pkg/codecs/mpeg4audio/object_type.go @@ -0,0 +1,11 @@ +package mpeg4audio + +// ObjectType is a MPEG-4 Audio object type. +type ObjectType int + +// supported types. +const ( + ObjectTypeAACLC ObjectType = 2 + ObjectTypeSBR ObjectType = 5 + ObjectTypePS ObjectType = 29 +) diff --git a/pkg/codecs/mpeg4audio/sample_rates.go b/pkg/codecs/mpeg4audio/sample_rates.go new file mode 100644 index 0000000..660b86e --- /dev/null +++ b/pkg/codecs/mpeg4audio/sample_rates.go @@ -0,0 +1,33 @@ +package mpeg4audio + +var sampleRates = []int{ + 96000, + 88200, + 64000, + 48000, + 44100, + 32000, + 24000, + 22050, + 16000, + 12000, + 11025, + 8000, + 7350, +} + +var reverseSampleRates = map[int]int{ + 96000: 0, + 88200: 1, + 64000: 2, + 48000: 3, + 44100: 4, + 32000: 5, + 24000: 6, + 22050: 7, + 16000: 8, + 12000: 9, + 11025: 10, + 8000: 11, + 7350: 12, +} diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/0de38b892c93cde2f2b32eeb00f6097b53b4250a097ff80e498ceb3f0bfb18e0 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/0de38b892c93cde2f2b32eeb00f6097b53b4250a097ff80e498ceb3f0bfb18e0 new file mode 100644 index 0000000..86f2599 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/0de38b892c93cde2f2b32eeb00f6097b53b4250a097ff80e498ceb3f0bfb18e0 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x102") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/2407269c6f2b6741b662b2a3f8a5bb9528c50c25e5ff75ee285eb272027491b2 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/2407269c6f2b6741b662b2a3f8a5bb9528c50c25e5ff75ee285eb272027491b2 new file mode 100644 index 0000000..c5cd837 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/2407269c6f2b6741b662b2a3f8a5bb9528c50c25e5ff75ee285eb272027491b2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("(") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/2f1e03b45b2a93962108e8a940cc0ee647a444fa09ed6839dac31246ff1d5a19 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/2f1e03b45b2a93962108e8a940cc0ee647a444fa09ed6839dac31246ff1d5a19 new file mode 100644 index 0000000..d82bac9 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/2f1e03b45b2a93962108e8a940cc0ee647a444fa09ed6839dac31246ff1d5a19 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\xef\xef") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/41b96153add60a0a300ad04393d1b16838280d9c256f3f5819ffea4dcfa87db1 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/41b96153add60a0a300ad04393d1b16838280d9c256f3f5819ffea4dcfa87db1 new file mode 100644 index 0000000..faf2f31 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/41b96153add60a0a300ad04393d1b16838280d9c256f3f5819ffea4dcfa87db1 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("(\x00") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/4e84166ad43e1c5846255d0155c259a95700b8fd3c3ada7d0cee9d8a99ad413f b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/4e84166ad43e1c5846255d0155c259a95700b8fd3c3ada7d0cee9d8a99ad413f new file mode 100644 index 0000000..c0584ba --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/4e84166ad43e1c5846255d0155c259a95700b8fd3c3ada7d0cee9d8a99ad413f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("(0\b") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/6962f04b357ab1240e26ab394ad6eb8127068a73f80ea005094fbe9e69874e65 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/6962f04b357ab1240e26ab394ad6eb8127068a73f80ea005094fbe9e69874e65 new file mode 100644 index 0000000..2d7d606 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/6962f04b357ab1240e26ab394ad6eb8127068a73f80ea005094fbe9e69874e65 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("(00") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/bbffbee953abbb79185a8caf6831ec6ab83dcc1f3ab1d748b0abe8ed3211bcda b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/bbffbee953abbb79185a8caf6831ec6ab83dcc1f3ab1d748b0abe8ed3211bcda new file mode 100644 index 0000000..f7a5b49 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/bbffbee953abbb79185a8caf6831ec6ab83dcc1f3ab1d748b0abe8ed3211bcda @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("(0") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/c12d7ec300bda22f7db490db8312dc2e64752791e45fec451533b5706f56bed9 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/c12d7ec300bda22f7db490db8312dc2e64752791e45fec451533b5706f56bed9 new file mode 100644 index 0000000..2cc8e6b --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/c12d7ec300bda22f7db490db8312dc2e64752791e45fec451533b5706f56bed9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x101") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 new file mode 100644 index 0000000..67322c7 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/d00ea3865173809d88de52497a25b23b2568d3c08b1d2b49a1ae857b6497f223 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/d00ea3865173809d88de52497a25b23b2568d3c08b1d2b49a1ae857b6497f223 new file mode 100644 index 0000000..8cd503b --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/d00ea3865173809d88de52497a25b23b2568d3c08b1d2b49a1ae857b6497f223 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("(A") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/f5da56f6a7a5431290dccfd0b7548511decda24d17c05fa7ddeccb3b0b049518 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/f5da56f6a7a5431290dccfd0b7548511decda24d17c05fa7ddeccb3b0b049518 new file mode 100644 index 0000000..f885c04 --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/f5da56f6a7a5431290dccfd0b7548511decda24d17c05fa7ddeccb3b0b049518 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte(".\xef") diff --git a/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/fca08d22f8534499db40e6510424748f46929ac0e89aca9dc59096b7c2d59dc7 b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/fca08d22f8534499db40e6510424748f46929ac0e89aca9dc59096b7c2d59dc7 new file mode 100644 index 0000000..39ccc7c --- /dev/null +++ b/pkg/codecs/mpeg4audio/testdata/fuzz/FuzzConfigUnmarshal/fca08d22f8534499db40e6510424748f46929ac0e89aca9dc59096b7c2d59dc7 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("(7\xed") diff --git a/scripts/format.mk b/scripts/format.mk new file mode 100644 index 0000000..0475707 --- /dev/null +++ b/scripts/format.mk @@ -0,0 +1,10 @@ +define DOCKERFILE_FORMAT +FROM $(BASE_IMAGE) +RUN go install mvdan.cc/gofumpt@v0.3.1 +endef +export DOCKERFILE_FORMAT + +format: + echo "$$DOCKERFILE_FORMAT" | docker build -q . -f - -t temp + docker run --rm -it -v $(PWD):/s -w /s temp \ + sh -c "gofumpt -l -w ." diff --git a/scripts/lint.mk b/scripts/lint.mk new file mode 100644 index 0000000..9c73673 --- /dev/null +++ b/scripts/lint.mk @@ -0,0 +1,4 @@ +lint: + docker run --rm -v $(PWD):/app -w /app \ + $(LINT_IMAGE) \ + golangci-lint run -v diff --git a/scripts/mod-tidy.mk b/scripts/mod-tidy.mk new file mode 100644 index 0000000..b02d72a --- /dev/null +++ b/scripts/mod-tidy.mk @@ -0,0 +1,3 @@ +mod-tidy: + docker run --rm -it -v $(PWD):/s -w /s $(BASE_IMAGE) \ + sh -c "apk add git && GOPROXY=direct go mod tidy" diff --git a/scripts/test.mk b/scripts/test.mk new file mode 100644 index 0000000..3defabd --- /dev/null +++ b/scripts/test.mk @@ -0,0 +1,21 @@ +test-pkg: + go test -v -race -coverprofile=coverage-pkg.txt ./pkg/... + +test-nodocker: test-pkg + +define DOCKERFILE_TEST +FROM $(BASE_IMAGE) +RUN apk add --no-cache make git gcc musl-dev +WORKDIR /s +COPY go.mod go.sum ./ +RUN go mod download +COPY . ./ +endef +export DOCKERFILE_TEST + +test: + echo "$$DOCKERFILE_TEST" | docker build -q . -f - -t temp + docker run --rm -it \ + --name temp \ + temp \ + make test-nodocker