Ios 将音频缓冲区[从文件]添加到';直播';音频缓冲区[录制到文件] 我想做的是:

Ios 将音频缓冲区[从文件]添加到';直播';音频缓冲区[录制到文件] 我想做的是:,ios,objective-c,avfoundation,Ios,Objective C,Avfoundation,录制指定持续时间的音频/视频,其中生成的输出文件将添加来自外部音频文件的预定义背景音乐-,而无需在录制后进一步编码/导出 就好像你正在使用iPhone摄像头应用程序录制视频一样,“摄像头滚动”中录制的所有视频都有背景歌曲。录音结束后不导出或加载,也不在单独的音轨中 我是如何实现这一目标的: 通过使用AVCaptureSession,在(CMSampleBufferRef)示例缓冲区通过的委托方法中,我将它们推送到AVAssetWriter以写入文件。由于我不想在输出文件中包含多个音频曲目,因此

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

就好像你正在使用iPhone摄像头应用程序录制视频一样,“摄像头滚动”中录制的所有视频都有背景歌曲。录音结束后不导出或加载,也不在单独的音轨中


我是如何实现这一目标的: 通过使用
AVCaptureSession
,在(
CMSampleBufferRef
)示例缓冲区通过的委托方法中,我将它们推送到AVAssetWriter以写入文件。由于我不想在输出文件中包含多个音频曲目,因此我无法通过单独的
AVAssetWriterInput
传递背景音乐,这意味着我必须在录制时将背景音乐添加到每个样本缓冲区,以避免录制后合并/导出

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

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

一些伪代码(线程除外):

AVCaptureSession
已经在播放摄像头视频和麦克风音频,正在等待
BOOL录制
设置为
YES
。这不完全是我如何做的,而是一个简短的,以某种方式等效的表示。当委托方法收到类型为Audio的
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
中提取
AudioBufferList
AudioBuffer
mData
等,但我不确定如何实际将它们添加到一起-然而-我无法测试不同的方法,因为真正的问题发生在这之前。在魔术发生之前,我拥有两个
CMSampleBufferRef
s,一个从麦克风接收,一个从文件读取,这就是问题所在:

从背景音乐文件接收到的示例缓冲区与我从录制会话接收到的示例缓冲区不同。似乎调用了
[self.backgroundAudioTrackOutput copyNextSampleBuffer]接收大量样本。我意识到这对某些人来说可能是显而易见的,但我以前从未在媒体技术方面达到过这样的水平。现在我明白了,每次从会话中收到sampleBuffer时调用
copyNextSampleBuffer
都是痴心妄想,但我不知道何时/何处放置它

据我所知,录制会话在每个样本缓冲区中提供一个音频样本,而文件读取器在每个样本缓冲区中提供多个样本。我是否可以创建一个计数器来计数每个接收到的记录样本/缓冲区,然后使用第一个文件sampleBuffer提取每个样本,直到当前文件sampleBuffer没有更多的样本“要提供”,然后调用[…copyNext…],并对该缓冲区执行相同的操作

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


注 我甚至不确定这是否可能,但我看不出有什么直接的理由不应该。
还值得一提的是,当我尝试使用视频文件而不是音频文件,并尝试持续拉取视频采样缓冲区时,它们会完美对齐。

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


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

谢谢!这是一个非常好的主意。我一直专注于寻找相反的方法(从许多样本中抽取一个样本,而不是等待一个样本变成多个样本)。然而,这意味着写入不会通过记录连续进行,而是成批进行,因此,如果这不会影响质量或帧速率,这可能是一个可行的解决方案!我非常想举一个例子,甚至使用CoreAudio。这里:有一个与使用CoreAudio创建音频会话相关的宏伟项目。我一直使用它作为创建自定义SES的模型
-(void)writeAudioSamplebuffer:(CMSampleBufferRef)recordedSampleBuffer
{
    CMSampleBufferRef backgroundSampleBuffer = 
                     [backgroundAudioTrackOutput copyNextSampleBuffer];

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

    [assetWriterAudioInput appendSampleBuffer:resultSampleBuffer];
}