rtpaac: add more test cases to MPEG4AudioConfig

This commit is contained in:
aler9
2021-03-21 21:44:01 +01:00
parent 9c9a651243
commit b4c7e9b95f
6 changed files with 278 additions and 234 deletions

View File

@@ -0,0 +1,124 @@
package rtpaac
import (
"bytes"
"fmt"
"github.com/icza/bitio"
)
// MPEG4AudioType is the type of a MPEG-4 Audio stream.
type MPEG4AudioType int
// standard MPEG-4 Audio types.
const (
MPEG4AudioTypeAACLC MPEG4AudioType = 2
)
// MPEG4AudioConfig is a MPEG-4 Audio configuration.
type MPEG4AudioConfig struct {
Type MPEG4AudioType
SampleRate int
ChannelCount int
}
// Decode decodes an MPEG-4 Audio configuration.
func (c *MPEG4AudioConfig) Decode(byts []byte) error {
// ref: https://wiki.multimedia.cx/index.php/MPEG-4_Audio
r := bitio.NewReader(bytes.NewBuffer(byts))
tmp, err := r.ReadBits(5)
if err != nil {
return err
}
c.Type = MPEG4AudioType(tmp)
if tmp == 31 {
tmp, err = r.ReadBits(6)
if err != nil {
return err
}
c.Type = MPEG4AudioType(tmp + 32)
}
switch c.Type {
case MPEG4AudioTypeAACLC:
default:
return fmt.Errorf("unsupported type: %d", c.Type)
}
sampleRateIndex, err := r.ReadBits(4)
if err != nil {
return err
}
switch sampleRateIndex {
case 0:
c.SampleRate = 96000
case 1:
c.SampleRate = 88200
case 2:
c.SampleRate = 64000
case 3:
c.SampleRate = 48000
case 4:
c.SampleRate = 44100
case 5:
c.SampleRate = 32000
case 6:
c.SampleRate = 24000
case 7:
c.SampleRate = 22050
case 8:
c.SampleRate = 16000
case 9:
c.SampleRate = 12000
case 10:
c.SampleRate = 11025
case 11:
c.SampleRate = 8000
case 12:
c.SampleRate = 7350
case 15:
sampleRateIndex, err := r.ReadBits(24)
if err != nil {
return err
}
c.SampleRate = int(sampleRateIndex)
default:
return fmt.Errorf("invalid sample rate index: %d", sampleRateIndex)
}
channelConfig, err := r.ReadBits(4)
if err != nil {
return err
}
switch channelConfig {
case 0:
return fmt.Errorf("not yet supported")
case 1:
c.ChannelCount = 1
case 2:
c.ChannelCount = 2
case 3:
c.ChannelCount = 3
case 4:
c.ChannelCount = 4
case 5:
c.ChannelCount = 5
case 6:
c.ChannelCount = 6
case 7:
c.ChannelCount = 8
default:
return fmt.Errorf("invalid channel configuration: %d", channelConfig)
}
return nil
}

View File

@@ -0,0 +1,52 @@
package rtpaac
import (
"testing"
"github.com/stretchr/testify/require"
)
var configCases = []struct {
name string
enc []byte
dec MPEG4AudioConfig
}{
{
name: "aac-lc 48khz stereo",
enc: []byte{17, 144},
dec: MPEG4AudioConfig{
Type: MPEG4AudioTypeAACLC,
SampleRate: 48000,
ChannelCount: 2,
},
},
{
name: "aac-lc 96khz stereo",
enc: []byte{0x10, 0x10, 0x56, 0xE5, 0x00},
dec: MPEG4AudioConfig{
Type: MPEG4AudioTypeAACLC,
SampleRate: 96000,
ChannelCount: 2,
},
},
{
name: "aac-lc 44.1khz 5.1",
enc: []byte{0x12, 0x30},
dec: MPEG4AudioConfig{
Type: MPEG4AudioTypeAACLC,
SampleRate: 44100,
ChannelCount: 6,
},
},
}
func TestConfigDecode(t *testing.T) {
for _, ca := range configCases {
t.Run(ca.name, func(t *testing.T) {
var dec MPEG4AudioConfig
err := dec.Decode(ca.enc)
require.NoError(t, err)
require.Equal(t, ca.dec, dec)
})
}
}

View File

@@ -2,11 +2,7 @@
package rtpaac
import (
"bytes"
"fmt"
"time"
"github.com/icza/bitio"
)
// AUAndTimestamp is an Access Unit and its timestamp.
@@ -14,105 +10,3 @@ type AUAndTimestamp struct {
Timestamp time.Duration
AU []byte
}
// MPEG4AudioConfig is a MPEG-4 Audio configuration.
type MPEG4AudioConfig struct {
ObjectType int
SampleRate int
ChannelCount int
}
// Decode decodes an MPEG-4 Audio configuration.
func (c *MPEG4AudioConfig) Decode(byts []byte) error {
// ref: https://wiki.multimedia.cx/index.php/MPEG-4_Audio
r := bitio.NewReader(bytes.NewBuffer(byts))
tmp, err := r.ReadBits(5)
if err != nil {
return err
}
c.ObjectType = int(tmp)
if tmp == 31 {
tmp, err = r.ReadBits(6)
if err != nil {
return err
}
c.ObjectType = int(tmp + 32)
}
sampleRateIndex, err := r.ReadBits(4)
if err != nil {
return err
}
switch sampleRateIndex {
case 0:
c.SampleRate = 96000
case 1:
c.SampleRate = 88200
case 2:
c.SampleRate = 64000
case 3:
c.SampleRate = 48000
case 4:
c.SampleRate = 44100
case 5:
c.SampleRate = 32000
case 6:
c.SampleRate = 24000
case 7:
c.SampleRate = 22050
case 8:
c.SampleRate = 16000
case 9:
c.SampleRate = 12000
case 10:
c.SampleRate = 11025
case 11:
c.SampleRate = 8000
case 12:
c.SampleRate = 7350
case 15:
sampleRateIndex, err := r.ReadBits(24)
if err != nil {
return err
}
c.SampleRate = int(sampleRateIndex)
default:
return fmt.Errorf("invalid sample rate index: %d", sampleRateIndex)
}
channelConfig, err := r.ReadBits(4)
if err != nil {
return err
}
switch channelConfig {
case 0:
return fmt.Errorf("not yet supported")
case 1:
c.ChannelCount = 1
case 2:
c.ChannelCount = 2
case 3:
c.ChannelCount = 3
case 4:
c.ChannelCount = 4
case 5:
c.ChannelCount = 5
case 6:
c.ChannelCount = 6
case 7:
c.ChannelCount = 8
default:
return fmt.Errorf("invalid channel configuration: %d", channelConfig)
}
return nil
}

View File

@@ -7,33 +7,6 @@ import (
"github.com/stretchr/testify/require"
)
var configCases = []struct {
name string
enc []byte
dec MPEG4AudioConfig
}{
{
name: "test 1",
enc: []byte{17, 144},
dec: MPEG4AudioConfig{
ObjectType: 2,
SampleRate: 48000,
ChannelCount: 2,
},
},
}
func TestConfigDecode(t *testing.T) {
for _, ca := range configCases {
t.Run(ca.name, func(t *testing.T) {
var dec MPEG4AudioConfig
err := dec.Decode(ca.enc)
require.NoError(t, err)
require.Equal(t, ca.dec, dec)
})
}
}
var cases = []struct {
name string
dec *AUAndTimestamp

102
pkg/rtph264/nalutype.go Normal file
View File

@@ -0,0 +1,102 @@
package rtph264
// 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 "unknown"
}

View File

@@ -10,104 +10,3 @@ type NALUAndTimestamp struct {
Timestamp time.Duration
NALU []byte
}
// 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 "unknown"
}