Sto scrivendo un'app per iOS che trasmette video e audio attraverso la rete.Posso usare AVCaptureSession per codificare un flusso AAC in memoria?
Sto usando AVCaptureSession per afferrare fotogrammi video grezzi usando AVCaptureVideoDataOutput e codificarli nel software using x264. Funziona alla grande
Volevo fare lo stesso per l'audio, solo che non ho bisogno di tanto controllo sul lato audio, quindi volevo usare l'encoder hardware integrato per produrre un flusso AAC. Questo significava usare Audio Converter dal livello Audio Toolbox. Per fare così ho messo in un gestore per frame audio AVCaptudeAudioDataOutput s':
- (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...
}
}
In questo caso la funzione di callback per il convertitore audio è piuttosto semplice (assumendo dimensioni dei pacchetti e conta sono installati correttamente):
- (void) putPcmSamplesInBufferList:(AudioBufferList *)bufferList withCount:(UInt32 *)count
{
bufferList->mBuffers[0].mData = _pcmBuffer;
bufferList->mBuffers[0].mDataByteSize = _pcmBufferSize;
}
E la configurazione del convertitore audio si presenta così:
{
// ...
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);
// ...
}
questo sembra abbastanza dritto inoltra solo il NON FUNZIONA. Una volta che AVCaptureSession è in esecuzione, il convertitore audio (in particolare AudioConverterFillComplexBuffer) restituisce un errore "hwiu" (hardware in uso). La conversione funziona correttamente se la sessione viene interrotta ma non riesco a catturare nulla ...
Mi chiedevo se esistesse un modo per ottenere un flusso AAC da AVCaptureSession. Le opzioni che sto considerando sono:
In qualche modo usando AVAssetWriterInput per codificare i campioni audio in AAC e quindi ottenere i pacchetti codificati in qualche modo (non attraverso AVAssetWriter, che solo scrivere in un file).
Riorganizzare la mia app in modo che utilizzi AVCaptureSession solo sul lato video ed utilizza Audio Queues sul lato audio. Questo renderà il controllo di flusso (avvio e l'arresto della registrazione, rispondendo alle interruzioni) più complicato e ho paura che potrebbe causare problemi synching tra l'audio e il video. Inoltre, non sembra un buon design.
Qualcuno sa se è possibile ottenere AAC da AVCaptureSession? Devo usare le code audio qui? Questo potrebbe portarmi a problemi di sincronizzazione o di controllo?
Sei sicuro che il tuo AudioConverter funzioni? Hai provato a disattivare l'acquisizione e codificare alcuni zeri, ad esempio? –
Sì, l'ho fatto (penso di averlo menzionato anche nella domanda). L'encoder funziona correttamente se AVCaptureSession non è in stato "in esecuzione". – Avner
oops, mi dispiace. sembra che tu sia in un vicolo cieco. l'aggiunta di un ingresso audio alla sessione di acquisizione sembra legare il codificatore AAC. –