6 changed files with 270 additions and 125 deletions
@ -0,0 +1,90 @@ |
|||||||
|
package h264 |
||||||
|
|
||||||
|
// AntiCompetitionAdd adds the anti-competition bytes to a NALU.
|
||||||
|
func AntiCompetitionAdd(nalu []byte) []byte { |
||||||
|
var ret []byte |
||||||
|
step := 0 |
||||||
|
start := 0 |
||||||
|
|
||||||
|
for i, b := range nalu { |
||||||
|
switch step { |
||||||
|
case 0: |
||||||
|
if b == 0 { |
||||||
|
step++ |
||||||
|
} |
||||||
|
|
||||||
|
case 1: |
||||||
|
if b == 0 { |
||||||
|
step++ |
||||||
|
} else { |
||||||
|
step = 0 |
||||||
|
} |
||||||
|
|
||||||
|
case 2: |
||||||
|
switch b { |
||||||
|
case 3, 2, 1, 0: |
||||||
|
ret = append(ret, nalu[start:i-2]...) |
||||||
|
ret = append(ret, []byte{0x00, 0x00, 0x03, b}...) |
||||||
|
step = 0 |
||||||
|
start = i + 1 |
||||||
|
|
||||||
|
default: |
||||||
|
step = 0 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ret = append(ret, nalu[start:]...) |
||||||
|
return ret |
||||||
|
} |
||||||
|
|
||||||
|
// AntiCompetitionRemove removes the anti-competition bytes from a NALU.
|
||||||
|
func AntiCompetitionRemove(nalu []byte) []byte { |
||||||
|
// 0x00 0x00 0x03 0x00 -> 0x00 0x00 0x00
|
||||||
|
// 0x00 0x00 0x03 0x01 -> 0x00 0x00 0x01
|
||||||
|
// 0x00 0x00 0x03 0x02 -> 0x00 0x00 0x02
|
||||||
|
// 0x00 0x00 0x03 0x03 -> 0x00 0x00 0x03
|
||||||
|
|
||||||
|
var ret []byte |
||||||
|
step := 0 |
||||||
|
start := 0 |
||||||
|
|
||||||
|
for i, b := range nalu { |
||||||
|
switch step { |
||||||
|
case 0: |
||||||
|
if b == 0 { |
||||||
|
step++ |
||||||
|
} |
||||||
|
|
||||||
|
case 1: |
||||||
|
if b == 0 { |
||||||
|
step++ |
||||||
|
} else { |
||||||
|
step = 0 |
||||||
|
} |
||||||
|
|
||||||
|
case 2: |
||||||
|
if b == 3 { |
||||||
|
step++ |
||||||
|
} else { |
||||||
|
step = 0 |
||||||
|
} |
||||||
|
|
||||||
|
case 3: |
||||||
|
switch b { |
||||||
|
case 3, 2, 1, 0: |
||||||
|
ret = append(ret, nalu[start:i-3]...) |
||||||
|
ret = append(ret, []byte{0x00, 0x00, b}...) |
||||||
|
step = 0 |
||||||
|
start = i + 1 |
||||||
|
|
||||||
|
default: |
||||||
|
step = 0 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ret = append(ret, nalu[start:]...) |
||||||
|
|
||||||
|
return ret |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package h264 |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/stretchr/testify/require" |
||||||
|
) |
||||||
|
|
||||||
|
var casesAntiCompetition = []struct { |
||||||
|
name string |
||||||
|
unproc []byte |
||||||
|
proc []byte |
||||||
|
}{ |
||||||
|
{ |
||||||
|
"base", |
||||||
|
[]byte{ |
||||||
|
0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x01, |
||||||
|
0x00, 0x00, 0x02, |
||||||
|
0x00, 0x00, 0x03, |
||||||
|
}, |
||||||
|
[]byte{ |
||||||
|
0x00, 0x00, 0x03, 0x00, |
||||||
|
0x00, 0x00, 0x03, 0x01, |
||||||
|
0x00, 0x00, 0x03, 0x02, |
||||||
|
0x00, 0x00, 0x03, 0x03, |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
func TestAntiCompetitionAdd(t *testing.T) { |
||||||
|
for _, ca := range casesAntiCompetition { |
||||||
|
t.Run(ca.name, func(t *testing.T) { |
||||||
|
proc := AntiCompetitionAdd(ca.unproc) |
||||||
|
require.Equal(t, ca.proc, proc) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestAntiCompetitionRemove(t *testing.T) { |
||||||
|
for _, ca := range casesAntiCompetition { |
||||||
|
t.Run(ca.name, func(t *testing.T) { |
||||||
|
unproc := AntiCompetitionRemove(ca.proc) |
||||||
|
require.Equal(t, ca.unproc, unproc) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
package h264 |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
// NALUType is the type of a NALU.
|
||||||
|
type NALUType uint8 |
||||||
|
|
||||||
|
// standard NALU types.
|
||||||
|
const ( |
||||||
|
NALUTypeNonIDR NALUType = 1 |
||||||
|
NALUTypeDataPartitionA NALUType = 2 |
||||||
|
NALUTypeDataPartitionB NALUType = 3 |
||||||
|
NALUTypeDataPartitionC NALUType = 4 |
||||||
|
NALUTypeIDR NALUType = 5 |
||||||
|
NALUTypeSei NALUType = 6 |
||||||
|
NALUTypeSPS NALUType = 7 |
||||||
|
NALUTypePPS NALUType = 8 |
||||||
|
NALUTypeAccessUnitDelimiter NALUType = 9 |
||||||
|
NALUTypeEndOfSequence NALUType = 10 |
||||||
|
NALUTypeEndOfStream NALUType = 11 |
||||||
|
NALUTypeFillerData NALUType = 12 |
||||||
|
NALUTypeSPSExtension NALUType = 13 |
||||||
|
NALUTypePrefix NALUType = 14 |
||||||
|
NALUTypeSubsetSPS NALUType = 15 |
||||||
|
NALUTypeReserved16 NALUType = 16 |
||||||
|
NALUTypeReserved17 NALUType = 17 |
||||||
|
NALUTypeReserved18 NALUType = 18 |
||||||
|
NALUTypeSliceLayerWithoutPartitioning NALUType = 19 |
||||||
|
NALUTypeSliceExtension NALUType = 20 |
||||||
|
NALUTypeSliceExtensionDepth NALUType = 21 |
||||||
|
NALUTypeReserved22 NALUType = 22 |
||||||
|
NALUTypeReserved23 NALUType = 23 |
||||||
|
NALUTypeStapA NALUType = 24 |
||||||
|
NALUTypeStapB NALUType = 25 |
||||||
|
NALUTypeMtap16 NALUType = 26 |
||||||
|
NALUTypeMtap24 NALUType = 27 |
||||||
|
NALUTypeFuA NALUType = 28 |
||||||
|
NALUTypeFuB NALUType = 29 |
||||||
|
) |
||||||
|
|
||||||
|
// String implements fmt.Stringer.
|
||||||
|
func (nt NALUType) String() string { |
||||||
|
switch nt { |
||||||
|
case NALUTypeNonIDR: |
||||||
|
return "NonIDR" |
||||||
|
case NALUTypeDataPartitionA: |
||||||
|
return "DataPartitionA" |
||||||
|
case NALUTypeDataPartitionB: |
||||||
|
return "DataPartitionB" |
||||||
|
case NALUTypeDataPartitionC: |
||||||
|
return "DataPartitionC" |
||||||
|
case NALUTypeIDR: |
||||||
|
return "IDR" |
||||||
|
case NALUTypeSei: |
||||||
|
return "Sei" |
||||||
|
case NALUTypeSPS: |
||||||
|
return "SPS" |
||||||
|
case NALUTypePPS: |
||||||
|
return "PPS" |
||||||
|
case NALUTypeAccessUnitDelimiter: |
||||||
|
return "AccessUnitDelimiter" |
||||||
|
case NALUTypeEndOfSequence: |
||||||
|
return "EndOfSequence" |
||||||
|
case NALUTypeEndOfStream: |
||||||
|
return "EndOfStream" |
||||||
|
case NALUTypeFillerData: |
||||||
|
return "FillerData" |
||||||
|
case NALUTypeSPSExtension: |
||||||
|
return "SPSExtension" |
||||||
|
case NALUTypePrefix: |
||||||
|
return "Prefix" |
||||||
|
case NALUTypeSubsetSPS: |
||||||
|
return "SubsetSPS" |
||||||
|
case NALUTypeReserved16: |
||||||
|
return "Reserved16" |
||||||
|
case NALUTypeReserved17: |
||||||
|
return "Reserved17" |
||||||
|
case NALUTypeReserved18: |
||||||
|
return "Reserved18" |
||||||
|
case NALUTypeSliceLayerWithoutPartitioning: |
||||||
|
return "SliceLayerWithoutPartitioning" |
||||||
|
case NALUTypeSliceExtension: |
||||||
|
return "SliceExtension" |
||||||
|
case NALUTypeSliceExtensionDepth: |
||||||
|
return "SliceExtensionDepth" |
||||||
|
case NALUTypeReserved22: |
||||||
|
return "Reserved22" |
||||||
|
case NALUTypeReserved23: |
||||||
|
return "Reserved23" |
||||||
|
case NALUTypeStapA: |
||||||
|
return "StapA" |
||||||
|
case NALUTypeStapB: |
||||||
|
return "StapB" |
||||||
|
case NALUTypeMtap16: |
||||||
|
return "Mtap16" |
||||||
|
case NALUTypeMtap24: |
||||||
|
return "Mtap24" |
||||||
|
case NALUTypeFuA: |
||||||
|
return "FuA" |
||||||
|
case NALUTypeFuB: |
||||||
|
return "FuB" |
||||||
|
} |
||||||
|
return fmt.Sprintf("unknown (%d)", nt) |
||||||
|
} |
Loading…
Reference in new issue