Skip to content

Commit

Permalink
h264: filter out invalid NALUs from Annex-B
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed May 25, 2024
1 parent 2016386 commit 1cd9546
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 30 deletions.
79 changes: 49 additions & 30 deletions pkg/codecs/h264/annexb.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
package h264

import (
"errors"
"fmt"
)

// ErrAnnexBNoNALUs is returned by AnnexBUnmarshal when no NALUs have been decoded.
var ErrAnnexBNoNALUs = errors.New("Annex-B unit doesn't contain any NALU")

// AnnexBUnmarshal decodes an access unit from the Annex-B stream format.
// Specification: ITU-T Rec. H.264, Annex B
func AnnexBUnmarshal(buf []byte) ([][]byte, error) {
bl := len(buf)
initZeroCount := 0
start := 0
i := 0

outer:
for {
if start >= bl || start >= 4 {
if i >= bl || i >= 4 {
return nil, fmt.Errorf("initial delimiter not found")
}

switch initZeroCount {
case 0, 1:
if buf[start] != 0 {
if buf[i] != 0 {
return nil, fmt.Errorf("initial delimiter not found")
}
initZeroCount++

case 2, 3:
switch buf[start] {
switch buf[i] {
case 1:
start++
break outer

case 0:
Expand All @@ -38,20 +41,36 @@ outer:
initZeroCount++
}

start++
i++
}

start := initZeroCount + 1
zeroCount := 0
n := 0
delimStart := 0
auSize := 0

for i := start; i < bl; i++ {
switch buf[i] {
case 0:
if zeroCount == 0 {
delimStart = i
}
zeroCount++

case 1:
if zeroCount == 2 || zeroCount == 3 {
n++
l := delimStart - start

if l != 0 {
if (auSize + l) > MaxAccessUnitSize {
return nil, fmt.Errorf("access unit size (%d) is too big, maximum is %d", auSize+l, MaxAccessUnitSize)
}

Check warning on line 68 in pkg/codecs/h264/annexb.go

View check run for this annotation

Codecov / codecov/patch

pkg/codecs/h264/annexb.go#L67-L68

Added lines #L67 - L68 were not covered by tests
n++
}

auSize += l
start = i + 1
}
zeroCount = 0

Expand All @@ -60,17 +79,29 @@ outer:
}
}

if (n + 1) > MaxNALUsPerAccessUnit {
l := bl - start

if l != 0 {
if (auSize + l) > MaxAccessUnitSize {
return nil, fmt.Errorf("access unit size (%d) is too big, maximum is %d", auSize+l, MaxAccessUnitSize)
}

Check warning on line 87 in pkg/codecs/h264/annexb.go

View check run for this annotation

Codecov / codecov/patch

pkg/codecs/h264/annexb.go#L86-L87

Added lines #L86 - L87 were not covered by tests
n++
}

if n == 0 {
return nil, ErrAnnexBNoNALUs
}

if n > MaxNALUsPerAccessUnit {
return nil, fmt.Errorf("NALU count (%d) exceeds maximum allowed (%d)",
n+1, MaxNALUsPerAccessUnit)
n, MaxNALUsPerAccessUnit)

Check warning on line 97 in pkg/codecs/h264/annexb.go

View check run for this annotation

Codecov / codecov/patch

pkg/codecs/h264/annexb.go#L97

Added line #L97 was not covered by tests
}

ret := make([][]byte, n+1)
ret := make([][]byte, n)
pos := 0
start = initZeroCount + 1
zeroCount = 0
delimStart := 0
auSize := 0
delimStart = 0

for i := start; i < bl; i++ {
switch buf[i] {
Expand All @@ -84,17 +115,11 @@ outer:
if zeroCount == 2 || zeroCount == 3 {
l := delimStart - start

Check failure on line 116 in pkg/codecs/h264/annexb.go

View workflow job for this annotation

GitHub Actions / golangci-lint

shadow: declaration of "l" shadows declaration at line 82 (govet)

if l == 0 {
return nil, fmt.Errorf("invalid NALU")
if l != 0 {
ret[pos] = buf[start:delimStart]
pos++
}

if (auSize + l) > MaxAccessUnitSize {
return nil, fmt.Errorf("access unit size (%d) is too big, maximum is %d", auSize+l, MaxAccessUnitSize)
}

ret[pos] = buf[start:delimStart]
pos++
auSize += l
start = i + 1
}
zeroCount = 0
Expand All @@ -104,18 +129,12 @@ outer:
}
}

l := bl - start
l = bl - start

if l == 0 {
return nil, fmt.Errorf("invalid NALU")
if l != 0 {
ret[pos] = buf[start:bl]
}

if (auSize + l) > MaxAccessUnitSize {
return nil, fmt.Errorf("access unit size (%d) is too big, maximum is %d", auSize+l, MaxAccessUnitSize)
}

ret[pos] = buf[start:bl]

return ret, nil
}

Expand Down
11 changes: 11 additions & 0 deletions pkg/codecs/h264/annexb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ func TestAnnexBUnmarshal(t *testing.T) {
}
}

func TestAnnexBUnmarshalEmpty(t *testing.T) {
buf := []byte{0, 0, 0, 1, 0, 0, 0, 1}
_, err := AnnexBUnmarshal(buf)
require.Equal(t, err, ErrAnnexBNoNALUs)

buf = []byte{0, 0, 0, 1, 0, 0, 0, 1, 1}
dec, err := AnnexBUnmarshal(buf)
require.NoError(t, err)
require.Equal(t, [][]byte{{1}}, dec)
}

func TestAnnexBMarshal(t *testing.T) {
for _, ca := range casesAnnexB {
t.Run(ca.name, func(t *testing.T) {
Expand Down

0 comments on commit 1cd9546

Please # to comment.