Skip to content

Commit

Permalink
Merge pull request #209 from Eyevinn/hevc-sps-fix
Browse files Browse the repository at this point in the history
Fix HEVC SPS scaling list parsing
  • Loading branch information
tobbee authored Jan 25, 2023
2 parents 238c080 + d46d41f commit 0d2fcb7
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 7 deletions.
51 changes: 51 additions & 0 deletions hevc/hevcdecoderconfigurationrecord_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,54 @@ func createNalusFromHex(hexStr string) [][]byte {
}
return nalus
}

func TestDecodeConfRec(t *testing.T) {
hexData := ("0102" +
"00000020b000000000009c0000000102" +
"0200000f03a00001001840010c01ffff" +
"022000000300b0000003000003009c15" +
"c090a100010025420101022000000300" +
"b0000003000003009ca001e020021c4d" +
"8815ee4595602d4244024020a2000100" +
"094401c02864b8d05324")
data, err := hex.DecodeString(hexData)
if err != nil {
t.Error(err)
}
hdcr, err := DecodeHEVCDecConfRec(data)
if err != nil {
t.Error(err)
}
for _, na := range hdcr.NaluArrays {

switch na.NaluType() {
case NALU_VPS, NALU_PPS:
case NALU_SPS:
for _, nalu := range na.Nalus {
sps, err := ParseSPSNALUnit(nalu)
if err != nil {
t.Error(err)
}
if !sps.ScalingListEnabledFlag || sps.ScalingListDataPresentFlag {
t.Error("scaling_list_enabled not properly parsed")
}
vui := sps.VUI
if vui == nil {
t.Error("no vui parsed")
} else {
if vui.TransferCharacteristics != 16 {
t.Errorf("vui transfer_characteristics is %d, not 16", vui.TransferCharacteristics)
}
if vui.ColourPrimaries != 9 {
t.Errorf("vui colour_primaries is %d, not 9", vui.ColourPrimaries)
}
if vui.MatrixCoefficients != 9 {
t.Errorf("vui matrix_coefficients is %d, not 9", vui.MatrixCoefficients)
}
}
}
default:
t.Errorf("strange nalu type %s", na.NaluType())
}
}
}
15 changes: 9 additions & 6 deletions hevc/sps.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ type BitstreamRestrictions struct {
Log2MaxMvLengthVertical uint
}

// ParseSPSNALUnit - Parse HEVC SPS NAL unit starting with NAL unit header
// ParseSPSNALUnit parses SPS NAL unit starting with NAL unit header
func ParseSPSNALUnit(data []byte) (*SPS, error) {

sps := &SPS{}
Expand Down Expand Up @@ -176,9 +176,9 @@ func ParseSPSNALUnit(data []byte) (*SPS, error) {
sps.BitDepthChromaMinus8 = byte(r.ReadExpGolomb())
sps.Log2MaxPicOrderCntLsbMinus4 = byte(r.ReadExpGolomb())
sps.SubLayerOrderingInfoPresentFlag = r.ReadFlag()
startValue := byte(0)
startValue := sps.MaxSubLayersMinus1
if sps.SubLayerOrderingInfoPresentFlag {
startValue = sps.MaxSubLayersMinus1
startValue = 0
}
for i := startValue; i <= sps.MaxSubLayersMinus1; i++ {
sps.SubLayeringOrderingInfos = append(
Expand All @@ -197,7 +197,10 @@ func ParseSPSNALUnit(data []byte) (*SPS, error) {
sps.MaxTransformHierarchyDepthIntra = byte(r.ReadExpGolomb())
sps.ScalingListEnabledFlag = r.ReadFlag()
if sps.ScalingListEnabledFlag {
readPastScalingList(r)
sps.ScalingListDataPresentFlag = r.ReadFlag()
if sps.ScalingListDataPresentFlag {
readPastScalingListData(r)
}
}
sps.AmpEnabledFlag = r.ReadFlag()
sps.SampleAdaptiveOffsetEnabledFlag = r.ReadFlag()
Expand Down Expand Up @@ -407,8 +410,8 @@ func parseShortTermRPS(r *bits.AccErrEBSPReader, idx, numSTRefPicSets byte, sps
return stps
}

// readPastScalingList - read and parse all bits of scaling list, without storing values
func readPastScalingList(r *bits.AccErrEBSPReader) {
// readPastScalingListData - read and parse all bits of scaling list, without storing values
func readPastScalingListData(r *bits.AccErrEBSPReader) {
for sizeId := 0; sizeId < 4; sizeId++ {
nrMatrixIds := 6
if sizeId == 3 {
Expand Down
89 changes: 88 additions & 1 deletion hevc/sps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
)

const (
spsNalu = "420101022000000300b0000003000003007ba0078200887db6718b92448053888892cf24a69272c9124922dc91aa48fca223ff000100016a02020201"
spsNalu = ("420101022000000300b0000003000003007ba0078200887db6718b92448053888892" +
"cf24a69272c9124922dc91aa48fca223ff000100016a02020201")
spsNaluHdr10 = "420101022000000300b0000003000003009ca001e020021c4d8815ee4595602d4244024020"
)

func TestSPSParser1(t *testing.T) {
Expand Down Expand Up @@ -178,3 +180,88 @@ func TestSPSParser1(t *testing.T) {
t.Errorf("Got %dx%d instead of %dx%d", gotWidth, gotHeight, expWidth, expHeight)
}
}

func TestSPSParser2(t *testing.T) {
byteData, _ := hex.DecodeString(spsNaluHdr10)

wantedVUI := VUIParameters{
SampleAspectRatioWidth: 1,
SampleAspectRatioHeight: 1,
VideoSignalTypePresentFlag: true,
VideoFormat: 5,
ColourDescriptionFlag: true,
ColourPrimaries: 9,
TransferCharacteristics: 16,
MatrixCoefficients: 9,
}
wanted := SPS{
VpsID: 0,
MaxSubLayersMinus1: 0,
TemporalIDNestingFlag: true,
ProfileTierLevel: ProfileTierLevel{
GeneralProfileSpace: 0,
GeneralTierFlag: false,
GeneralProfileIDC: 2,
GeneralProfileCompatibilityFlags: 536870912,
GeneralConstraintIndicatorFlags: 193514046488576,
GeneralProgressiveSourceFlag: false,
GeneralInterlacedSourceFlag: false,
GeneralNonPackedConstraintFlag: false,
GeneralFrameOnlyConstraintFlag: false,
GeneralLevelIDC: 156,
},
SpsID: 0,
ChromaFormatIDC: 1,
SeparateColourPlaneFlag: false,
ConformanceWindowFlag: false,
PicWidthInLumaSamples: 3840,
PicHeightInLumaSamples: 2160,
ConformanceWindow: ConformanceWindow{
LeftOffset: 0,
RightOffset: 0,
TopOffset: 0,
BottomOffset: 0,
},
BitDepthLumaMinus8: 2,
BitDepthChromaMinus8: 2,
Log2MaxPicOrderCntLsbMinus4: 7,
SubLayerOrderingInfoPresentFlag: false,
SubLayeringOrderingInfos: []SubLayerOrderingInfo{
{
MaxDecPicBufferingMinus1: 4,
MaxNumReorderPics: 2,
MaxLatencyIncreasePlus1: 0,
},
},
Log2MinLumaCodingBlockSizeMinus3: 0,
Log2DiffMaxMinLumaCodingBlockSize: 2,
Log2MinLumaTransformBlockSizeMinus2: 0,
Log2DiffMaxMinLumaTransformBlockSize: 3,
MaxTransformHierarchyDepthInter: 1,
MaxTransformHierarchyDepthIntra: 0,
ScalingListEnabledFlag: true,
ScalingListDataPresentFlag: false,
AmpEnabledFlag: false,
SampleAdaptiveOffsetEnabledFlag: true,
PCMEnabledFlag: false,
NumShortTermRefPicSets: 0,
LongTermRefPicsPresentFlag: false,
SpsTemporalMvpEnabledFlag: true,
StrongIntraSmoothingEnabledFlag: false,
VUIParametersPresentFlag: true,
VUI: &wantedVUI,
}
got, err := ParseSPSNALUnit(byteData)
if err != nil {
t.Error("Error parsing SPS")
}

if diff := deep.Equal(*got, wanted); diff != nil {
t.Error(diff)
}
gotWidth, gotHeight := got.ImageSize()
var expWidth, expHeight uint32 = 3840, 2160
if gotWidth != expWidth || gotHeight != expHeight {
t.Errorf("Got %dx%d instead of %dx%d", gotWidth, gotHeight, expWidth, expHeight)
}
}

0 comments on commit 0d2fcb7

Please sign in to comment.