mirror of
https://github.com/bluenviron/mediacommon.git
synced 2025-09-26 21:01:14 +08:00
270 lines
5.6 KiB
Go
270 lines
5.6 KiB
Go
package mpeg4audio
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/bluenviron/mediacommon/v2/pkg/bits"
|
|
)
|
|
|
|
// Config is an alias for AudioSpecificConfig.
|
|
//
|
|
// Deprecated: replaced by AudioSpecificConfig.
|
|
type Config = AudioSpecificConfig
|
|
|
|
// AudioSpecificConfig is an AudioSpecificConfig.
|
|
// Specification: ISO 14496-3, 1.6.2.1
|
|
type AudioSpecificConfig struct {
|
|
Type ObjectType
|
|
SampleRate int
|
|
ChannelCount int
|
|
|
|
// SBR / PS specific
|
|
ExtensionType ObjectType
|
|
ExtensionSampleRate int
|
|
|
|
// GASpecificConfig
|
|
FrameLengthFlag bool
|
|
DependsOnCoreCoder bool
|
|
CoreCoderDelay uint16
|
|
}
|
|
|
|
// Unmarshal decodes a AudioSpecificConfig.
|
|
func (c *AudioSpecificConfig) Unmarshal(buf []byte) error {
|
|
pos := 0
|
|
err := c.unmarshalBits(buf, &pos)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UnmarshalFromPos decodes a AudioSpecificConfig.
|
|
//
|
|
// Deprecated: not meant to be public.
|
|
func (c *AudioSpecificConfig) UnmarshalFromPos(buf []byte, pos *int) error {
|
|
return c.unmarshalBits(buf, pos)
|
|
}
|
|
|
|
// unmarshalBits decodes a AudioSpecificConfig.
|
|
func (c *AudioSpecificConfig) unmarshalBits(buf []byte, pos *int) error {
|
|
tmp, err := bits.ReadBits(buf, pos, 5)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.Type = ObjectType(tmp)
|
|
|
|
switch c.Type {
|
|
case ObjectTypeAACLC, ObjectTypeSBR, ObjectTypePS:
|
|
default:
|
|
return fmt.Errorf("unsupported object type: %d", c.Type)
|
|
}
|
|
|
|
sampleRateIndex, err := bits.ReadBits(buf, pos, 4)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch {
|
|
case sampleRateIndex <= 12:
|
|
c.SampleRate = sampleRates[sampleRateIndex]
|
|
|
|
case sampleRateIndex == 0x0F:
|
|
tmp, err = bits.ReadBits(buf, pos, 24)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.SampleRate = int(tmp)
|
|
|
|
default:
|
|
return fmt.Errorf("invalid sample rate index (%d)", sampleRateIndex)
|
|
}
|
|
|
|
channelConfig, err := bits.ReadBits(buf, pos, 4)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch {
|
|
case channelConfig == 0:
|
|
return fmt.Errorf("not yet supported")
|
|
|
|
case channelConfig >= 1 && channelConfig <= 6:
|
|
c.ChannelCount = int(channelConfig)
|
|
|
|
case channelConfig == 7:
|
|
c.ChannelCount = 8
|
|
|
|
default:
|
|
return fmt.Errorf("invalid channel configuration (%d)", channelConfig)
|
|
}
|
|
|
|
if c.Type == ObjectTypeSBR || c.Type == ObjectTypePS {
|
|
c.ExtensionType = c.Type
|
|
|
|
var extensionSamplingFrequencyIndex uint64
|
|
extensionSamplingFrequencyIndex, err = bits.ReadBits(buf, pos, 4)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch {
|
|
case extensionSamplingFrequencyIndex <= 12:
|
|
c.ExtensionSampleRate = sampleRates[extensionSamplingFrequencyIndex]
|
|
|
|
case extensionSamplingFrequencyIndex == 0x0F:
|
|
tmp, err = bits.ReadBits(buf, pos, 24)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.ExtensionSampleRate = int(tmp)
|
|
|
|
default:
|
|
return fmt.Errorf("invalid extension sample rate index: %d", extensionSamplingFrequencyIndex)
|
|
}
|
|
|
|
tmp, err = bits.ReadBits(buf, pos, 5)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.Type = ObjectType(tmp)
|
|
|
|
if c.Type != ObjectTypeAACLC {
|
|
return fmt.Errorf("unsupported object type: %d", c.Type)
|
|
}
|
|
}
|
|
|
|
// GASpecificConfig
|
|
|
|
c.FrameLengthFlag, err = bits.ReadFlag(buf, pos)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.DependsOnCoreCoder, err = bits.ReadFlag(buf, pos)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.DependsOnCoreCoder {
|
|
tmp, err = bits.ReadBits(buf, pos, 14)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.CoreCoderDelay = uint16(tmp)
|
|
}
|
|
|
|
extensionFlag, err := bits.ReadFlag(buf, pos)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if extensionFlag {
|
|
return fmt.Errorf("extensionFlag is unsupported")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c AudioSpecificConfig) marshalSizeBits() int {
|
|
n := 5 + 4 + 2 + 1
|
|
|
|
_, ok := reverseSampleRates[c.SampleRate]
|
|
if !ok {
|
|
n += 28
|
|
} else {
|
|
n += 4
|
|
}
|
|
|
|
if c.ExtensionType == ObjectTypeSBR || c.ExtensionType == ObjectTypePS {
|
|
_, ok = reverseSampleRates[c.ExtensionSampleRate]
|
|
if !ok {
|
|
n += 28
|
|
} else {
|
|
n += 4
|
|
}
|
|
n += 5
|
|
}
|
|
|
|
if c.DependsOnCoreCoder {
|
|
n += 14
|
|
}
|
|
|
|
return n
|
|
}
|
|
|
|
func (c AudioSpecificConfig) marshalSize() int {
|
|
n := c.marshalSizeBits()
|
|
|
|
ret := n / 8
|
|
if (n % 8) != 0 {
|
|
ret++
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
// Marshal encodes a AudioSpecificConfig.
|
|
func (c AudioSpecificConfig) Marshal() ([]byte, error) {
|
|
buf := make([]byte, c.marshalSize())
|
|
pos := 0
|
|
|
|
err := c.marshalToBits(buf, &pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
func (c AudioSpecificConfig) marshalToBits(buf []byte, pos *int) error {
|
|
if c.ExtensionType == ObjectTypeSBR || c.ExtensionType == ObjectTypePS {
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(c.ExtensionType), 5)
|
|
} else {
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(c.Type), 5)
|
|
}
|
|
|
|
sampleRateIndex, ok := reverseSampleRates[c.SampleRate]
|
|
if !ok {
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(15), 4)
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(c.SampleRate), 24)
|
|
} else {
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(sampleRateIndex), 4)
|
|
}
|
|
|
|
var channelConfig int
|
|
switch {
|
|
case c.ChannelCount >= 1 && c.ChannelCount <= 6:
|
|
channelConfig = c.ChannelCount
|
|
|
|
case c.ChannelCount == 8:
|
|
channelConfig = 7
|
|
|
|
default:
|
|
return fmt.Errorf("invalid channel count (%d)", c.ChannelCount)
|
|
}
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(channelConfig), 4)
|
|
|
|
if c.ExtensionType == ObjectTypeSBR || c.ExtensionType == ObjectTypePS {
|
|
sampleRateIndex, ok = reverseSampleRates[c.ExtensionSampleRate]
|
|
if !ok {
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(0x0F), 4)
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(c.ExtensionSampleRate), 24)
|
|
} else {
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(sampleRateIndex), 4)
|
|
}
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(c.Type), 5)
|
|
}
|
|
|
|
bits.WriteFlagUnsafe(buf, pos, c.FrameLengthFlag)
|
|
bits.WriteFlagUnsafe(buf, pos, c.DependsOnCoreCoder)
|
|
|
|
if c.DependsOnCoreCoder {
|
|
bits.WriteBitsUnsafe(buf, pos, uint64(c.CoreCoderDelay), 14)
|
|
}
|
|
|
|
*pos++ // extensionFlag
|
|
|
|
return nil
|
|
}
|