将音频缓冲区[从文件]添加到' live'音频缓冲[录制到文件]

时间:2014-09-19 22:04:17

标签: ios objective-c avfoundation

我想做的事情:

录制到指定的音频/视频持续时间,其中生成的输出文件将添加来自外部音频文件的预定义背景音乐 - 录制后无需进一步编码/导出。< / p>

好像您正在使用iPhone相机应用程序录制视频,以及“相机胶卷”中的所有录制视频。有背景歌曲。结束录制后无法导出或加载,而不是单独的AudioTrack。


我是如何努力实现这一目标的:

通过使用AVCaptureSession,在传递(CMSampleBufferRef)样本缓冲区的委托方法中,我将它们推送到AVAssetWriter以写入文件。由于我不想在输出文件中输入多个音轨,因此无法通过单独的AVAssetWriterInput传递背景音乐,这意味着我必须将背景音乐添加到每个样本缓冲区来自录制录制以避免录制后合并/导出。

背景音乐是​​一个特定的,预定义的音频文件(格式/编解码器:m4a aac),不需要时间编辑,只需在下面添加整个录音,从开始到结束。录音永远不会比背景音乐文件长。

在开始写入文件之前,我还准备了一个AVAssetReader,读取指定的音频文件。

某些伪代码(排除线程):

-(void)startRecording
{
    /*
        Initialize writer and reader here: [...]
    */

    backgroundAudioTrackOutput = [AVAssetReaderTrackOutput 
                            assetReaderTrackOutputWithTrack:
                                backgroundAudioTrack 
                            outputSettings:nil];

    if([backgroundAudioReader canAddOutput:backgroundAudioTrackOutput])
        [backgroundAudioReader addOutput:backgroundAudioTrackOutput];
    else
        NSLog(@"This doesn't happen");

    [backgroundAudioReader startReading];

    /* Some more code */

    recording = YES;
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
             didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
             fromConnection:(AVCaptureConnection *)connection
{
    if(!recording)
        return;

    if(videoConnection)
        [self writeVideoSampleBuffer:sampleBuffer];
    else if(audioConnection)
        [self writeAudioSampleBuffer:sampleBuffer];
}

AVCaptureSession已经播放了相机视频和麦克风音频,只是等待BOOL recording设置为YES。这并不是我如何做到这一点,而是一个短暂的,某种程度上等同的表现形式。当委托方法收到CMSampleBufferRef类型的音频时,我调用自己的方法writeAudioSamplebuffer:sampleBuffer。如果要做到这一点,没有我试图做的背景音轨,我只需要输入这样的内容:[assetWriterAudioInput appendSampleBuffer:sampleBuffer];而不是调用我的方法。在我的情况下,我需要在写入之前重叠两个缓冲区:

-(void)writeAudioSamplebuffer:(CMSampleBufferRef)recordedSampleBuffer
{
    CMSampleBufferRef backgroundSampleBuffer = 
                     [backgroundAudioTrackOutput copyNextSampleBuffer];

    /* DO MAGIC HERE  */
    CMSampleBufferRef resultSampleBuffer = 
                         [self overlapBuffer:recordedSampleBuffer 
                            withBackgroundBuffer:backgroundSampleBuffer];
    /* END MAGIC HERE */

    [assetWriterAudioInput appendSampleBuffer:resultSampleBuffer];
}

问题:

我必须将增量样本缓冲区从本地文件添加到进入的实时缓冲区。我创建的名为overlapBuffer:withBackgroundBuffer:的方法现在并没有做很多事情。 我知道如何从AudioBufferList中提取AudioBuffermDataCMSampleBufferRef等,但我不确定如何实际将它们加在一起 ​​- 然而 - 我还没有能够测试不同的方法来做到这一点,因为真正的问题发生在此之前。在 Magic 发生之前,我拥有两个CMSampleBufferRef s,一个从麦克风接收,一个从文件中读取,这就是问题所在:

从background-music-file收到的样本缓冲区与我从录制会话中收到的样本缓冲区不同。似乎对[self.backgroundAudioTrackOutput copyNextSampleBuffer];的调用收到了大量的样本。我意识到这对某些人来说可能是显而易见的,但我从来没有达到这种媒体技术水平。我现在看到,每次从会话中收到sampleBuffer时都会调用copyNextSampleBuffer这是一厢情愿的想法,但我不知道何时/何时放置它。

据我所知,录音会话在每个样本缓冲区中提供一个音频样本,而文件阅读器在每个样本中提供多个样本-缓冲。我可以以某种方式创建一个计数器来计算每个接收到的记录样本/缓冲区,然后使用第一个file-sampleBuffer提取每个样本,直到当前file-sampleBuffer没有更多样本&#39;到给&#39;,然后调用[..copyNext ..],并对该缓冲区执行相同的操作?

由于我完全控制了录音和文件的编解码器,格式等,我希望这样的解决方案不会破坏& #39;对齐&#39; /音频同步。鉴于两个样本都具有相同的sampleRate,这仍然是个问题吗?


注意

我甚至不确定这是否可行,但我认为没有直接的理由不应该这样做。 另外值得一提的是,当我尝试使用视频文件而不是音频文件,并尝试不断拉动视频样本缓冲区时,它们完美对齐。

1 个答案:

答案 0 :(得分:4)

我对AVCaptureOutput并不熟悉,因为我的所有声音/音乐会话都是使用AudioToolbox而不是AVFoundation构建的。但是,我猜你应该能够设置录制捕获缓冲区的大小。如果没有,并且您仍然只获得一个样本,我建议您将从捕获输出获得的每个单独数据存储在辅助缓冲区中。当辅助缓冲区达到与文件读取缓冲区相同的大小时,请调用[self overlapBuffer:auxiliarSampleBuffer withBackgroundBuffer:backgroundSampleBuffer];

我希望这会对你有所帮助。如果没有,我可以提供有关如何使用CoreAudio执行此操作的示例。使用CoreAudio我已经能够从麦克风捕获和文件读取中获得1024个LCPM样本缓冲区。所以重叠是立即的。