From 939329bd2972e04b1572a2dba1ead1990041f641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Kol=C3=A1=C5=99?= Date: Tue, 26 Sep 2023 16:37:05 +0200 Subject: [PATCH] fix(avc/slice): breaks doesn't stop parser loops --- avc/slice.go | 17 ++++++++--- avc/slice_test.go | 57 +++++++++++++++++++++++++++++++++++- avc/testdata/two-frames.264 | Bin 0 -> 16448 bytes 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 avc/testdata/two-frames.264 diff --git a/avc/slice.go b/avc/slice.go index 4314702d..f4d73ae1 100644 --- a/avc/slice.go +++ b/avc/slice.go @@ -208,6 +208,7 @@ func ParseSliceHeader(nalu []byte, spsMap map[uint32]*SPS, ppsMap map[uint32]*PP if sliceType != SLICE_I && sliceType != SLICE_SI { sh.RefPicListModificationL0Flag = r.ReadFlag() if sh.RefPicListModificationL0Flag { + refPicListL0Loop: for { sh.ModificationOfPicNumsIDC = uint32(r.ReadExpGolomb()) switch sh.ModificationOfPicNumsIDC { @@ -216,10 +217,10 @@ func ParseSliceHeader(nalu []byte, spsMap map[uint32]*SPS, ppsMap map[uint32]*PP case 2: sh.LongTermPicNum = uint32(r.ReadExpGolomb()) case 3: - break + break refPicListL0Loop } if r.AccError() != nil { - break + break refPicListL0Loop } } } @@ -227,6 +228,7 @@ func ParseSliceHeader(nalu []byte, spsMap map[uint32]*SPS, ppsMap map[uint32]*PP if sliceType == SLICE_B { sh.RefPicListModificationL1Flag = r.ReadFlag() if sh.RefPicListModificationL1Flag { + refPicListL1Loop: for { sh.ModificationOfPicNumsIDC = uint32(r.ReadExpGolomb()) switch sh.ModificationOfPicNumsIDC { @@ -235,7 +237,10 @@ func ParseSliceHeader(nalu []byte, spsMap map[uint32]*SPS, ppsMap map[uint32]*PP case 2: sh.LongTermPicNum = uint32(r.ReadExpGolomb()) case 3: - break + break refPicListL1Loop + } + if r.AccError() != nil { + break refPicListL1Loop } } } @@ -299,6 +304,7 @@ func ParseSliceHeader(nalu []byte, spsMap map[uint32]*SPS, ppsMap map[uint32]*PP } else { sh.AdaptiveRefPicMarkingModeFlag = r.ReadFlag() if sh.AdaptiveRefPicMarkingModeFlag { + adaptiveRefPicLoop: for { memoryManagementControlOperation := r.ReadExpGolomb() switch memoryManagementControlOperation { @@ -313,7 +319,10 @@ func ParseSliceHeader(nalu []byte, spsMap map[uint32]*SPS, ppsMap map[uint32]*PP case 4: sh.MaxLongTermFrameIdxPlus1 = uint32(r.ReadExpGolomb()) case 0: - break + break adaptiveRefPicLoop + } + if r.AccError() != nil { + break adaptiveRefPicLoop } } } diff --git a/avc/slice_test.go b/avc/slice_test.go index 0890c8a2..38889d31 100644 --- a/avc/slice_test.go +++ b/avc/slice_test.go @@ -23,7 +23,7 @@ func TestSliceTypeParser(t *testing.T) { } } -func TestParseSliceHeader(t *testing.T) { +func TestParseSliceHeader_BlackFrame(t *testing.T) { wantedHdr := SliceHeader{ SliceType: 7, SliceQPDelta: 6, @@ -65,3 +65,58 @@ func TestParseSliceHeader(t *testing.T) { t.Error(diff) } } + +func TestParseSliceHeader_TwoFrames(t *testing.T) { + wantedIdrHdr := SliceHeader{SliceType: SLICE_I, IDRPicID: 1, SliceQPDelta: 8, Size: 5} + wantedNonIdrHdr := SliceHeader{ + SliceType: SLICE_P, FrameNum: 1, ModificationOfPicNumsIDC: 3, SliceQPDelta: 13, + Size: 5, NumRefIdxActiveOverrideFlag: true, RefPicListModificationL0Flag: true, + } + + data, err := ioutil.ReadFile("testdata/two-frames.264") + if err != nil { + t.Error(err) + } + nalus, err := GetNalusFromSample(data) + if err != nil { + t.Error(err) + } + spsMap := make(map[uint32]*SPS, 1) + ppsMap := make(map[uint32]*PPS, 1) + var gotIdrHdr *SliceHeader + var gotNonIdrHdr *SliceHeader + for _, nalu := range nalus { + switch GetNaluType(nalu[0]) { + case NALU_SPS: + sps, err := ParseSPSNALUnit(nalu, true) + if err != nil { + t.Error(err) + } + spsMap[uint32(sps.ParameterID)] = sps + case NALU_PPS: + pps, err := ParsePPSNALUnit(nalu, spsMap) + if err != nil { + t.Error(err) + } + ppsMap[uint32(pps.PicParameterSetID)] = pps + case NALU_IDR: + gotIdrHdr, err = ParseSliceHeader(nalu, spsMap, ppsMap) + if err != nil { + t.Error(err) + } + case NALU_NON_IDR: + gotNonIdrHdr, err = ParseSliceHeader(nalu, spsMap, ppsMap) + if err != nil { + t.Error(err) + } + } + } + if diff := deep.Equal(wantedIdrHdr, *gotIdrHdr); diff != nil { + fmt.Printf("Got IDR Slice Header: %+v\n Diff is: ", *gotIdrHdr) + t.Error(diff) + } + if diff := deep.Equal(wantedNonIdrHdr, *gotNonIdrHdr); diff != nil { + fmt.Printf("Got NON_IDR Slice Header: %+v\n Diff is: ", *gotNonIdrHdr) + t.Error(diff) + } +} diff --git a/avc/testdata/two-frames.264 b/avc/testdata/two-frames.264 new file mode 100644 index 0000000000000000000000000000000000000000..6d7dec4addbf5bfcd699194b47b3e16724ba6371 GIT binary patch literal 16448 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