codec/h264/h264dec: separated VUI and HRD from SPS struct

Took out all VUI and HRD parameters from the SPS struct and gave them their own structs - VUIParameters and HRDParameters, along with 'contructors'
NewVUIParameters and NewHRDParameters to parse from a bits.BitReader and populate the fields of the struct.
This commit is contained in:
Saxon 2019-07-21 22:11:24 +09:30
parent 269b607606
commit a755ccfc58
5 changed files with 451 additions and 446 deletions

View File

@ -35,14 +35,14 @@ func YOffset(yRefMin16, refMbH int) int {
}
func MbWidthC(sps *SPS) int {
mbWidthC := 16 / SubWidthC(sps)
if sps.ChromaFormat == chromaMonochrome || sps.UseSeparateColorPlane {
if sps.ChromaFormatIDC == chromaMonochrome || sps.SeparateColorPlaneFlag {
mbWidthC = 0
}
return mbWidthC
}
func MbHeightC(sps *SPS) int {
mbHeightC := 16 / SubHeightC(sps)
if sps.ChromaFormat == chromaMonochrome || sps.UseSeparateColorPlane {
if sps.ChromaFormatIDC == chromaMonochrome || sps.SeparateColorPlaneFlag {
mbHeightC = 0
}
return mbHeightC

View File

@ -195,7 +195,7 @@ func NewPPS(sps *SPS, rbsp []byte, showPacket bool) (*PPS, error) {
if pps.PicScalingMatrixPresent {
v := 6
if sps.ChromaFormat != chroma444 {
if sps.ChromaFormatIDC != chroma444 {
v = 2
}
for i := 0; i < 6+(v*pps.Transform8x8Mode); i++ {
@ -231,9 +231,6 @@ func NewPPS(sps *SPS, rbsp []byte, showPacket bool) (*PPS, error) {
// rbspTrailingBits()
}
if showPacket {
debugPacket("PPS", pps)
}
return &pps, nil
}

View File

@ -145,13 +145,13 @@ func (d SliceData) ae(v int) int {
// 8.2.2
func MbToSliceGroupMap(sps *SPS, pps *PPS, header *SliceHeader) []int {
mbaffFrameFlag := 0
if sps.MBAdaptiveFrameField && !header.FieldPic {
if sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
mbaffFrameFlag = 1
}
mapUnitToSliceGroupMap := MapUnitToSliceGroupMap(sps, pps, header)
mbToSliceGroupMap := []int{}
for i := 0; i <= PicSizeInMbs(sps, header)-1; i++ {
if sps.FrameMbsOnly || header.FieldPic {
if sps.FrameMBSOnlyFlag || header.FieldPic {
mbToSliceGroupMap = append(mbToSliceGroupMap, mapUnitToSliceGroupMap[i])
continue
}
@ -159,7 +159,7 @@ func MbToSliceGroupMap(sps *SPS, pps *PPS, header *SliceHeader) []int {
mbToSliceGroupMap = append(mbToSliceGroupMap, mapUnitToSliceGroupMap[i/2])
continue
}
if !sps.FrameMbsOnly && !sps.MBAdaptiveFrameField && !header.FieldPic {
if !sps.FrameMBSOnlyFlag && !sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
mbToSliceGroupMap = append(
mbToSliceGroupMap,
mapUnitToSliceGroupMap[(i/(2*PicWidthInMbs(sps)))*PicWidthInMbs(sps)+(i%PicWidthInMbs(sps))])
@ -169,7 +169,7 @@ func MbToSliceGroupMap(sps *SPS, pps *PPS, header *SliceHeader) []int {
}
func PicWidthInMbs(sps *SPS) int {
return sps.PicWidthInMbsMinus1 + 1
return sps.PicWidthInMBSMinus1 + 1
}
func PicHeightInMapUnits(sps *SPS) int {
return sps.PicHeightInMapUnitsMinus1 + 1
@ -178,7 +178,7 @@ func PicSizeInMapUnits(sps *SPS) int {
return PicWidthInMbs(sps) * PicHeightInMapUnits(sps)
}
func FrameHeightInMbs(sps *SPS) int {
return (2 - flagVal(sps.FrameMbsOnly)) * PicHeightInMapUnits(sps)
return (2 - flagVal(sps.FrameMBSOnlyFlag)) * PicHeightInMapUnits(sps)
}
func PicHeightInMbs(sps *SPS, header *SliceHeader) int {
return FrameHeightInMbs(sps) / (1 + flagVal(header.FieldPic))
@ -190,13 +190,13 @@ func PicSizeInMbs(sps *SPS, header *SliceHeader) int {
// table 6-1
func SubWidthC(sps *SPS) int {
n := 17
if sps.UseSeparateColorPlane {
if sps.ChromaFormat == chroma444 {
if sps.SeparateColorPlaneFlag {
if sps.ChromaFormatIDC == chroma444 {
return n
}
}
switch sps.ChromaFormat {
switch sps.ChromaFormatIDC {
case chromaMonochrome:
return n
case chroma420:
@ -211,12 +211,12 @@ func SubWidthC(sps *SPS) int {
}
func SubHeightC(sps *SPS) int {
n := 17
if sps.UseSeparateColorPlane {
if sps.ChromaFormat == chroma444 {
if sps.SeparateColorPlaneFlag {
if sps.ChromaFormatIDC == chroma444 {
return n
}
}
switch sps.ChromaFormat {
switch sps.ChromaFormatIDC {
case chromaMonochrome:
return n
case chroma420:
@ -578,17 +578,17 @@ func nextMbAddress(n int, sps *SPS, pps *PPS, header *SliceHeader) int {
i := n + 1
// picSizeInMbs is the number of macroblocks in picture 0
// 7-13
// PicWidthInMbs = sps.PicWidthInMbsMinus1 + 1
// PicWidthInMbs = sps.PicWidthInMBSMinus1 + 1
// PicHeightInMapUnits = sps.PicHeightInMapUnitsMinus1 + 1
// 7-29
// picSizeInMbs = PicWidthInMbs * PicHeightInMbs
// 7-26
// PicHeightInMbs = FrameHeightInMbs / (1 + header.fieldPicFlag)
// 7-18
// FrameHeightInMbs = (2 - ps.FrameMbsOnly) * PicHeightInMapUnits
picWidthInMbs := sps.PicWidthInMbsMinus1 + 1
// FrameHeightInMbs = (2 - ps.FrameMBSOnlyFlag) * PicHeightInMapUnits
picWidthInMbs := sps.PicWidthInMBSMinus1 + 1
picHeightInMapUnits := sps.PicHeightInMapUnitsMinus1 + 1
frameHeightInMbs := (2 - flagVal(sps.FrameMbsOnly)) * picHeightInMapUnits
frameHeightInMbs := (2 - flagVal(sps.FrameMBSOnlyFlag)) * picHeightInMapUnits
picHeightInMbs := frameHeightInMbs / (1 + flagVal(header.FieldPic))
picSizeInMbs := picWidthInMbs * picHeightInMbs
mbToSliceGroupMap := MbToSliceGroupMap(sps, pps, header)
@ -600,7 +600,7 @@ func nextMbAddress(n int, sps *SPS, pps *PPS, header *SliceHeader) int {
func CurrMbAddr(sps *SPS, header *SliceHeader) int {
mbaffFrameFlag := 0
if sps.MBAdaptiveFrameField && !header.FieldPic {
if sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
mbaffFrameFlag = 1
}
@ -608,7 +608,7 @@ func CurrMbAddr(sps *SPS, header *SliceHeader) int {
}
func MbaffFrameFlag(sps *SPS, header *SliceHeader) int {
if sps.MBAdaptiveFrameField && !header.FieldPic {
if sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
return 1
}
return 0
@ -630,7 +630,7 @@ func NewSliceData(sliceContext *SliceContext, br *bits.BitReader) (*SliceData, e
}
}
mbaffFrameFlag := 0
if sliceContext.SPS.MBAdaptiveFrameField && !sliceContext.Slice.Header.FieldPic {
if sliceContext.SPS.MBAdaptiveFrameFieldFlag && !sliceContext.Slice.Header.FieldPic {
mbaffFrameFlag = 1
}
currMbAddr := sliceContext.Slice.Header.FirstMbInSlice * (1 * mbaffFrameFlag)
@ -791,7 +791,7 @@ func NewSliceData(sliceContext *SliceContext, br *bits.BitReader) (*SliceData, e
mbWidthC := 16 / SubWidthC(sliceContext.SPS)
mbHeightC := 16 / SubHeightC(sliceContext.SPS)
// if monochrome
if sliceContext.SPS.ChromaFormat == chromaMonochrome || sliceContext.SPS.UseSeparateColorPlane {
if sliceContext.SPS.ChromaFormatIDC == chromaMonochrome || sliceContext.SPS.SeparateColorPlaneFlag {
mbWidthC = 0
mbHeightC = 0
}
@ -824,7 +824,7 @@ func NewSliceData(sliceContext *SliceContext, br *bits.BitReader) (*SliceData, e
if NumbSubMbPart(subMbType[mbPartIdx]) > 1 {
noSubMbPartSizeLessThan8x8Flag = 0
}
} else if !sliceContext.SPS.Direct8x8Inference {
} else if !sliceContext.SPS.Direct8x8InferenceFlag {
noSubMbPartSizeLessThan8x8Flag = 0
}
}
@ -876,7 +876,7 @@ func NewSliceData(sliceContext *SliceContext, br *bits.BitReader) (*SliceData, e
}
// sliceContext.Slice.Data.CodedBlockPattern = me(v) | ae(v)
if CodedBlockPatternLuma(sliceContext.Slice.Data) > 0 && sliceContext.PPS.Transform8x8Mode == 1 && sliceContext.Slice.Data.MbTypeName != "I_NxN" && noSubMbPartSizeLessThan8x8Flag == 1 && (sliceContext.Slice.Data.MbTypeName != "B_Direct_16x16" || sliceContext.SPS.Direct8x8Inference) {
if CodedBlockPatternLuma(sliceContext.Slice.Data) > 0 && sliceContext.PPS.Transform8x8Mode == 1 && sliceContext.Slice.Data.MbTypeName != "I_NxN" && noSubMbPartSizeLessThan8x8Flag == 1 && (sliceContext.Slice.Data.MbTypeName != "B_Direct_16x16" || sliceContext.SPS.Direct8x8InferenceFlag) {
// TODO: 1 bit or ae(v)
if sliceContext.PPS.EntropyCodingMode == 1 {
binarization := NewBinarization("Transform8x8Flag", sliceContext.Slice.Data)
@ -956,10 +956,10 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, sh
idrPic = true
}
header := SliceHeader{}
if sps.UseSeparateColorPlane {
if sps.SeparateColorPlaneFlag {
header.ChromaArrayType = 0
} else {
header.ChromaArrayType = sps.ChromaFormat
header.ChromaArrayType = sps.ChromaFormatIDC
}
br := bits.NewBitReader(bytes.NewReader(rbsp))
@ -980,7 +980,7 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, sh
return nil, errors.Wrap(err, "could not parse PPSID")
}
if sps.UseSeparateColorPlane {
if sps.SeparateColorPlaneFlag {
b, err := br.ReadBits(2)
if err != nil {
return nil, errors.Wrap(err, "could not read ColorPlaneID")
@ -989,7 +989,7 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, sh
}
// TODO: See 7.4.3
// header.FrameNum = b.NextField("FrameNum", 0)
if !sps.FrameMbsOnly {
if !sps.FrameMBSOnlyFlag {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read FieldPic")
@ -1023,7 +1023,7 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, sh
}
}
}
if sps.PicOrderCountType == 1 && !sps.DeltaPicOrderAlwaysZero {
if sps.PicOrderCountType == 1 && !sps.DeltaPicOrderAlwaysZeroFlag {
header.DeltaPicOrderCnt[0], err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse DeltaPicOrderCnt")
@ -1361,9 +1361,6 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, sh
if err != nil {
return nil, errors.Wrap(err, "could not create slice data")
}
if showPacket {
debugPacket("debug: Header", sliceContext.Slice.Header)
debugPacket("debug: Data", sliceContext.Slice.Data)
}
return sliceContext, nil
}

View File

@ -7,12 +7,12 @@ var subWidthCTests = []struct {
want int
}{
{SPS{}, 17},
{SPS{ChromaFormat: 0}, 17},
{SPS{ChromaFormat: 1}, 2},
{SPS{ChromaFormat: 2}, 2},
{SPS{ChromaFormat: 3}, 1},
{SPS{ChromaFormat: 3, UseSeparateColorPlane: true}, 17},
{SPS{ChromaFormat: 999}, 17},
{SPS{ChromaFormatIDC: 0}, 17},
{SPS{ChromaFormatIDC: 1}, 2},
{SPS{ChromaFormatIDC: 2}, 2},
{SPS{ChromaFormatIDC: 3}, 1},
{SPS{ChromaFormatIDC: 3, SeparateColorPlaneFlag: true}, 17},
{SPS{ChromaFormatIDC: 999}, 17},
}
// TestSubWidthC tests that the correct SubWidthC is returned given
@ -30,12 +30,12 @@ var subHeightCTests = []struct {
want int
}{
{SPS{}, 17},
{SPS{ChromaFormat: 0}, 17},
{SPS{ChromaFormat: 1}, 2},
{SPS{ChromaFormat: 2}, 1},
{SPS{ChromaFormat: 3}, 1},
{SPS{ChromaFormat: 3, UseSeparateColorPlane: true}, 17},
{SPS{ChromaFormat: 999}, 17},
{SPS{ChromaFormatIDC: 0}, 17},
{SPS{ChromaFormatIDC: 1}, 2},
{SPS{ChromaFormatIDC: 2}, 1},
{SPS{ChromaFormatIDC: 3}, 1},
{SPS{ChromaFormatIDC: 3, SeparateColorPlaneFlag: true}, 17},
{SPS{ChromaFormatIDC: 999}, 17},
}
// TestSubHeightC tests that the correct SubHeightC is returned given

View File

@ -2,112 +2,11 @@ package h264dec
import (
"bytes"
"fmt"
"strings"
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
"github.com/pkg/errors"
)
// Specification Page 43 7.3.2.1.1
// Range is always inclusive
// XRange is always exclusive
type SPS struct {
// 8 bits
Profile int
// 6 bits
Constraint0, Constraint1 int
Constraint2, Constraint3 int
Constraint4, Constraint5 int
// 2 bit reserved 0 bits
// 8 bits
Level int
// Range 0 - 31 ; 6 bits
ID int
ChromaFormat int
UseSeparateColorPlane bool
BitDepthLumaMinus8 int
BitDepthChromaMinus8 int
QPrimeYZeroTransformBypass bool
SeqScalingMatrixPresent bool
// Delta is (0-12)-1 ; 4 bits
SeqScalingList []bool // se
// Range 0 - 12; 4 bits
Log2MaxFrameNumMinus4 int
// Range 0 - 2; 2 bits
PicOrderCountType int
// Range 0 - 12; 4 bits
Log2MaxPicOrderCntLSBMin4 int
DeltaPicOrderAlwaysZero bool
// Range (-2^31)+1 to (2^31)-1 ; 31 bits
OffsetForNonRefPic int // Value - 1 (se)
// Range (-2^31)+1 to (2^31)-1 ; 31 bits
OffsetForTopToBottomField int // Value - 1 (se)
// Range 0 - 255 ; 8 bits
NumRefFramesInPicOrderCntCycle int
// Range (-2^31)+1 to (2^31)-1 ; 31 bits
OffsetForRefFrameList []int // Value - 1 ([]se)
// Range 0 - MaxDpbFrames
MaxNumRefFrames int
GapsInFrameNumValueAllowed bool
// Page 77
PicWidthInMbsMinus1 int
// Page 77
PicHeightInMapUnitsMinus1 int
FrameMbsOnly bool
MBAdaptiveFrameField bool
Direct8x8Inference bool
FrameCropping bool
FrameCropLeftOffset int
FrameCropRightOffset int
FrameCropTopOffset int
FrameCropBottomOffset int
VuiParametersPresent bool
VuiParameters []int
AspectRatioInfoPresent bool
AspectRatio int
SarWidth int
SarHeight int
OverscanInfoPresent bool
OverscanAppropriate bool
VideoSignalTypePresent bool
VideoFormat int
VideoFullRange bool
ColorDescriptionPresent bool
ColorPrimaries int
TransferCharacteristics int
MatrixCoefficients int
ChromaLocInfoPresent bool
ChromaSampleLocTypeTopField int
ChromaSampleLocTypeBottomField int
CpbCntMinus1 int
BitRateScale int
CpbSizeScale int
BitRateValueMinus1 []int
Cbr []bool
InitialCpbRemovalDelayLengthMinus1 int
CpbRemovalDelayLengthMinus1 int
CpbSizeValueMinus1 []int
DpbOutputDelayLengthMinus1 int
TimeOffsetLength int
TimingInfoPresent bool
NumUnitsInTick int
TimeScale int
NalHrdParametersPresent bool
FixedFrameRate bool
VclHrdParametersPresent bool
LowHrdDelay bool
PicStructPresent bool
BitstreamRestriction bool
MotionVectorsOverPicBoundaries bool
MaxBytesPerPicDenom int
MaxBitsPerMbDenom int
Log2MaxMvLengthHorizontal int
Log2MaxMvLengthVertical int
MaxDecFrameBuffering int
MaxNumReorderFrames int
}
var (
DefaultScalingMatrix4x4 = [][]int{
{6, 13, 20, 28, 13, 20, 28, 32, 20, 28, 32, 37, 28, 32, 37, 42},
@ -161,98 +60,62 @@ var (
ScalingList8x8 = ScalingList4x4
)
func isInList(l []int, term int) bool {
for _, m := range l {
if m == term {
return true
}
}
return false
}
func debugPacket(name string, packet interface{}) {
logger.Printf("debug: %s packet\n", name)
for _, line := range strings.Split(fmt.Sprintf("%+v", packet), " ") {
logger.Printf("debug: \t%#v\n", line)
}
}
func scalingList(br *bits.BitReader, scalingList []int, sizeOfScalingList int, defaultScalingMatrix []int) error {
lastScale := 8
nextScale := 8
for i := 0; i < sizeOfScalingList; i++ {
if nextScale != 0 {
deltaScale, err := readSe(br)
if err != nil {
return errors.Wrap(err, "could not parse deltaScale")
}
nextScale = (lastScale + deltaScale + 256) % 256
if i == 0 && nextScale == 0 {
// Scaling list should use the default list for this point in the matrix
_ = defaultScalingMatrix
}
}
if nextScale == 0 {
scalingList[i] = lastScale
} else {
scalingList[i] = nextScale
}
lastScale = scalingList[i]
}
return nil
// SPS describes a sequence parameter set as defined by section 7.3.2.1.1 in
// the Specifications.
type SPS struct {
Profile int
Constraint0 int
Constraint1 int
Constraint2 int
Constraint3 int
Constraint4 int
Constraint5 int
LevelIDC int
SPSID int
ChromaFormatIDC int
SeparateColorPlaneFlag bool
BitDepthLumaMinus8 int
BitDepthChromaMinus8 int
QPPrimeYZeroTransformBypassFlag bool
SeqScalingMatrixPresentFlag bool
SeqScalingListPresentFlag []bool
ScalingList4x4 [][]int
UseDefaultScalingMatrix4x4Flag []bool
ScalingList8x8 [][]int
UseDefaultScalingMatrix8x8Flag []bool
Log2MaxFrameNumMinus4 int
PicOrderCountType int
Log2MaxPicOrderCntLSBMin4 int
DeltaPicOrderAlwaysZeroFlag bool
OffsetForNonRefPic int
OffsetForTopToBottomField int
NumRefFramesInPicOrderCntCycle int
OffsetForRefFrameList []int
MaxNumRefFrames int
GapsInFrameNumValueAllowed bool
PicWidthInMBSMinus1 int
PicHeightInMapUnitsMinus1 int
FrameMBSOnlyFlag bool
MBAdaptiveFrameFieldFlag bool
Direct8x8InferenceFlag bool
FrameCroppingFlag bool
FrameCropLeftOffset int
FrameCropRightOffset int
FrameCropTopOffset int
FrameCropBottomOffset int
VUIParametersPresentFlag bool
VUIParameters *VUIParameters
}
// NewSPS parses a sequence parameter set raw byte sequence from br following
// the syntax structure specified in section 7.3.2.1.1, and returns as a new
// SPS.
func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
logger.Printf("debug: SPS RBSP %d bytes %d bits\n", len(rbsp), len(rbsp)*8)
logger.Printf("debug: \t%#v\n", rbsp[0:8])
sps := SPS{}
br := bits.NewBitReader(bytes.NewReader(rbsp))
var err error
hrdParameters := func() error {
sps.CpbCntMinus1, err = readUe(br)
if err != nil {
return errors.Wrap(err, "could not parse CpbCntMinus1")
}
err := readFields(br, []field{
{&sps.BitRateScale, "BitRateScale", 4},
{&sps.CpbSizeScale, "CpbSizeScale", 4},
})
if err != nil {
return err
}
// SchedSelIdx E1.2
for sseli := 0; sseli <= sps.CpbCntMinus1; sseli++ {
ue, err := readUe(br)
if err != nil {
return errors.Wrap(err, "could not parse BitRateValueMinus1")
}
sps.BitRateValueMinus1 = append(sps.BitRateValueMinus1, ue)
ue, err = readUe(br)
if err != nil {
return errors.Wrap(err, "could not parse CpbSizeValueMinus1")
}
sps.CpbSizeValueMinus1 = append(sps.CpbSizeValueMinus1, ue)
if v, _ := br.ReadBits(1); v == 1 {
sps.Cbr = append(sps.Cbr, true)
} else {
sps.Cbr = append(sps.Cbr, false)
}
err = readFields(br,
[]field{
{&sps.InitialCpbRemovalDelayLengthMinus1, "InitialCpbRemovalDelayLengthMinus1", 5},
{&sps.CpbRemovalDelayLengthMinus1, "CpbRemovalDelayLengthMinus1", 5},
{&sps.DpbOutputDelayLengthMinus1, "DpbOutputDelayLengthMinus1", 5},
{&sps.TimeOffsetLength, "TimeOffsetLength", 5},
},
)
if err != nil {
return err
}
}
return nil
}
err = readFields(br,
[]field{
@ -275,30 +138,30 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read Level")
}
sps.Level = int(b)
sps.LevelIDC = int(b)
// sps.ID = b.NextField("SPSID", 6) // proper
sps.ID, err = readUe(br)
sps.SPSID, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ID")
}
sps.ChromaFormat, err = readUe(br)
sps.ChromaFormatIDC, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ChromaFormat")
return nil, errors.Wrap(err, "could not parse ChromaFormatIDC")
}
// This should be done only for certain ProfileIDC:
isProfileIDC := []int{100, 110, 122, 244, 44, 83, 86, 118, 128, 138, 139, 134, 135}
// SpecialProfileCase1
if isInList(isProfileIDC, sps.Profile) {
if sps.ChromaFormat == chroma444 {
if sps.ChromaFormatIDC == chroma444 {
// TODO: should probably deal with error here.
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read UseSeparateColorPlaneFlag")
}
sps.UseSeparateColorPlane = b == 1
sps.SeparateColorPlaneFlag = b == 1
}
sps.BitDepthLumaMinus8, err = readUe(br)
@ -315,17 +178,17 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read QPrimeYZeroTransformBypass")
}
sps.QPrimeYZeroTransformBypass = b == 1
sps.QPPrimeYZeroTransformBypassFlag = b == 1
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read SeqScalingMatrixPresent")
}
sps.SeqScalingMatrixPresent = b == 1
sps.SeqScalingMatrixPresentFlag = b == 1
if sps.SeqScalingMatrixPresent {
if sps.SeqScalingMatrixPresentFlag {
max := 12
if sps.ChromaFormat != chroma444 {
if sps.ChromaFormatIDC != chroma444 {
max = 8
}
logger.Printf("debug: \tbuilding Scaling matrix for %d elements\n", max)
@ -334,9 +197,9 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read SeqScalingList")
}
sps.SeqScalingList = append(sps.SeqScalingList, b == 1)
sps.SeqScalingListPresentFlag = append(sps.SeqScalingListPresentFlag, b == 1)
if sps.SeqScalingList[i] {
if sps.SeqScalingListPresentFlag[i] {
if i < 6 {
scalingList(
br,
@ -380,7 +243,7 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read DeltaPicOrderAlwaysZero")
}
sps.DeltaPicOrderAlwaysZero = b == 1
sps.DeltaPicOrderAlwaysZeroFlag = b == 1
sps.OffsetForNonRefPic, err = readSe(br)
if err != nil {
@ -420,7 +283,7 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
}
sps.GapsInFrameNumValueAllowed = b == 1
sps.PicWidthInMbsMinus1, err = readUe(br)
sps.PicWidthInMBSMinus1, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse PicWidthInMbsMinus1")
}
@ -434,25 +297,25 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read FrameMbsOnly")
}
sps.FrameMbsOnly = b == 1
sps.FrameMBSOnlyFlag = b == 1
if !sps.FrameMbsOnly {
if !sps.FrameMBSOnlyFlag {
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read MBAdaptiveFrameField")
}
sps.MBAdaptiveFrameField = b == 1
sps.MBAdaptiveFrameFieldFlag = b == 1
}
err = readFlags(br, []flag{
{&sps.Direct8x8Inference, "Direct8x8Inference"},
{&sps.FrameCropping, "FrameCropping"},
{&sps.Direct8x8InferenceFlag, "Direct8x8Inference"},
{&sps.FrameCroppingFlag, "FrameCropping"},
})
if err != nil {
return nil, err
}
if sps.FrameCropping {
if sps.FrameCroppingFlag {
sps.FrameCropLeftOffset, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse FrameCropLeftOffset")
@ -478,36 +341,86 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read VuiParametersPresent")
}
sps.VuiParametersPresent = b == 1
sps.VUIParametersPresentFlag = b == 1
if sps.VuiParametersPresent {
// vui_parameters
b, err = br.ReadBits(1)
if sps.VUIParametersPresentFlag {
} // End VuiParameters Annex E.1.1
return &sps, nil
}
// SPS describes a sequence parameter set as defined by section E.1.1 in the
// Specifications.
type VUIParameters struct {
AspectRatioInfoPresentFlag bool
AspectRatioIDC int
SARWidth int
SARHeight int
OverscanInfoPresentFlag bool
OverscanAppropriateFlag bool
VideoSignalTypePresentFlag bool
VideoFormat int
VideoFullRangeFlag bool
ColorDescriptionPresentFlag bool
ColorPrimaries int
TransferCharacteristics int
MatrixCoefficients int
ChromaLocInfoPresentFlag bool
ChromaSampleLocTypeTopField int
ChromaSampleLocTypeBottomField int
TimingInfoPresentFlag bool
NumUnitsInTick int
TimeScale int
FixedFrameRateFlag bool
NALHRDParametersPresentFlag bool
NALHRDParameters *HRDParameters
VCLHRDParametersPresentFlag bool
VCLHRDParameters *HRDParameters
LowDelayHRDFlag bool
PicStructPresentFlag bool
BitstreamRestrictionFlag bool
MotionVectorsOverPicBoundariesFlag bool
MaxBytesPerPicDenom int
MaxBitsPerMBDenom int
Log2MaxMVLengthHorizontal int
Log2MaxMVLengthVertical int
MaxNumReorderFrames int
MaxDecFrameBuffering int
}
// NewVUIParameters parses video usability information parameters from br
// following the syntax structure specified in section E.1.1, and returns as a
// new VUIParameters.
func NewVUIParameters(br *bits.BitReader) (*VUIParameters, error) {
p := &VUIParameters{}
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read AspectRatioInfoPresent")
}
sps.AspectRatioInfoPresent = b == 1
p.AspectRatioInfoPresentFlag = b == 1
if sps.AspectRatioInfoPresent {
if p.AspectRatioInfoPresentFlag {
b, err = br.ReadBits(8)
if err != nil {
return nil, errors.Wrap(err, "could not read AspectRatio")
}
sps.AspectRatio = int(b)
p.AspectRatioIDC = int(b)
EXTENDED_SAR := 999
if sps.AspectRatio == EXTENDED_SAR {
if p.AspectRatioIDC == EXTENDED_SAR {
b, err = br.ReadBits(16)
if err != nil {
return nil, errors.Wrap(err, "could not read SarWidth")
}
sps.SarWidth = int(b)
p.SARWidth = int(b)
b, err = br.ReadBits(16)
if err != nil {
return nil, errors.Wrap(err, "could not read SarHeight")
}
sps.SarHeight = int(b)
p.SARHeight = int(b)
}
}
@ -515,49 +428,49 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read OverscanInfoPresent")
}
sps.OverscanInfoPresent = b == 1
p.OverscanInfoPresentFlag = b == 1
if sps.OverscanInfoPresent {
if p.OverscanInfoPresentFlag {
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read OverscanAppropriate")
}
sps.OverscanAppropriate = b == 1
p.OverscanAppropriateFlag = b == 1
}
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read VideoSignalTypePresent")
}
sps.VideoSignalTypePresent = b == 1
p.VideoSignalTypePresentFlag = b == 1
if sps.VideoSignalTypePresent {
if p.VideoSignalTypePresentFlag {
b, err = br.ReadBits(3)
if err != nil {
return nil, errors.Wrap(err, "could not read VideoFormat")
}
sps.VideoFormat = int(b)
p.VideoFormat = int(b)
}
if sps.VideoSignalTypePresent {
if p.VideoSignalTypePresentFlag {
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read VideoFullRange")
}
sps.VideoFullRange = b == 1
p.VideoFullRangeFlag = b == 1
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read ColorDescriptionPresent")
}
sps.ColorDescriptionPresent = b == 1
p.ColorDescriptionPresentFlag = b == 1
if sps.ColorDescriptionPresent {
if p.ColorDescriptionPresentFlag {
err = readFields(br,
[]field{
{&sps.ColorPrimaries, "ColorPrimaries", 8},
{&sps.TransferCharacteristics, "TransferCharacteristics", 8},
{&sps.MatrixCoefficients, "MatrixCoefficients", 8},
{&p.ColorPrimaries, "ColorPrimaries", 8},
{&p.TransferCharacteristics, "TransferCharacteristics", 8},
{&p.MatrixCoefficients, "MatrixCoefficients", 8},
},
)
if err != nil {
@ -570,15 +483,15 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read ChromaLocInfoPresent")
}
sps.ChromaLocInfoPresent = b == 1
p.ChromaLocInfoPresentFlag = b == 1
if sps.ChromaLocInfoPresent {
sps.ChromaSampleLocTypeTopField, err = readUe(br)
if p.ChromaLocInfoPresentFlag {
p.ChromaSampleLocTypeTopField, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ChromaSampleLocTypeTopField")
}
sps.ChromaSampleLocTypeBottomField, err = readUe(br)
p.ChromaSampleLocTypeBottomField, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ChromaSampleLocTypeBottomField")
}
@ -588,12 +501,12 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read TimingInfoPresent")
}
sps.TimingInfoPresent = b == 1
p.TimingInfoPresentFlag = b == 1
if sps.TimingInfoPresent {
if p.TimingInfoPresentFlag {
err := readFields(br, []field{
{&sps.NumUnitsInTick, "NumUnitsInTick", 32},
{&sps.TimeScale, "TimeScale", 32},
{&p.NumUnitsInTick, "NumUnitsInTick", 32},
{&p.TimeScale, "TimeScale", 32},
})
if err != nil {
return nil, err
@ -603,17 +516,17 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read FixedFrameRate")
}
sps.FixedFrameRate = b == 1
p.FixedFrameRateFlag = b == 1
}
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read NalHrdParametersPresent")
}
sps.NalHrdParametersPresent = b == 1
p.NALHRDParametersPresentFlag = b == 1
if sps.NalHrdParametersPresent {
err = hrdParameters()
if p.NALHRDParametersPresentFlag {
p.NALHRDParameters, err = NewHRDParameters(br)
if err != nil {
return nil, errors.Wrap(err, "could not get hrdParameters")
}
@ -623,68 +536,166 @@ func NewSPS(rbsp []byte, showPacket bool) (*SPS, error) {
if err != nil {
return nil, errors.Wrap(err, "could not read VclHrdParametersPresent")
}
sps.VclHrdParametersPresent = b == 1
p.VCLHRDParametersPresentFlag = b == 1
if sps.VclHrdParametersPresent {
err = hrdParameters()
if p.VCLHRDParametersPresentFlag {
p.VCLHRDParameters, err = NewHRDParameters(br)
if err != nil {
return nil, errors.Wrap(err, "could not get hrdParameters")
}
}
if sps.NalHrdParametersPresent || sps.VclHrdParametersPresent {
if p.NALHRDParametersPresentFlag || p.VCLHRDParametersPresentFlag {
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read LowHrdDelay")
}
sps.LowHrdDelay = b == 1
p.LowDelayHRDFlag = b == 1
}
err := readFlags(br, []flag{
{&sps.PicStructPresent, "PicStructPresent"},
{&sps.BitstreamRestriction, "BitStreamRestriction"},
err = readFlags(br, []flag{
{&p.PicStructPresentFlag, "PicStructPresent"},
{&p.BitstreamRestrictionFlag, "BitStreamRestriction"},
})
if sps.BitstreamRestriction {
if p.BitstreamRestrictionFlag {
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read MotionVectorsOverPicBoundaries")
}
sps.MotionVectorsOverPicBoundaries = b == 1
p.MotionVectorsOverPicBoundariesFlag = b == 1
sps.MaxBytesPerPicDenom, err = readUe(br)
p.MaxBytesPerPicDenom, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse MaxBytesPerPicDenom")
}
sps.MaxBitsPerMbDenom, err = readUe(br)
p.MaxBitsPerMBDenom, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse MaxBitsPerMbDenom")
}
sps.Log2MaxMvLengthHorizontal, err = readUe(br)
p.Log2MaxMVLengthHorizontal, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse Log2MaxMvLengthHorizontal")
}
sps.Log2MaxMvLengthVertical, err = readUe(br)
p.Log2MaxMVLengthVertical, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse Log2MaxMvLengthVertical")
}
sps.MaxNumReorderFrames, err = readUe(br)
p.MaxNumReorderFrames, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse MaxNumReorderFrames")
}
sps.MaxDecFrameBuffering, err = readUe(br)
p.MaxDecFrameBuffering, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse MaxDecFrameBuffering")
}
}
} // End VuiParameters Annex E.1.1
if showPacket {
debugPacket("SPS", sps)
}
return &sps, nil
return p, nil
}
// HRDParameters describes hypothetical reference decoder parameters as defined
// by section E.1.2 in the specifications.
type HRDParameters struct {
CPBCntMinus1 int
BitRateScale int
CPBSizeScale int
BitRateValueMinus1 []int
CPBSizeValueMinus1 []int
CBRFlag []bool
InitialCPBRemovalDelayLenMinus1 int
CPBRemovalDelayLenMinus1 int
DPBOutputDelayLenMinus1 int
TimeOffsetLen int
}
// NewHRDParameters parses hypothetical reference decoder parameter from br
// following the syntax structure specified in section E.1.2, and returns as a
// new HRDParameters.
func NewHRDParameters(br *bits.BitReader) (*HRDParameters, error) {
h := &HRDParameters{}
var err error
h.CPBCntMinus1, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse CPBCntMinus1")
}
err = readFields(br, []field{
{&h.BitRateScale, "BitRateScale", 4},
{&h.CPBSizeScale, "CPBSizeScale", 4},
})
if err != nil {
return nil, err
}
// SchedSelIdx E1.2
for sseli := 0; sseli <= h.CPBCntMinus1; sseli++ {
ue, err := readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse BitRateValueMinus1")
}
h.BitRateValueMinus1 = append(h.BitRateValueMinus1, ue)
ue, err = readUe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse CPBSizeValueMinus1")
}
h.CPBSizeValueMinus1 = append(h.CPBSizeValueMinus1, ue)
if v, _ := br.ReadBits(1); v == 1 {
h.CBRFlag = append(h.CBRFlag, true)
} else {
h.CBRFlag = append(h.CBRFlag, false)
}
err = readFields(br,
[]field{
{&h.InitialCPBRemovalDelayLenMinus1, "InitialCPBRemovalDelayLenMinus1", 5},
{&h.CPBRemovalDelayLenMinus1, "CPBRemovalDelayLenMinus1", 5},
{&h.DPBOutputDelayLenMinus1, "DpbOutputDelayLenMinus1", 5},
{&h.TimeOffsetLen, "TimeOffsetLen", 5},
},
)
if err != nil {
return nil, err
}
}
return h, nil
}
func isInList(l []int, term int) bool {
for _, m := range l {
if m == term {
return true
}
}
return false
}
func scalingList(br *bits.BitReader, scalingList []int, sizeOfScalingList int, defaultScalingMatrix []int) error {
lastScale := 8
nextScale := 8
for i := 0; i < sizeOfScalingList; i++ {
if nextScale != 0 {
deltaScale, err := readSe(br)
if err != nil {
return errors.Wrap(err, "could not parse deltaScale")
}
nextScale = (lastScale + deltaScale + 256) % 256
if i == 0 && nextScale == 0 {
// Scaling list should use the default list for this point in the matrix
_ = defaultScalingMatrix
}
}
if nextScale == 0 {
scalingList[i] = lastScale
} else {
scalingList[i] = nextScale
}
lastScale = scalingList[i]
}
return nil
}