Skip to content

Commit 3ce9f47

Browse files
authored
Merge pull request #31 from edgeware/parse-pps
Add complete AVC PPS parsing
2 parents 2f6b23b + 93fc6ff commit 3ce9f47

File tree

6 files changed

+573
-56
lines changed

6 files changed

+573
-56
lines changed

avc/avc.go

Lines changed: 45 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ type SPS struct {
9898
BitDepthChromaMinus8 uint
9999
QPPrimeYZeroTransformBypassFlag bool
100100
SeqScalingMatrixPresentFlag bool
101-
SeqScalings *SeqScalings
101+
SeqScalingLists []ScalingList
102102
Log2MaxFrameNumMinus4 uint
103103
PicOrderCntType uint
104104
Log2MaxPicOrderCntLsbMinus4 uint
@@ -123,13 +123,7 @@ type SPS struct {
123123
VUI *VUIParameters
124124
}
125125

126-
type SeqScalings struct {
127-
SeqScalingLists []SeqScalingList
128-
}
129-
type SeqScalingList struct {
130-
SeqScalingListPresentFlag bool
131-
ScalingLists []int
132-
}
126+
type ScalingList []int // 4x4 or 8x8 Scaling lists. Nil if not present
133127

134128
// VUIParameters - extra parameters according to 14496-10, E.1
135129
type VUIParameters struct {
@@ -256,50 +250,28 @@ func ParseSPSNALUnit(data []byte, parseVUIBeyondAspectRatio bool) (*SPS, error)
256250
return nil, err
257251
}
258252
if sps.SeqScalingMatrixPresentFlag {
259-
sps.SeqScalings = &SeqScalings{}
260-
length := 12 // Default
261-
if sps.ChromaFormatIDC == 3 {
262-
length = 8
253+
nrScalingLists := 12
254+
if sps.ChromaFormatIDC != 3 {
255+
nrScalingLists = 8
263256
}
264-
for i := 0; i < length; i++ {
265-
if i < 6 {
266-
sm := make([]int, 16) // 4x4 scaling matrix
267-
lastScale := 8
268-
nextScale := 8
269-
for j := 0; j < 16; j++ {
270-
if nextScale != 0 {
271-
deltaScale, err := reader.ReadSignedGolomb()
272-
if err != nil {
273-
return nil, err
274-
}
275-
nextScale = (lastScale + deltaScale + 256) % 256
276-
}
277-
if nextScale == 0 {
278-
sm[j] = lastScale
279-
} else {
280-
sm[j] = nextScale
281-
}
282-
lastScale = sm[j]
283-
}
284-
} else {
285-
sm := make([]int, 64) // 8x8 scaling matrix
286-
lastScale := 8
287-
nextScale := 8
288-
for j := 0; j < 64; j++ {
289-
if nextScale != 0 {
290-
deltaScale, err := reader.ReadSignedGolomb()
291-
if err != nil {
292-
return nil, err
293-
}
294-
nextScale = (lastScale + deltaScale + 256) % 256
295-
}
296-
if nextScale == 0 {
297-
sm[j] = lastScale
298-
} else {
299-
sm[j] = nextScale
300-
}
301-
lastScale = sm[j]
302-
}
257+
sps.SeqScalingLists = make([]ScalingList, nrScalingLists)
258+
259+
for i := 0; i < nrScalingLists; i++ {
260+
seqScalingPresent, err := reader.ReadFlag()
261+
if err != nil {
262+
return nil, err
263+
}
264+
if !seqScalingPresent {
265+
sps.SeqScalingLists[i] = nil
266+
continue
267+
}
268+
sizeOfScalingList := 16 // 4x4 for i < 6
269+
if i >= 6 {
270+
sizeOfScalingList = 64 // 8x8 for i >= 6
271+
}
272+
sps.SeqScalingLists[i], err = readScalingList(reader, sizeOfScalingList)
273+
if err != nil {
274+
return nil, err
303275
}
304276
}
305277
}
@@ -690,3 +662,25 @@ func getSAR(index uint) (uint, uint, error) {
690662
{160, 99}, {4, 3}, {3, 2}, {2, 1}}
691663
return aspectRatioTable[index-1][0], aspectRatioTable[index-1][1], nil
692664
}
665+
666+
func readScalingList(reader *bits.EBSPReader, sizeOfScalingList int) (ScalingList, error) {
667+
scalingList := make([]int, sizeOfScalingList)
668+
lastScale := 8
669+
nextScale := 8
670+
for j := 0; j < sizeOfScalingList; j++ {
671+
if nextScale != 0 {
672+
deltaScale, err := reader.ReadSignedGolomb()
673+
if err != nil {
674+
return nil, err
675+
}
676+
nextScale = (lastScale + deltaScale + 256) % 256
677+
}
678+
if nextScale == 0 {
679+
scalingList[j] = lastScale
680+
} else {
681+
scalingList[j] = nextScale
682+
}
683+
lastScale = scalingList[j]
684+
}
685+
return scalingList, nil
686+
}

avc/pps.go

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package avc
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"fmt"
7+
"io"
8+
9+
"github.com/edgeware/mp4ff/bits"
10+
)
11+
12+
type PPS struct {
13+
PicParameterSetID uint
14+
SeqParameterSetID uint
15+
EntropyCodingModeFlag bool
16+
BottomFieldPicOrderInFramePresentFlag bool
17+
NumSliceGroupsMinus1 uint
18+
SliceGroupMapType uint
19+
RunLengthMinus1 []uint
20+
TopLeft []uint
21+
BottomRight []uint
22+
SliceGroupChangeDirectionFlag bool
23+
SliceGroupChangeRateMinus1 uint
24+
PicSizeInMapUnitsMinus1 uint
25+
SliceGroupId []uint
26+
NumRefIdxI0DefaultActiveMinus1 uint
27+
NumRefIdxI1DefaultActiveMinus1 uint
28+
WeightedPredFlag bool
29+
WeightedBipredIDC uint
30+
PicInitQpMinus26 int
31+
PicInitQsMinus26 int
32+
ChromaQpIndexOffset int
33+
DeblockingFilterControlPresentFlag bool
34+
ConstrainedIntraPredFlag bool
35+
RedundantPicCntPresentFlag bool
36+
Transform8x8ModeFlag bool
37+
PicScalingMatrixPresentFlag bool
38+
PicScalingLists []ScalingList
39+
SecondChromaQpIndexOffset int
40+
}
41+
42+
var ErrNotPPS = errors.New("Not an PPS NAL unit")
43+
44+
// ParsePPSNALUnit - Parse AVC PPS NAL unit starting with NAL header
45+
func ParsePPSNALUnit(data []byte, sps *SPS) (*PPS, error) {
46+
47+
var err error
48+
49+
pps := &PPS{}
50+
51+
rd := bytes.NewReader(data)
52+
reader := bits.NewEBSPReader(rd)
53+
// Note! First byte is NAL Header
54+
55+
nalHdr, err := reader.Read(8)
56+
if err != nil {
57+
return nil, err
58+
}
59+
nalType := GetNalType(byte(nalHdr))
60+
if nalType != NALU_PPS {
61+
return nil, ErrNotPPS
62+
}
63+
64+
pps.PicParameterSetID, err = reader.ReadExpGolomb()
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
pps.SeqParameterSetID, err = reader.ReadExpGolomb()
70+
if err != nil {
71+
return nil, err
72+
}
73+
74+
pps.EntropyCodingModeFlag, err = reader.ReadFlag()
75+
if err != nil {
76+
return nil, err
77+
}
78+
79+
pps.BottomFieldPicOrderInFramePresentFlag, err = reader.ReadFlag()
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
pps.NumSliceGroupsMinus1, err = reader.ReadExpGolomb()
85+
if err != nil {
86+
return nil, err
87+
}
88+
89+
if pps.NumSliceGroupsMinus1 > 0 {
90+
pps.SliceGroupMapType, err = reader.ReadExpGolomb()
91+
if err != nil {
92+
return nil, err
93+
}
94+
switch pps.SliceGroupMapType {
95+
case 0:
96+
for iGroup := uint(0); iGroup <= pps.NumSliceGroupsMinus1; iGroup++ {
97+
rl, err := reader.ReadExpGolomb()
98+
if err != nil {
99+
return nil, err
100+
}
101+
pps.RunLengthMinus1 = append(pps.RunLengthMinus1, rl)
102+
}
103+
case 2:
104+
for iGroup := uint(0); iGroup <= pps.NumSliceGroupsMinus1; iGroup++ {
105+
tl, err := reader.ReadExpGolomb()
106+
if err != nil {
107+
return nil, err
108+
}
109+
pps.TopLeft = append(pps.TopLeft, tl)
110+
br, err := reader.ReadExpGolomb()
111+
if err != nil {
112+
return nil, err
113+
}
114+
pps.BottomRight = append(pps.BottomRight, br)
115+
}
116+
case 3, 4, 5:
117+
pps.SliceGroupChangeDirectionFlag, err = reader.ReadFlag()
118+
if err != nil {
119+
return nil, err
120+
}
121+
pps.SliceGroupChangeRateMinus1, err = reader.ReadExpGolomb()
122+
if err != nil {
123+
return nil, err
124+
}
125+
case 6:
126+
// slice_group_id[i] has Ceil(Log2(num_slice_groups_minus1 +1) bits)
127+
nrBits := ceilLog2(pps.NumSliceGroupsMinus1 + 1)
128+
129+
for iGroup := uint(0); iGroup <= pps.NumSliceGroupsMinus1; iGroup++ {
130+
sgi, err := reader.Read(nrBits)
131+
if err != nil {
132+
return nil, err
133+
}
134+
pps.SliceGroupId = append(pps.SliceGroupId, sgi)
135+
}
136+
}
137+
}
138+
pps.NumRefIdxI0DefaultActiveMinus1, err = reader.ReadExpGolomb()
139+
if err != nil {
140+
return nil, err
141+
}
142+
pps.NumRefIdxI1DefaultActiveMinus1, err = reader.ReadExpGolomb()
143+
if err != nil {
144+
return nil, err
145+
}
146+
pps.WeightedPredFlag, err = reader.ReadFlag()
147+
if err != nil {
148+
return nil, err
149+
}
150+
pps.WeightedBipredIDC, err = reader.Read(2)
151+
if err != nil {
152+
return nil, err
153+
}
154+
pps.PicInitQpMinus26, err = reader.ReadSignedGolomb()
155+
if err != nil {
156+
return nil, err
157+
}
158+
pps.PicInitQsMinus26, err = reader.ReadSignedGolomb()
159+
if err != nil {
160+
return nil, err
161+
}
162+
pps.ChromaQpIndexOffset, err = reader.ReadSignedGolomb()
163+
if err != nil {
164+
return nil, err
165+
}
166+
pps.DeblockingFilterControlPresentFlag, err = reader.ReadFlag()
167+
if err != nil {
168+
return nil, err
169+
}
170+
pps.ConstrainedIntraPredFlag, err = reader.ReadFlag()
171+
if err != nil {
172+
return nil, err
173+
}
174+
pps.RedundantPicCntPresentFlag, err = reader.ReadFlag()
175+
if err != nil {
176+
return nil, err
177+
}
178+
if !reader.IsSeeker() {
179+
// Cannot call MoreRbspData, so cannot parse further
180+
return pps, nil
181+
}
182+
moreRbsp, err := reader.MoreRbspData()
183+
if err != nil {
184+
return nil, err
185+
}
186+
if moreRbsp {
187+
pps.Transform8x8ModeFlag, err = reader.ReadFlag()
188+
if err != nil {
189+
return nil, err
190+
}
191+
pps.PicScalingMatrixPresentFlag, err = reader.ReadFlag()
192+
if err != nil {
193+
return nil, err
194+
}
195+
if pps.PicScalingMatrixPresentFlag {
196+
if sps == nil {
197+
return pps, fmt.Errorf("Need SPS to decode PPS PicScalings")
198+
}
199+
nrScalingLists := 6
200+
if pps.Transform8x8ModeFlag {
201+
if sps.ChromaFormatIDC != 3 {
202+
nrScalingLists += 2
203+
} else {
204+
nrScalingLists += 6
205+
}
206+
pps.PicScalingLists = make([]ScalingList, nrScalingLists)
207+
208+
for i := 0; i < nrScalingLists; i++ {
209+
picScalingPresent, err := reader.ReadFlag()
210+
if err != nil {
211+
return nil, err
212+
}
213+
if !picScalingPresent {
214+
pps.PicScalingLists[i] = nil
215+
continue
216+
}
217+
sizeOfScalingList := 16 // 4x4 for i < 6
218+
if i >= 6 {
219+
sizeOfScalingList = 64 // 8x8 for i >= 6
220+
}
221+
pps.PicScalingLists[i], err = readScalingList(reader, sizeOfScalingList)
222+
if err != nil {
223+
return nil, err
224+
}
225+
}
226+
}
227+
}
228+
pps.SecondChromaQpIndexOffset, err = reader.ReadSignedGolomb()
229+
if err != nil {
230+
return nil, err
231+
}
232+
}
233+
234+
err = reader.ReadRbspTrailingBits()
235+
if err != nil {
236+
return nil, err
237+
}
238+
_, err = reader.Read(1)
239+
if err != io.EOF {
240+
return nil, fmt.Errorf("Not at end after reading rbsp_trailing_bits")
241+
}
242+
return pps, nil
243+
}
244+
245+
// ceilLog2 - nr bits needed to represent numbers 0 - n-1 values
246+
func ceilLog2(n uint) int {
247+
for i := 0; i < 32; i++ {
248+
maxNr := uint(1 << i)
249+
if maxNr >= n {
250+
return i
251+
}
252+
}
253+
return 32
254+
}

0 commit comments

Comments
 (0)