github.com/bluenviron/mediacommon@v1.9.3/pkg/codecs/mpeg4audio/adts.go (about)

     1  package mpeg4audio
     2  
     3  import (
     4  	"fmt"
     5  )
     6  
     7  // ADTSPacket is an ADTS frame.
     8  // Specification: ISO 14496-3, Table 1.A.5
     9  type ADTSPacket struct {
    10  	Type         ObjectType
    11  	SampleRate   int
    12  	ChannelCount int
    13  	AU           []byte
    14  }
    15  
    16  // ADTSPackets is a group od ADTS packets.
    17  type ADTSPackets []*ADTSPacket
    18  
    19  // Unmarshal decodes an ADTS stream into ADTS packets.
    20  func (ps *ADTSPackets) Unmarshal(buf []byte) error {
    21  	// refs: https://wiki.multimedia.cx/index.php/ADTS
    22  
    23  	bl := len(buf)
    24  	pos := 0
    25  
    26  	for {
    27  		if (bl - pos) < 8 {
    28  			return fmt.Errorf("invalid length")
    29  		}
    30  
    31  		syncWord := (uint16(buf[pos]) << 4) | (uint16(buf[pos+1]) >> 4)
    32  		if syncWord != 0xfff {
    33  			return fmt.Errorf("invalid syncword")
    34  		}
    35  
    36  		protectionAbsent := buf[pos+1] & 0x01
    37  		if protectionAbsent != 1 {
    38  			return fmt.Errorf("CRC is not supported")
    39  		}
    40  
    41  		pkt := &ADTSPacket{}
    42  
    43  		pkt.Type = ObjectType((buf[pos+2] >> 6) + 1)
    44  		switch pkt.Type {
    45  		case ObjectTypeAACLC:
    46  		default:
    47  			return fmt.Errorf("unsupported audio type: %d", pkt.Type)
    48  		}
    49  
    50  		sampleRateIndex := (buf[pos+2] >> 2) & 0x0F
    51  		switch {
    52  		case sampleRateIndex <= 12:
    53  			pkt.SampleRate = sampleRates[sampleRateIndex]
    54  
    55  		default:
    56  			return fmt.Errorf("invalid sample rate index: %d", sampleRateIndex)
    57  		}
    58  
    59  		channelConfig := ((buf[pos+2] & 0x01) << 2) | ((buf[pos+3] >> 6) & 0x03)
    60  		switch {
    61  		case channelConfig >= 1 && channelConfig <= 6:
    62  			pkt.ChannelCount = int(channelConfig)
    63  
    64  		case channelConfig == 7:
    65  			pkt.ChannelCount = 8
    66  
    67  		default:
    68  			return fmt.Errorf("invalid channel configuration: %d", channelConfig)
    69  		}
    70  
    71  		frameLen := int(((uint16(buf[pos+3])&0x03)<<11)|
    72  			(uint16(buf[pos+4])<<3)|
    73  			((uint16(buf[pos+5])>>5)&0x07)) - 7
    74  
    75  		if frameLen <= 0 {
    76  			return fmt.Errorf("invalid FrameLen")
    77  		}
    78  
    79  		if frameLen > MaxAccessUnitSize {
    80  			return fmt.Errorf("access unit size (%d) is too big, maximum is %d", frameLen, MaxAccessUnitSize)
    81  		}
    82  
    83  		frameCount := buf[pos+6] & 0x03
    84  		if frameCount != 0 {
    85  			return fmt.Errorf("frame count greater than 1 is not supported")
    86  		}
    87  
    88  		if len(buf[pos+7:]) < frameLen {
    89  			return fmt.Errorf("invalid frame length")
    90  		}
    91  
    92  		pkt.AU = buf[pos+7 : pos+7+frameLen]
    93  		pos += 7 + frameLen
    94  
    95  		*ps = append(*ps, pkt)
    96  
    97  		if (bl - pos) == 0 {
    98  			break
    99  		}
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  func (ps ADTSPackets) marshalSize() int {
   106  	n := 0
   107  	for _, pkt := range ps {
   108  		n += 7 + len(pkt.AU)
   109  	}
   110  	return n
   111  }
   112  
   113  // Marshal encodes ADTS packets into an ADTS stream.
   114  func (ps ADTSPackets) Marshal() ([]byte, error) {
   115  	buf := make([]byte, ps.marshalSize())
   116  	pos := 0
   117  
   118  	for _, pkt := range ps {
   119  		sampleRateIndex, ok := reverseSampleRates[pkt.SampleRate]
   120  		if !ok {
   121  			return nil, fmt.Errorf("invalid sample rate: %d", pkt.SampleRate)
   122  		}
   123  
   124  		var channelConfig int
   125  		switch {
   126  		case pkt.ChannelCount >= 1 && pkt.ChannelCount <= 6:
   127  			channelConfig = pkt.ChannelCount
   128  
   129  		case pkt.ChannelCount == 8:
   130  			channelConfig = 7
   131  
   132  		default:
   133  			return nil, fmt.Errorf("invalid channel count (%d)", pkt.ChannelCount)
   134  		}
   135  
   136  		frameLen := len(pkt.AU) + 7
   137  
   138  		fullness := 0x07FF // like ffmpeg does
   139  
   140  		buf[pos+0] = 0xFF
   141  		buf[pos+1] = 0xF1
   142  		buf[pos+2] = uint8((int(pkt.Type-1) << 6) | (sampleRateIndex << 2) | ((channelConfig >> 2) & 0x01))
   143  		buf[pos+3] = uint8((channelConfig&0x03)<<6 | (frameLen>>11)&0x03)
   144  		buf[pos+4] = uint8((frameLen >> 3) & 0xFF)
   145  		buf[pos+5] = uint8((frameLen&0x07)<<5 | ((fullness >> 6) & 0x1F))
   146  		buf[pos+6] = uint8((fullness & 0x3F) << 2)
   147  		pos += 7
   148  
   149  		pos += copy(buf[pos:], pkt.AU)
   150  	}
   151  
   152  	return buf, nil
   153  }