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

前端之家收集整理的这篇文章主要介绍了ios – 我可以使用AVCaptureSession将AAC流编码到内存吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在编写一个iOS应用程序,通过网络传输视频和音频.

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

我想对音频做同样的事情,只是因为我不需要在音频方面那么多控制,所以我想使用内置的硬件编码器来产生AAC流.这意味着使用Audio ToolBox图层中的Audio Converter.为了做到这一点,我为AVCaptudeAudioDataOutput的音频帧添加了一个处理程序:

  1. - (void)captureOutput:(AVCaptureOutput *)captureOutput
  2. didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
  3. fromConnection:(AVCaptureConnection *)connection
  4. {
  5. // get the audio samples into a common buffer _pcmBuffer
  6. CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
  7. CMBlockBufferGetDataPointer(blockBuffer,NULL,&_pcmBufferSize,&_pcmBuffer);
  8.  
  9. // use AudioConverter to
  10. UInt32 ouputPacketsCount = 1;
  11. AudioBufferList bufferList;
  12. bufferList.mNumberBuffers = 1;
  13. bufferList.mBuffers[0].mNumberChannels = 1;
  14. bufferList.mBuffers[0].mDataByteSize = sizeof(_aacBuffer);
  15. bufferList.mBuffers[0].mData = _aacBuffer;
  16. OSStatus st = AudioConverterFillComplexBuffer(_converter,converter_callback,(__bridge void *) self,&ouputPacketsCount,&bufferList,NULL);
  17. if (0 == st) {
  18. // ... send bufferList.mBuffers[0].mDataByteSize bytes from _aacBuffer...
  19. }
  20. }

在这种情况下,音频转换器的回调函数非常简单(假设数据包大小和计数设置正确):

  1. - (void) putPcmSamplesInBufferList:(AudioBufferList *)bufferList withCount:(UInt32 *)count
  2. {
  3. bufferList->mBuffers[0].mData = _pcmBuffer;
  4. bufferList->mBuffers[0].mDataByteSize = _pcmBufferSize;
  5. }

音频转换器的设置如下所示:

  1. {
  2. // ...
  3. AudioStreamBasicDescription pcmASBD = {0};
  4. pcmASBD.mSampleRate = ((AVAudioSession *) [AVAudioSession sharedInstance]).currentHardwareSampleRate;
  5. pcmASBD.mFormatID = kAudioFormatLinearPCM;
  6. pcmASBD.mFormatFlags = kAudioFormatFlagsCanonical;
  7. pcmASBD.mChannelsPerFrame = 1;
  8. pcmASBD.mBytesPerFrame = sizeof(AudioSampleType);
  9. pcmASBD.mFramesPerPacket = 1;
  10. pcmASBD.mBytesPerPacket = pcmASBD.mBytesPerFrame * pcmASBD.mFramesPerPacket;
  11. pcmASBD.mBitsPerChannel = 8 * pcmASBD.mBytesPerFrame;
  12.  
  13. AudioStreamBasicDescription aacASBD = {0};
  14. aacASBD.mFormatID = kAudioFormatMPEG4AAC;
  15. aacASBD.mSampleRate = pcmASBD.mSampleRate;
  16. aacASBD.mChannelsPerFrame = pcmASBD.mChannelsPerFrame;
  17. size = sizeof(aacASBD);
  18. AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,&size,&aacASBD);
  19.  
  20. AudioConverterNew(&pcmASBD,&aacASBD,&_converter);
  21. // ...
  22. }

这似乎很简单,只有IT不工作. AVCaptureSession运行后,音频转换器(特别是AudioConverterFillComplexBuffer)返回’hwiu'(硬件使用中)错误.如果会话停止但是我无法捕获任何内容,转换工作正常…

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

>以某种方式使用AVAssetWriterInput将音频样本编码到AAC中,然后以某种方式获取编码的数据包(而不是通过AVAssetWriter,它只会写入文件).
>重新组织我的应用程序,使其仅在视频端使用AVCaptureSession,并在音频端使用Audio Queues.这将使流控制(开始和停止录制,响应中断)变得更加复杂,我担心它可能会导致音频和视频之间的同步问题.而且,它似乎不是一个好的设计.

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

解决方法

我最后向Apple寻求建议(如果你有一个付费的开发者帐户,你可以这样做).

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

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

  1. AudioClassDescription *description = [self
  2. getAudioClassDescriptionWithType:kAudioFormatMPEG4AAC
  3. fromManufacturer:kAppleSoftwareAudioCodecManufacturer];
  4. if (!description) {
  5. return false;
  6. }
  7. // see the question as for setting up pcmASBD and arc ASBD
  8. OSStatus st = AudioConverterNewSpecific(&pcmASBD,1,description,&_converter);
  9. if (st) {
  10. NSLog(@"error creating audio converter: %s",OSSTATUS(st));
  11. return false;
  12. }

  1. - (AudioClassDescription *)getAudioClassDescriptionWithType:(UInt32)type
  2. fromManufacturer:(UInt32)manufacturer
  3. {
  4. static AudioClassDescription desc;
  5.  
  6. UInt32 encoderSpecifier = type;
  7. OSStatus st;
  8.  
  9. UInt32 size;
  10. st = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders,sizeof(encoderSpecifier),&encoderSpecifier,&size);
  11. if (st) {
  12. NSLog(@"error getting audio format propery info: %s",OSSTATUS(st));
  13. return nil;
  14. }
  15.  
  16. unsigned int count = size / sizeof(AudioClassDescription);
  17. AudioClassDescription descriptions[count];
  18. st = AudioFormatGetProperty(kAudioFormatProperty_Encoders,descriptions);
  19. if (st) {
  20. NSLog(@"error getting audio format propery: %s",OSSTATUS(st));
  21. return nil;
  22. }
  23.  
  24. for (unsigned int i = 0; i < count; i++) {
  25. if ((type == descriptions[i].mSubType) &&
  26. (manufacturer == descriptions[i].mManufacturer)) {
  27. memcpy(&desc,&(descriptions[i]),sizeof(desc));
  28. return &desc;
  29. }
  30. }
  31.  
  32. return nil;
  33. }

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

猜你在找的iOS相关文章