我正在编写一个通过网络传输视频和音频的 iOS 应用程序。
我正在使用 AVCaptureSession 使用AVCaptureVideoDataOutput抓取原始视频帧,并使用 x264在软件中对其进行编码。这很好用。
我想对音频做同样的事情,只是我不需要在音频方面进行太多控制,所以我想使用内置的硬件编码器来生成 AAC 流。这意味着使用音频工具箱层中的音频转换器。为了做到这一点,我为AVCapudeAudioDataOutput的音频帧添加了一个处理程序:
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
// get the audio samples into a common buffer _pcmBuffer
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &_pcmBufferSize, &_pcmBuffer);
// use AudioConverter to
UInt32 ouputPacketsCount = 1;
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = 1;
bufferList.mBuffers[0].mDataByteSize = sizeof(_aacBuffer);
bufferList.mBuffers[0].mData = _aacBuffer;
OSStatus st = AudioConverterFillComplexBuffer(_converter, converter_callback, (__bridge void *) self, &ouputPacketsCount, &bufferList, NULL);
if (0 == st) {
// ... send bufferList.mBuffers[0].mDataByteSize bytes from _aacBuffer...
}
}
在这种情况下,音频转换器的回调函数非常简单(假设数据包大小和计数设置正确):
- (void) putPcmSamplesInBufferList:(AudioBufferList *)bufferList withCount:(UInt32 *)count
{
bufferList->mBuffers[0].mData = _pcmBuffer;
bufferList->mBuffers[0].mDataByteSize = _pcmBufferSize;
}
音频转换器的设置如下所示:
{
// ...
AudioStreamBasicDescription pcmASBD = {0};
pcmASBD.mSampleRate = ((AVAudioSession *) [AVAudioSession sharedInstance]).currentHardwareSampleRate;
pcmASBD.mFormatID = kAudioFormatLinearPCM;
pcmASBD.mFormatFlags = kAudioFormatFlagsCanonical;
pcmASBD.mChannelsPerFrame = 1;
pcmASBD.mBytesPerFrame = sizeof(AudioSampleType);
pcmASBD.mFramesPerPacket = 1;
pcmASBD.mBytesPerPacket = pcmASBD.mBytesPerFrame * pcmASBD.mFramesPerPacket;
pcmASBD.mBitsPerChannel = 8 * pcmASBD.mBytesPerFrame;
AudioStreamBasicDescription aacASBD = {0};
aacASBD.mFormatID = kAudioFormatMPEG4AAC;
aacASBD.mSampleRate = pcmASBD.mSampleRate;
aacASBD.mChannelsPerFrame = pcmASBD.mChannelsPerFrame;
size = sizeof(aacASBD);
AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &aacASBD);
AudioConverterNew(&pcmASBD, &aacASBD, &_converter);
// ...
}
这似乎很简单,只是它不起作用。一旦 AVCaptureSession 运行,音频转换器(特别是 AudioConverterFillComplexBuffer)返回一个“hwiu”(使用中的硬件)错误。如果会话停止,转换工作正常,但我无法捕获任何东西......
我想知道是否有办法从 AVCaptureSession 中获取 AAC 流。我正在考虑的选项是:
不知何故使用 AVAssetWriterInput 将音频样本编码为 AAC,然后以某种方式获取编码的数据包(而不是通过 AVAssetWriter,它只会写入文件)。
重新组织我的应用程序,使其仅在视频端使用 AVCaptureSession 并在音频端使用音频队列。这将使流控制(开始和停止录制,响应中断)更加复杂,我担心它可能会导致音频和视频之间的同步问题。此外,它似乎不是一个好的设计。
有谁知道是否可以将 AAC 从 AVCaptureSession 中取出?我必须在这里使用音频队列吗?这会让我陷入同步或控制问题吗?