0

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) でランダムに失敗するため、デバイスを再接続した後、記録を停止するのに数分しかないことです。

4

1 に答える 1

0

エラーは、作成した CMSampleBuffer が長すぎるためです。

作成された CMSampleBuffer は、ライブ オーディオで満たされた後続のサンプル バッファーと同じ長さ (同じ数のサンプルを含む) である必要があります。必要に応じて、複数のサイレント バッファを作成し、ライブ オーディオ バッファと同じレートで配信できます。

于 2015-12-05T20:47:59.443 に答える