【问题标题】:Adding audio buffer [from file] to 'live' audio buffer [recording to file]将音频缓冲区 [从文件] 添加到“实时”音频缓冲区 [录制到文件]
【发布时间】:2014-11-14 14:02:44
【问题描述】:

我想要做什么:

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

就像您使用 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: 的方法现在并没有做太多。 我知道如何从 CMSampleBufferRef 中提取 AudioBufferListAudioBuffermData 等,但我不确定如何将它们实际加在一起 ​​- 然而 strong> - 我无法测试不同的方法来做到这一点,因为真正的问题发生在此之前。在 Magic 发生之前,我拥有两个 CMSampleBufferRefs,一个从麦克风接收,一个从文件读取,这就是问题所在:

从背景音乐文件接收到的样本缓冲区与我从录制会话接收到的不同。似乎对[self.backgroundAudioTrackOutput copyNextSampleBuffer]; 的调用接收了大量样本。我意识到这对某些人来说可能显而易见,但我以前从未接触过这种媒体技术水平。我现在看到,每次我从会话中收到一个 sampleBuffer 时调用 copyNextSampleBuffer 是一厢情愿的想法,但我不知道何时/何处放置它。

据我所知,录制会话在每个样本缓冲区中提供 一个 音频样本,而文件阅读器在每个样本中提供 多个 样本-缓冲。我可以以某种方式创建一个 counter 来计算每个接收到的记录样本/缓冲区,然后使用第一个 file-sampleBuffer 来提取每个样本,直到当前 file-sampleBuffer 没有更多样本“要提供”,然后调用[..copyNext..],对那个缓冲区做同样的事情?

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


注意

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

【问题讨论】:

    标签: ios objective-c avfoundation


    【解决方案1】:

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

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

    【讨论】:

    • 谢谢!这是一个很好的主意。我一直非常专注于尝试找到相反的方法(从许多样本中获取一个样本,而不是等待一个成为多个样本)。然而,这意味着写入不会通过记录连续发生,而是分批发生,所以如果这不会影响质量或帧速率,它可能是一个可能的解决方案!我非常想要一个例子,即使使用 CoreAudio。
    • 这里:zerokidz.com/audiograph/Download.html 有一个与使用 CoreAudio 创建音频会话相关的宏伟项目。我一直将它用作创建 iOS 自定义会话的模型。
    • 那么你必须关注MixerHostAudio.m中的readAudioFilesIntoMemory方法。 soundStructArray[audioFile].audioDataLeft 存储完整音频文件的样本。我建议您将它们复制到新的缓冲区中。然后,如果您查看MixerHostAudio.m 中的micLineInCallback,您会发现处理输入样本的回调。您会在sampleBufferLeft 中按帧找到输入样本。然后,如果您只在文件缓冲区上按顺序(关于正确的时间戳)重叠这些样本,您将实现您的目标。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    相关资源
    最近更新 更多