Запись тихого CMSampleBuffer вызывает сбой: CrashIfClientProvidedBogusAudioBufferList

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


person Legi    schedule 04.12.2015    source источник
comment
Вы сделали это? @Legi спасибо   -  person Pablo Martinez    schedule 22.02.2016


Ответы (1)


Ошибка в том, что созданный вами CMSampleBuffer слишком длинный.

Созданный CMSampleBuffer должен иметь такую ​​же длину (содержать такое же количество выборок), что и буферы исходных выборок, которые заполнены живым звуком. При необходимости вы можете создать несколько буферов молчания и доставлять их с той же скоростью, что и буферы живого звука.

person hotpaw2    schedule 05.12.2015
comment
Спасибо за Ваш ответ. Чтобы проверить это, я создал новую переменную с именем lastAudioNumSamples для хранения этой информации из последнего записанного сэмплбуфера и установил numSamples = lastAudioNumSamples в моем примере. С этим изменением будет случайным, независимо от того, вылетает ли он каждый раз, когда я повторно подключаю аудиоустройство во время записи. Такое ощущение, что становится лучше. Я отредактировал свой вопрос, чтобы добавить немного больше информации о моих предыдущих попытках. - person Legi; 06.12.2015