github.com/cnotch/ipchub@v1.1.0/av/codec/aac/asc.go (about)

     1  // Copyright (c) 2019,CAOHONGJU All rights reserved.
     2  // Use of this source code is governed by a MIT-style
     3  // license that can be found in the LICENSE file.
     4  //
     5  // Translate from FFmpeg mpeg4audio.h mpeg4audio.c
     6  //
     7  package aac
     8  
     9  import (
    10  	"encoding/binary"
    11  	"encoding/hex"
    12  	"errors"
    13  	"fmt"
    14  	"runtime/debug"
    15  
    16  	"github.com/cnotch/ipchub/utils/bits"
    17  )
    18  
    19  // RawSps AudioSpecificConfig 的别名
    20  type RawSPS = AudioSpecificConfig
    21  
    22  // AudioSpecificConfig .
    23  type AudioSpecificConfig struct {
    24  	ObjectType       uint8
    25  	SamplingIndex    uint8
    26  	SampleRate       int
    27  	ChannelConfig    uint8
    28  	Sbr              int ///< -1 implicit, 1 presence
    29  	ExtObjectType    uint8
    30  	ExtSamplingIndex uint8
    31  	ExtSampleRate    int
    32  	ExtChannelConfig uint8
    33  	Channels         uint8
    34  	Ps               int ///< -1 implicit, 1 presence
    35  	FrameLengthShort int
    36  }
    37  
    38  // DecodeString 从 hex 字串解码 sps
    39  func (asc *AudioSpecificConfig) DecodeString(config string) error {
    40  	data, err := hex.DecodeString(config)
    41  	if err != nil {
    42  		return err
    43  	}
    44  	return asc.Decode(data)
    45  }
    46  
    47  // Decode 从字节序列中解码 sps
    48  func (asc *AudioSpecificConfig) Decode(config []byte) (err error) {
    49  	defer func() {
    50  		if r := recover(); r != nil {
    51  			err = fmt.Errorf("AudioSpecificConfig decode panic;r = %v \n %s", r, debug.Stack())
    52  		}
    53  	}()
    54  
    55  	r := bits.NewReader(config)
    56  
    57  	asc.ObjectType = getObjectType(r)
    58  	asc.SamplingIndex, asc.SampleRate = getSampleRate(r)
    59  	asc.ChannelConfig = r.ReadUint8(4)
    60  	if int(asc.ChannelConfig) < len(aacAudioChannels) {
    61  		asc.Channels = aacAudioChannels[asc.ChannelConfig]
    62  	}
    63  	asc.Sbr = -1
    64  	asc.Ps = -1
    65  	if asc.ObjectType == AOT_SBR || (asc.ObjectType == AOT_PS &&
    66  		0 == r.Peek(3)&0x03 && 0 == r.Peek(9)&0x3F) { // check for W6132 Annex YYYY draft MP3onMP4
    67  		if asc.ObjectType == AOT_PS {
    68  			asc.Ps = 1
    69  		}
    70  		asc.ExtObjectType = AOT_SBR
    71  		asc.Sbr = 1
    72  		asc.ExtSamplingIndex, asc.ExtSampleRate = getSampleRate(r)
    73  		asc.ObjectType = getObjectType(r)
    74  		if asc.ObjectType == AOT_ER_BSAC {
    75  			asc.ExtChannelConfig = r.ReadUint8(4)
    76  		}
    77  	} else {
    78  		asc.ExtObjectType = AOT_NULL
    79  		asc.ExtSampleRate = 0
    80  	}
    81  
    82  	if asc.ObjectType == AOT_ALS {
    83  		r.Skip(5)
    84  		if uint32(r.Peek(24)) != binary.BigEndian.Uint32([]byte{0, 'A', 'L', 'S'}) {
    85  			r.Skip(24)
    86  		}
    87  
    88  		if err = asc.parseConfigALS(r); err != nil {
    89  			return
    90  		}
    91  	}
    92  
    93  	if asc.ExtObjectType != AOT_SBR {
    94  		for r.BitsLeft() > 15 {
    95  			if r.Peek(11) == 0x2b7 { // sync extension
    96  				r.Skip(11)
    97  				asc.ExtObjectType = getObjectType(r)
    98  				if asc.ExtObjectType == AOT_SBR {
    99  					asc.Sbr = int(r.ReadBit())
   100  					if asc.Sbr == 1 {
   101  						asc.ExtSamplingIndex, asc.ExtSampleRate = getSampleRate(r)
   102  						if asc.ExtSampleRate == asc.SampleRate {
   103  							asc.Sbr = -1
   104  						}
   105  					}
   106  
   107  				}
   108  				if r.BitsLeft() > 11 && r.Read(11) == 0x548 {
   109  					asc.Ps = int(r.ReadBit())
   110  				}
   111  
   112  				break
   113  			} else {
   114  				r.Skip(1) // skip 1 bit
   115  			}
   116  		}
   117  	}
   118  
   119  	//PS requires SBR
   120  	if asc.Sbr == 0 {
   121  		asc.Ps = 0
   122  	}
   123  	//Limit implicit PS to the HE-AACv2 Profile
   124  	if (asc.Ps == -1 && asc.ObjectType != AOT_AAC_LC) || (asc.Channels&^0x01) != 0 {
   125  		asc.Ps = 0
   126  	}
   127  	return
   128  }
   129  
   130  func (asc *AudioSpecificConfig) ToAdtsHeader(payloadSize int) ADTSHeader {
   131  	sampleRateIdx := asc.SamplingIndex
   132  	if asc.ExtSampleRate > 0 {
   133  		sampleRateIdx = asc.ExtSamplingIndex
   134  	}
   135  
   136  	return NewADTSHeader(asc.ObjectType-1, sampleRateIdx, asc.ChannelConfig, payloadSize)
   137  }
   138  
   139  func Encode2BytesASC(objType, samplingIdx, channelConfig byte) []byte {
   140  	var config = make([]byte, 2)
   141  	config[0] = objType<<3 | (samplingIdx>>1)&0x07
   142  	config[1] = samplingIdx<<7 | (channelConfig&0x0f)<<3
   143  	return config
   144  }
   145  
   146  var errInvalidData = errors.New("Invalid data found when processing input")
   147  
   148  func (asc *AudioSpecificConfig) parseConfigALS(r *bits.Reader) (err error) {
   149  	if r.BitsLeft() < 112 {
   150  		return errInvalidData
   151  	}
   152  
   153  	if r.Read(32) != binary.BigEndian.Uint32([]byte{'A', 'L', 'S', 0}) {
   154  		return errInvalidData
   155  	}
   156  
   157  	// override AudioSpecificConfig channel configuration and sample rate
   158  	// which are buggy in old ALS conformance files
   159  	asc.SampleRate = r.ReadInt(32)
   160  
   161  	if asc.SampleRate <= 0 {
   162  		return errInvalidData
   163  	}
   164  
   165  	// skip number of samples
   166  	r.Skip(32)
   167  
   168  	// read number of channels
   169  	asc.ChannelConfig = 0
   170  	asc.Channels = uint8(r.ReadInt(16) + 1)
   171  	return
   172  }
   173  
   174  func getObjectType(r *bits.Reader) (objType uint8) {
   175  	objType = r.ReadUint8(5)
   176  
   177  	if AOT_ESCAPE == objType {
   178  		objType = r.ReadUint8(6) + 32
   179  	}
   180  	return
   181  }
   182  
   183  func getSampleRate(r *bits.Reader) (sampleRateIdx uint8, sampleRate int) {
   184  	sampleRateIdx = r.ReadUint8(4)
   185  	if sampleRateIdx == 0xf {
   186  		sampleRate = r.ReadInt(24)
   187  	} else {
   188  		sampleRate = SampleRate(int(sampleRateIdx))
   189  	}
   190  	return
   191  }