Я записываю видео / аудио с помощью 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).