まず、AVCaptureSession を使用して、camero と micophone から vedio とオーディオをキャプチャします。次に、以下のメソッド コードをデリゲートします。
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
// if is Vedio data ,append to vedioInputWriter
if (mediaType == kCMMediaType_Vedio){
// ...
// ...
// ...
// write the video data
if (_assetWriterVideoInput.readyForMoreMediaData){
[_assetWriterInputPixelBufferAdaptor appendPixelBuffer:renderedOutputPixelBuffer withPresentationTime:timestamp];
}
return;
}
size_t bufferListSizeNeededOut;
CMBlockBufferRef blockBufferOut = nil;
// get AudioBufferList
err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer,
&bufferListSizeNeededOut,
currentInputAudioBufferList,
CAAudioBufferList::CalculateByteSize(currentInputASBD.mChannelsPerFrame),
kCFAllocatorSystemDefault,
kCFAllocatorSystemDefault,
kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
&blockBufferOut);
// mix recorded audio with background music
[self mixAudioBufferListwithBackgroundMusic:currentInputAudioBufferList];
if (!self.audioInputAssetWriter.readyForMoreMediaData) {
if (self.assetWriter.status == AVAssetWriterStatusFailed) {
NSLog(@"assetWrite error=%@",self.viewController.assetWriter.error);
}
return;
}
// tranfer `AudioBufferList` to `CMSampleBuffer`
CMSampleBuffer newSampleBuffer = [self processAudioData:outputBufferList->ABL() framesNumber:numberOfFrames format:&mClientFormat];
// append samplebuffer to assetInputWriter
if ([self.audioInputAssetWriter appendSampleBuffer:newSampleBuffer]) {
NSLog(@" append sample buffer success");
}else{
NSLog(@"append sample buffer failed");
}
}
以下のコードに転送AudioBufferList
します。CMSampleBuffer
- (CMSampleBufferRef)processAudioData:(AudioBufferList *)audioData framesNumber:(UInt32 )num format:(AudioStreamBasicDescription *)asbd
{
CMSampleBufferRef sbuf;
OSStatus status;
// 1.audio foramt description
CMAudioFormatDescriptionRef format;
status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault,&(bufferToSampleFormat), 0, NULL, 0, NULL, NULL, &format);
// 2.sample timing info
CMSampleTimingInfo timing;
timing.duration = CMTimeMake(1,44100);
timing.presentationTimeStamp = kCMTimeZero;
timing.decodeTimeStamp = kCMTimeInvalid;
size_t sampleSizeArray[1] = {4};
// 3.create sample buffer
status = CMSampleBufferCreate(kCFAllocatorDefault,NULL,false, NULL,NULL,format,(CMItemCount)num,1,&timing,0,NULL, &sbuf);
// 4.sample buffer set data buffer from audio buffer list
status = CMSampleBufferSetDataBufferFromAudioBufferList(sbuf, kCFAllocatorDefault, kCFAllocatorDefault, 0, audioData);
if (status != noErr) {
NSLog(@"sample buffer set data buffer from audio buffer list failed -- %d",(int)status);
return nil;
}
return sbuf;
}
最後に、ビデオとオーディオ データをtest.mov
ファイルとして保存します。VLC でファイルを再生し、音を出します。また、ffmpeg で aac 形式のオーディオ ファイルを剥がすことができます。
AudioBufferList
問題は への転送だと思いCMSampleBuffer
ます。いくつかの情報が欠落しているため、Quicktime が正しく再生できません。