//----------------------------------------------------------------------------- /*! @function AudioConverterNewSpecific @abstract Create a new AudioConverter using specific codecs.
@param inSourceFormat The format of the source audio to be converted. @param inDestinationFormat The destination format to which the audio is to be converted. @param inNumberClassDescriptions The number of class descriptions. @param inClassDescriptions AudioClassDescriptions specifiying the codec to instantiate. @param outAudioConverter On successful return, points to a new AudioConverter instance. @result An OSStatus result code. This function is identical to AudioConverterNew(), except that the client may explicitly choose which codec to instantiate if there is more than one choice. */ extern OSStatus AudioConverterNewSpecific( const AudioStreamBasicDescription * inSourceFormat, const AudioStreamBasicDescription * inDestinationFormat, UInt32 inNumberClassDescriptions, const AudioClassDescription * inClassDescriptions, AudioConverterRef __nullable * __nonnull outAudioConverter) API_AVAILABLE(macos(10.4), ios(2.0), watchos(2.0), tvos(9.0));
//----------------------------------------------------------------------------- /*! @function AudioConverterFillComplexBuffer @abstract Converts data supplied by an input callback function, supporting non-interleaved and packetized formats.
@param inAudioConverter The AudioConverter to use. @param inInputDataProc A callback function which supplies the input data. @param inInputDataProcUserData A value for the use of the callback function. @param ioOutputDataPacketSize On entry, the capacity of outOutputData expressed in packets in the converter's output format. On exit, the number of packets of converted data that were written to outOutputData. @param outOutputData The converted output data is written to this buffer. On entry, the buffers' mDataByteSize fields (which must all be the same) reflect buffer capacity. On exit, mDataByteSize is set to the number of bytes written. @param outPacketDescription If non-null, and the converter's output uses packet descriptions, then packet descriptions are written to this array. It must point to a memory block capable of holding *ioOutputDataPacketSize packet descriptions. (See AudioFormat.h for ways to determine whether an audio format uses packet descriptions). @result An OSStatus result code.
Produces a buffer list of output data from an AudioConverter. The supplied input callback function is called whenever necessary. */ extern OSStatus AudioConverterFillComplexBuffer( AudioConverterRef inAudioConverter, AudioConverterComplexInputDataProc inInputDataProc, void * __nullable inInputDataProcUserData, UInt32 * ioOutputDataPacketSize, AudioBufferList * outOutputData, AudioStreamPacketDescription * __nullable outPacketDescription) API_AVAILABLE(macos(10.2), ios(2.0), watchos(2.0), tvos(9.0));
使用完调用 AudioConverterDispose 释放资源:
1 2 3 4 5 6 7 8 9 10 11
//----------------------------------------------------------------------------- /*! @function AudioConverterDispose @abstract Destroy an AudioConverter.
@param inAudioConverter The AudioConverter to dispose. @result An OSStatus result code. */ extern OSStatus AudioConverterDispose( AudioConverterRef inAudioConverter) API_AVAILABLE(macos(10.1), ios(2.0), watchos(2.0), tvos(9.0));
另一个是时间戳的计算,在后续封装 Flv 时需要在 Tag Header 里指定这一帧起始位置的时间戳,为了保证音画同步,需要计算原始数据产生时的时间戳,我们在 Audio Unit 回调时打了一个时间戳,但这个时间戳至少是在此 Buffer 最后一个采样点产生时生成的,需要校准成第一个采样点产生时的时间,这个偏移量很好计算,用采样点个数除以采样率。由于 Buffer Data 需要先加入队列后取出,所以 Meta Data 也需要同样的操作,取出时需要再计算一个偏移量,保证给编码器的 Buffer 首个采样点的时间是对的。
实际测试过程中发现,在送入第一个 1024 frame 的 Buffer Data 给编码器后,输出的 Packet Size 只有 4 个字节,这显然是不足以压缩 1024 个 frame 的,由于目前还不太清楚编码器底层的实现,盲猜一下可能是编码器内部也有缓存,如果是这样的话,那上边计算时间戳的方式也是有偏差的,但实际影响不大,测试效果是 OK 的。