mirror of
https://github.com/aler9/gortsplib
synced 2025-10-19 21:44:51 +08:00
rtpaac: add more test cases to MPEG4AudioConfig
This commit is contained in:
124
pkg/rtpaac/mpeg4audioconfig.go
Normal file
124
pkg/rtpaac/mpeg4audioconfig.go
Normal 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
|
||||
}
|
52
pkg/rtpaac/mpeg4audioconfig_test.go
Normal file
52
pkg/rtpaac/mpeg4audioconfig_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
@@ -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
102
pkg/rtph264/nalutype.go
Normal 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"
|
||||
}
|
@@ -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"
|
||||
}
|
||||
|
Reference in New Issue
Block a user