gpt4 book ai didi

ios - 我可以使用 AVCaptureSession 将 AAC 流编码到内存吗?

转载 作者:可可西里 更新时间:2023-11-01 03:31:24 30 4
gpt4 key购买 nike

我正在编写一个通过网络流式传输视频和音频的 iOS 应用。

我正在使用 AVCaptureSession 使用 AVCaptureVideoDataOutput 抓取原始视频帧并在软件中对其进行编码 using x264 .这很好用。

我想对音频做同样的事情,只是我不需要在音频方面进行太多控制,所以我想使用内置的硬件编码器来生成 AAC 流。这意味着使用 Audio Converter从音频工具箱层。为此,我为 AVCaptudeAudioDataOutput 的音频帧添加了一个处理程序:

- (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”(正在使用的硬件)错误。如果 session 停止,则转换工作正常,但我无法捕获任何内容...

我想知道是否有办法从 AVCaptureSession 中获取 AAC 流。我正在考虑的选项是:

  1. 以某种方式使用 AVAssetWriterInput 将音频样本编码为 AAC,然后以某种方式获取编码数据包(不是通过 AVAssetWriter,它只会写入文件)。

  2. 重组我的应用,使其仅在视频端使用 AVCaptureSession 并使用 Audio Queues在音频方面。这将使流量控制(开始和停止录制,响应中断)变得更加复杂,而且我担心它可能会导致音频和视频之间的同步问题。而且,它看起来也不是一个好的设计。

有谁知道是否可以从 AVCaptureSession 中获取 AAC?我必须在这里使用音频队列吗?这会让我陷入同步或控制问题吗?

最佳答案

我最后向 Apple 征求意见(事实证明,如果你有付费开发者帐户,你就可以这样做)。

AVCaptureSession 似乎掌握了 AAC 硬件编码器,但只允许您使用它直接写入文件。

您可以使用软件编码器,但您必须专门要求它而不是使用 AudioConverterNew:

AudioClassDescription *description = [self
getAudioClassDescriptionWithType:kAudioFormatMPEG4AAC
fromManufacturer:kAppleSoftwareAudioCodecManufacturer];
if (!description) {
return false;
}
// see the question as for setting up pcmASBD and arc ASBD
OSStatus st = AudioConverterNewSpecific(&pcmASBD, &aacASBD, 1, description, &_converter);
if (st) {
NSLog(@"error creating audio converter: %s", OSSTATUS(st));
return false;
}

- (AudioClassDescription *)getAudioClassDescriptionWithType:(UInt32)type
fromManufacturer:(UInt32)manufacturer
{
static AudioClassDescription desc;

UInt32 encoderSpecifier = type;
OSStatus st;

UInt32 size;
st = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders,
sizeof(encoderSpecifier),
&encoderSpecifier,
&size);
if (st) {
NSLog(@"error getting audio format propery info: %s", OSSTATUS(st));
return nil;
}

unsigned int count = size / sizeof(AudioClassDescription);
AudioClassDescription descriptions[count];
st = AudioFormatGetProperty(kAudioFormatProperty_Encoders,
sizeof(encoderSpecifier),
&encoderSpecifier,
&size,
descriptions);
if (st) {
NSLog(@"error getting audio format propery: %s", OSSTATUS(st));
return nil;
}

for (unsigned int i = 0; i < count; i++) {
if ((type == descriptions[i].mSubType) &&
(manufacturer == descriptions[i].mManufacturer)) {
memcpy(&desc, &(descriptions[i]), sizeof(desc));
return &desc;
}
}

return nil;
}

当然,软件编码器会占用 CPU 资源,但会完成工作。

关于ios - 我可以使用 AVCaptureSession 将 AAC 流编码到内存吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10817036/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com