我正在编写一个iOS应用程序,通过网络传输视频和音频.
我使用AVCaptureSession用抢原始视频帧AVCaptureVideoDataOutput然后对其编码,在软件使用X264.这非常有效.
我想对音频做同样的事情,只是我不需要在音频方面那么多控制,所以我想使用内置的硬件编码器来产生AAC流.这意味着从Audio Toolbox层使用Audio Converter.为了做到这一点,我为AVCaptudeAudioDataOutput的音频帧添加了一个处理程序:
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
// get the audio samples into a common buffer _pcmBuffer
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &_pcmBufferSize, &_pcmBuffer);
// use AudioConverter to
UInt32 ouputPacketsCount = 1;
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = 1;
bufferList.mBuffers[0].mDataByteSize = sizeof(_aacBuffer);
bufferList.mBuffers[0].mData = _aacBuffer;
OSStatus st = AudioConverterFillComplexBuffer(_converter, converter_callback, (__bridge void *) self, &ouputPacketsCount, &bufferList, NULL);
if (0 == st) { …Run Code Online (Sandbox Code Playgroud) 这已经困扰了我一段时间。我有视频转换器将视频转换为“.mp4”格式。但是在某些视频上发生了崩溃,但不是全部。
这是崩溃日志
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVAssetWriterInput appendSampleBuffer:]
Cannot append sample buffer: First input buffer must have an appropriate kCMSampleBufferAttachmentKey_TrimDurationAtStart since the codec has encoder delay'
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
NSURL *uploadURL = [NSURL fileURLWithPath:[[NSTemporaryDirectory() stringByAppendingPathComponent:[self getVideoName]] stringByAppendingString:@".mp4"]];
AVAssetTrack *videoTrack = [[self.avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CGSize videoSize = videoTrack.naturalSize;
NSDictionary *videoWriterCompressionSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1250000], AVVideoAverageBitRateKey, nil];
NSDictionary *videoWriterSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey, videoWriterCompressionSettings, AVVideoCompressionPropertiesKey, [NSNumber numberWithFloat:videoSize.width], AVVideoWidthKey, [NSNumber numberWithFloat:videoSize.height], AVVideoHeightKey, nil];
AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoWriterSettings]; …Run Code Online (Sandbox Code Playgroud) 我正在从 iOS 上的 Unity 应用程序生成视频。我正在使用 iVidCap,它使用 AVFoundation 来执行此操作。那一侧一切正常。本质上,视频是通过使用纹理渲染目标并将帧传递给 Obj-C 插件来渲染的。
现在我需要向视频添加音频。音频将是在特定时间发生的声音效果,也可能是一些背景声音。所使用的文件实际上是 Unity 应用程序内部的资产。我可以将它们写入手机存储,然后生成 AVComposition,但我的计划是避免这种情况并将音频合成在浮点格式缓冲区中(从音频剪辑获取音频采用浮点格式)。稍后我可能会做一些动态音频效果。
几个小时后,我设法录制音频并与视频一起播放......但它很卡顿。
目前,我只是在视频的每帧持续时间内生成一个方波并将其写入 AVAssetWriterInput。稍后,我将生成我真正想要的音频。
如果我生成大量样本,我就不会出现卡顿的情况。如果我把它写成块(我更喜欢分配一个巨大的数组),那么音频块似乎会互相剪辑:

我似乎无法弄清楚这是为什么。我很确定我得到的音频缓冲区的时间戳是正确的,但也许我整个部分都做错了。或者我是否需要一些标志来使视频与音频同步?我看不出这是问题所在,因为将音频数据提取到 wav 后,我可以在波形编辑器中看到问题。
编写音频的相关代码:
- (id)init {
self = [super init];
if (self) {
// [snip]
rateDenominator = 44100;
rateMultiplier = rateDenominator / frameRate;
sample_position_ = 0;
audio_fmt_desc_ = nil;
int nchannels = 2;
AudioStreamBasicDescription audioFormat;
bzero(&audioFormat, sizeof(audioFormat));
audioFormat.mSampleRate = 44100;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = nchannels;
int bytes_per_sample = sizeof(float);
audioFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsAlignedHigh;
audioFormat.mBitsPerChannel = bytes_per_sample …Run Code Online (Sandbox Code Playgroud) 我可以找到的所有示例代码都AudioConverterRef集中在我预先拥有所有数据的用例(例如在磁盘上转换文件).它们通常调用AudioConverterFillComplexBufferPCM进行转换,然后将其inInputDataProcUserData填入回调中.(这真的是它应该如何使用?为什么它需要回调呢?)对于我的用例,我试图从麦克风流式传输aac音频,所以我没有文件,我的PCM缓冲区正在实时填写.
由于我没有*ioNumberDataPackets = 0预先拥有所有数据,所以我在输入数据输出后尝试进行回调,但这只是将AudioConverter置于需要进行AudioConverterReset()ted 的死亡状态,而我不会从中获取任何数据.
我在网上看到的一种方法是,如果我存储的数据太小,就会从回调中返回错误,只要我有更多数据就再试一次,但这似乎是浪费资源,我不能让自己尝试一下.
我真的需要做"重试,直到我的输入缓冲区足够大",还是有更好的方法?