-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #287 from tanghaowillow/add-av1
feat: add av01 and av1C box
- Loading branch information
Showing
7 changed files
with
246 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package av1 | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
|
||
"github.com/Eyevinn/mp4ff/bits" | ||
) | ||
|
||
// AV1 parsing errors | ||
var ( | ||
ErrInvalidMarker = errors.New("invalid marker value found in AV1CodecConfigurationRecord") | ||
ErrInvalidVersion = errors.New("unsupported AV1CodecConfigurationRecord version") | ||
ErrNonZeroReservedBits = errors.New("non-zero reserved bits found in AV1CodecConfigurationRecord") | ||
) | ||
|
||
// CodecConfRec - AV1CodecConfigurationRecord | ||
// Specified in https://github.com/AOMediaCodec/av1-isobmff/releases/tag/v1.2.0 | ||
type CodecConfRec struct { | ||
Version byte | ||
SeqProfile byte | ||
SeqLevelIdx0 byte | ||
SeqTier0 byte | ||
HighBitdepth byte | ||
TwelveBit byte | ||
MonoChrome byte | ||
ChromaSubsamplingX byte | ||
ChromaSubsamplingY byte | ||
ChromaSamplePosition byte | ||
InitialPresentationDelayPresent byte | ||
InitialPresentationDelayMinusOne byte | ||
ConfigOBUs []byte | ||
} | ||
|
||
// DecodeAVCDecConfRec - decode an AV1CodecConfRec | ||
func DecodeAV1CodecConfRec(data []byte) (CodecConfRec, error) { | ||
av1drc := CodecConfRec{} | ||
|
||
Marker := data[0] >> 7 | ||
if Marker != 1 { | ||
return CodecConfRec{}, ErrInvalidMarker | ||
} | ||
av1drc.Version = data[0] & 0x7F | ||
if av1drc.Version != 1 { | ||
return CodecConfRec{}, ErrInvalidVersion | ||
} | ||
av1drc.SeqProfile = data[1] >> 5 | ||
av1drc.SeqLevelIdx0 = data[1] & 0x1F | ||
av1drc.SeqTier0 = data[2] >> 7 | ||
av1drc.HighBitdepth = (data[2] >> 6) & 0x01 | ||
av1drc.TwelveBit = (data[2] >> 5) & 0x01 | ||
av1drc.MonoChrome = (data[2] >> 4) & 0x01 | ||
av1drc.ChromaSubsamplingX = (data[2] >> 3) & 0x01 | ||
av1drc.ChromaSubsamplingY = (data[2] >> 2) & 0x01 | ||
av1drc.ChromaSamplePosition = data[2] & 0x03 | ||
if data[3]>>5 != 0 { | ||
return CodecConfRec{}, ErrNonZeroReservedBits | ||
} | ||
av1drc.InitialPresentationDelayPresent = (data[3] >> 4) & 0x01 | ||
if av1drc.InitialPresentationDelayPresent == 1 { | ||
av1drc.InitialPresentationDelayMinusOne = data[3] & 0x0F | ||
} else { | ||
if data[3]&0x0F != 0 { | ||
return CodecConfRec{}, ErrNonZeroReservedBits | ||
} | ||
av1drc.InitialPresentationDelayMinusOne = 0 | ||
} | ||
if len(data) > 4 { | ||
av1drc.ConfigOBUs = data[4:] | ||
} | ||
|
||
return av1drc, nil | ||
} | ||
|
||
// Size - total size in bytes | ||
func (a *CodecConfRec) Size() uint64 { | ||
return uint64(4 + len(a.ConfigOBUs)) | ||
} | ||
|
||
// EncodeSW- write an AV1CodecConfRec to w | ||
func (a *CodecConfRec) Encode(w io.Writer) error { | ||
sw := bits.NewFixedSliceWriter(int(a.Size())) | ||
err := a.EncodeSW(sw) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = w.Write(sw.Bytes()) | ||
return err | ||
} | ||
|
||
// EncodeSW- write an AV1CodecConfRec to sw | ||
func (a *CodecConfRec) EncodeSW(sw bits.SliceWriter) error { | ||
sw.WriteBits(1, 1) | ||
sw.WriteBits(uint(a.Version), 7) | ||
sw.WriteBits(uint(a.SeqProfile), 3) | ||
sw.WriteBits(uint(a.SeqLevelIdx0), 5) | ||
sw.WriteBits(uint(a.SeqTier0), 1) | ||
sw.WriteBits(uint(a.HighBitdepth), 1) | ||
sw.WriteBits(uint(a.TwelveBit), 1) | ||
sw.WriteBits(uint(a.MonoChrome), 1) | ||
sw.WriteBits(uint(a.ChromaSubsamplingX), 1) | ||
sw.WriteBits(uint(a.ChromaSubsamplingY), 1) | ||
sw.WriteBits(uint(a.ChromaSamplePosition), 2) | ||
sw.WriteBits(0, 3) | ||
sw.WriteBits(uint(a.InitialPresentationDelayPresent), 1) | ||
if a.InitialPresentationDelayPresent == 1 { | ||
sw.WriteBits(uint(a.InitialPresentationDelayMinusOne), 4) | ||
} else { | ||
sw.WriteBits(0, 4) | ||
} | ||
if len(a.ConfigOBUs) != 0 { | ||
sw.WriteBytes(a.ConfigOBUs) | ||
} | ||
|
||
return sw.AccError() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package av1 | ||
|
||
import ( | ||
"encoding/hex" | ||
"testing" | ||
|
||
"github.com/go-test/deep" | ||
) | ||
|
||
const av1DecoderConfigRecord = "81094c000a0b0000004aabbfc377ffe701" | ||
const configOBUs = "0a0b0000004aabbfc377ffe701" | ||
|
||
func TestDecodeAV1DecConfRec(t *testing.T) { | ||
byteData, _ := hex.DecodeString(av1DecoderConfigRecord) | ||
configOBUsBytes, _ := hex.DecodeString(configOBUs) | ||
|
||
wanted := CodecConfRec{ | ||
Version: 1, | ||
SeqProfile: 0, | ||
SeqLevelIdx0: 9, | ||
SeqTier0: 0, | ||
HighBitdepth: 1, | ||
TwelveBit: 0, | ||
MonoChrome: 0, | ||
ChromaSubsamplingX: 1, | ||
ChromaSubsamplingY: 1, | ||
ChromaSamplePosition: 0, | ||
InitialPresentationDelayPresent: 0, | ||
InitialPresentationDelayMinusOne: 0, | ||
ConfigOBUs: configOBUsBytes, | ||
} | ||
|
||
got, err := DecodeAV1CodecConfRec(byteData) | ||
if err != nil { | ||
t.Error("Error parsing Av1DecoderConfigRecord") | ||
} | ||
if diff := deep.Equal(got, wanted); diff != nil { | ||
t.Error(diff) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/* | ||
Package av1 - parsing of av1 AV1CodecConfigurationRecord. | ||
*/ | ||
package av1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package mp4 | ||
|
||
import ( | ||
"encoding/hex" | ||
"io" | ||
|
||
"github.com/Eyevinn/mp4ff/av1" | ||
"github.com/Eyevinn/mp4ff/bits" | ||
) | ||
|
||
type Av1CBox struct { | ||
av1.CodecConfRec | ||
} | ||
|
||
// DecodeAv1C - box-specific decode | ||
func DecodeAv1C(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) { | ||
data, err := readBoxBody(r, hdr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
av1DecConfRec, err := av1.DecodeAV1CodecConfRec(data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Av1CBox{av1DecConfRec}, nil | ||
} | ||
|
||
// DecodeAv1CSR - box-specific decode | ||
func DecodeAv1CSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, error) { | ||
av1DecConfRec, err := av1.DecodeAV1CodecConfRec(sr.ReadBytes(hdr.payloadLen())) | ||
return &Av1CBox{av1DecConfRec}, err | ||
} | ||
|
||
// Type - return box type | ||
func (b *Av1CBox) Type() string { | ||
return "av1C" | ||
} | ||
|
||
// Size - return calculated size | ||
func (b *Av1CBox) Size() uint64 { | ||
return uint64(boxHeaderSize + b.CodecConfRec.Size()) | ||
} | ||
|
||
// Encode - write box to w | ||
func (b *Av1CBox) Encode(w io.Writer) error { | ||
err := EncodeHeader(b, w) | ||
if err != nil { | ||
return err | ||
} | ||
return b.CodecConfRec.Encode(w) | ||
} | ||
|
||
// Encode - write box to sw | ||
func (b *Av1CBox) EncodeSW(sw bits.SliceWriter) error { | ||
err := EncodeHeaderSW(b, sw) | ||
if err != nil { | ||
return err | ||
} | ||
return b.CodecConfRec.EncodeSW(sw) | ||
} | ||
|
||
// Info - box-specific Info | ||
func (b *Av1CBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error { | ||
bd := newInfoDumper(w, indent, b, -1, 0) | ||
bd.write(" - SeqProfile: %d", b.SeqProfile) | ||
bd.write(" - SeqLevelIdx0: %d", b.SeqLevelIdx0) | ||
bd.write(" - SeqTier0: %d", b.SeqTier0) | ||
bd.write(" - HighBitdepth: %d", b.HighBitdepth) | ||
bd.write(" - TwelveBit: %d", b.TwelveBit) | ||
bd.write(" - MonoChrome: %d", b.MonoChrome) | ||
bd.write(" - ChromaSubsamplingX: %d", b.ChromaSubsamplingX) | ||
bd.write(" - ChromaSubsamplingY: %d", b.ChromaSubsamplingY) | ||
bd.write(" - ChromaSamplePosition: %d", b.ChromaSamplePosition) | ||
if b.InitialPresentationDelayPresent == 1 { | ||
bd.write(" - InitialPresentationDelayMinusOne: %d", b.InitialPresentationDelayMinusOne) | ||
} | ||
bd.write(" - ConfigOBUs: %s", hex.EncodeToString(b.ConfigOBUs)) | ||
return bd.err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters