AVAssetwriter を使用してビデオ/オーディオを録音しており、サイレント サンプル バッファーを書き込めるようにしたいと考えています。私は CoreAudio の経験があまりないので、実用的な解決策を思いつくのに苦労しています。
アイデアは、オーディオ デバイスが切断されても、再接続されるまでビデオを録画し続けることです。問題は、AVFoundation がどういうわけかオーディオを前面に押し出すため、結果のムービー ファイルが大幅に同期されないことです。
私の現在の実装では、オーディオ デバイスが接続されていないセグメントの間に配置するために、空の/サイレント CMSampleBuffer を作成しようとしています。
if (audioOutput == captureOutput && audioWriterInput.readyForMoreMediaData) {
if (needToFillAudioGap) {
CMTime temp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
CMItemCount numSamples = temp.value - lastAudioDisconnect.value;
OSStatus status;
CMBlockBufferRef bbuf = NULL;
CMSampleBufferRef sbuf = NULL;
int nchans = 2;
size_t buflen = numSamples * nchans * sizeof(float);
NSMutableData* data = [NSMutableData dataWithLength:buflen];
void* samples = [data mutableBytes];
status = CMBlockBufferCreateWithMemoryBlock(
kCFAllocatorDefault,
samples,
buflen,
kCFAllocatorNull,
NULL,
0,
buflen,
0,
&bbuf);
if (status != noErr) {
NSLog(@"CMBlockBufferCreateWithMemoryBlock error: %d", (int)status);
return;
}
CMBlockBufferRef blockBufferContiguous;
status = CMBlockBufferCreateContiguous(kCFAllocatorDefault,
bbuf,
kCFAllocatorNull,
NULL,
0,
buflen,
0,
&blockBufferContiguous);
CFRelease(bbuf);
if(status != noErr)
{
printf("CMBlockBufferCreateContiguous failed with error %d\n", (int)status);
return;
}
status = CMAudioSampleBufferCreateReadyWithPacketDescriptions(kCFAllocatorDefault, blockBufferContiguous, CMSampleBufferGetFormatDescription(sampleBuffer), numSamples, lastAudioDisconnect, NULL, &sbuf);
CFRelease(blockBufferContiguous);
if (status != noErr) {
NSLog(@"CMSampleBufferCreate error: %d", (int)status);
return;
}
BOOL r = [audioWriterInput appendSampleBuffer:sbuf];
if (!r) {
NSLog(@"appendSampleBuffer error: %d", (int)status);
return;
}
CFRelease(sbuf);
NSLog(@"Filling Audio Gap");
needToFillAudioGap = false;
} else {
if ([audioWriterInput appendSampleBuffer:sampleBuffer])
lastAudioDisconnect = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
}
}
上部の sampleBuffer は、オーディオ デバイスが再接続された後の最初のサンプル バッファーです。これにより、埋めなければならないギャップの長さに関する情報が得られます。LastAudioDisconnect は、最後に書き込まれたオーディオ サンプル バッファからのプレゼンテーション タイムスタンプを常に保持します。
Guard Malloc を有効にすると、プログラムが次のようにクラッシュします: CrashIfClientProvidedBogusAudioBufferList
編集: Guard Malloc を無効にすると、録音中にオーディオ デバイスを複数回再接続できます。録音を停止すると、問題なくギャップが生じます。
問題は、AVAssetWriter がエラー コード 11800 (AVErrorUnknown) でランダムに失敗するため、デバイスを再接続した後、記録を停止するのに数分しかないことです。