我正在尝试创建CMSampleBuffer的副本,captureOutput在AVCaptureAudioDataOutputSampleBufferDelegate中返回该副本。
我遇到的问题是,我的框架来自委托方法captureOutput:didOutputSampleBuffer:fromConnection:,在CFArray中保留了很长一段时间之后,它们被删除了。
显然,我需要为进一步的处理创建传入缓冲区的深度副本。我也知道CMSampleBufferCreateCopy只创建浅拷贝。
因此,很少有人提出相关的问题:
但是它们都没有帮助我正确地使用包含12个参数的CMSampleBufferCreate函数:
CMSampleBufferRef copyBuffer;
CMBlockBufferRef data = CMSampleBufferGetDataBuffer(sampleBuffer);
CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
CMItemCount itemCount = CMSampleBufferGetNumSamples(sampleBuffer);
CMTime duration = CMSampleBufferGetDuration(sampleBuffer);
CMTime presentationStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
CMSampleTimingInfo timingInfo;
timingInfo.duration = duration;
timingInfo.presentationTimeStamp = presentationStamp;
timingInfo.decodeTimeStamp = CMSampleBufferGetDecodeTimeStamp(sampleBuffer);
size_t sampleSize = CMBlockBufferGetDataLength(data);
CMBlockBufferRef sampleData;
if (CMBlockBufferCopyDataBytes(data, 0, sampleSize, &sampleData) != kCMBlockBufferNoErr) {
VLog(@"error during copying sample buffer");
}
// Here I tried data and sampleData CMBlockBuffer instance, but no success
OSStatus status = CMSampleBufferCreate(kCFAllocatorDefault, data, isDataReady, nil, nil, formatDescription, itemCount, 1, &timingInfo, 1, &sampleSize, ©Buffer);
if (!self.sampleBufferArray) {
self.sampleBufferArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
//EXC_BAD_ACCESS crash when trying to add sampleBuffer to the array
CFArrayAppendValue(self.sampleBufferArray, copyBuffer);
} else {
CFArrayAppendValue(self.sampleBufferArray, copyBuffer);
}你如何深入复制音频CMSampleBuffer?在你的答案中可以随意使用任何语言(迅速/客观-c)。
发布于 2017-10-31 11:05:54
下面是我最后实现的一个工作解决方案。我将此片段发送给Apple Developer技术支持部门,并要求他们检查它是否是复制传入示例缓冲区的正确方法。基本思想是复制AudioBufferList,然后创建一个CMSampleBuffer并将AudioBufferList设置为此示例。
AudioBufferList audioBufferList;
CMBlockBufferRef blockBuffer;
//Create an AudioBufferList containing the data from the CMSampleBuffer,
//and a CMBlockBuffer which references the data in that AudioBufferList.
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);
NSUInteger size = sizeof(audioBufferList);
char buffer[size];
memcpy(buffer, &audioBufferList, size);
//This is the Audio data.
NSData *bufferData = [NSData dataWithBytes:buffer length:size];
const void *copyBufferData = [bufferData bytes];
copyBufferData = (char *)copyBufferData;
CMSampleBufferRef copyBuffer = NULL;
OSStatus status = -1;
/* Format Description */
AudioStreamBasicDescription audioFormat = *CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef) CMSampleBufferGetFormatDescription(sampleBuffer));
CMFormatDescriptionRef format = NULL;
status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &audioFormat, 0, nil, 0, nil, nil, &format);
CMFormatDescriptionRef formatdes = NULL;
status = CMFormatDescriptionCreate(NULL, kCMMediaType_Audio, 'lpcm', NULL, &formatdes);
if (status != noErr)
{
NSLog(@"Error in CMAudioFormatDescriptionCreator");
CFRelease(blockBuffer);
return;
}
/* Create sample Buffer */
CMItemCount framesCount = CMSampleBufferGetNumSamples(sampleBuffer);
CMSampleTimingInfo timing = {.duration= CMTimeMake(1, 44100), .presentationTimeStamp= CMSampleBufferGetPresentationTimeStamp(sampleBuffer), .decodeTimeStamp= CMSampleBufferGetDecodeTimeStamp(sampleBuffer)};
status = CMSampleBufferCreate(kCFAllocatorDefault, nil , NO,nil,nil,format, framesCount, 1, &timing, 0, nil, ©Buffer);
if( status != noErr) {
NSLog(@"Error in CMSampleBufferCreate");
CFRelease(blockBuffer);
return;
}
/* Copy BufferList to Sample Buffer */
AudioBufferList receivedAudioBufferList;
memcpy(&receivedAudioBufferList, copyBufferData, sizeof(receivedAudioBufferList));
//Creates a CMBlockBuffer containing a copy of the data from the
//AudioBufferList.
status = CMSampleBufferSetDataBufferFromAudioBufferList(copyBuffer, kCFAllocatorDefault , kCFAllocatorDefault, 0, &receivedAudioBufferList);
if (status != noErr) {
NSLog(@"Error in CMSampleBufferSetDataBufferFromAudioBufferList");
CFRelease(blockBuffer);
return;
}代码级支持答案:
这段代码看起来没问题(尽管您希望添加一些额外的错误检查)。我已经在一个应用程序中成功地测试了它,该应用程序实现了AVCaptureAudioDataOutput委托
captureOutput:didOutputSampleBuffer:fromConnection:方法来捕获和记录音频。使用此深拷贝代码时捕获的音频与直接使用所提供的示例缓冲区(没有深层副本)时得到的音频似乎是相同的。 Apple Developer技术支持
发布于 2021-10-22 19:24:05
在斯威夫特做这件事找不到合适的答案。这里有一个分机:
extension CMSampleBuffer {
func deepCopy() -> CMSampleBuffer? {
guard let formatDesc = CMSampleBufferGetFormatDescription(self),
let data = self.data else {
return nil
}
let nFrames = CMSampleBufferGetNumSamples(self)
let pts = CMSampleBufferGetPresentationTimeStamp(self)
let dataBuffer = data.withUnsafeBytes { (buffer) -> CMBlockBuffer? in
var blockBuffer: CMBlockBuffer?
let length: Int = data.count
guard CMBlockBufferCreateWithMemoryBlock(
allocator: kCFAllocatorDefault,
memoryBlock: nil,
blockLength: length,
blockAllocator: nil,
customBlockSource: nil,
offsetToData: 0,
dataLength: length,
flags: 0,
blockBufferOut: &blockBuffer) == noErr else {
print("Failed to create block")
return nil
}
guard CMBlockBufferReplaceDataBytes(
with: buffer.baseAddress!,
blockBuffer: blockBuffer!,
offsetIntoDestination: 0,
dataLength: length) == noErr else {
print("Failed to move bytes for block")
return nil
}
return blockBuffer
}
guard let dataBuffer = dataBuffer else {
return nil
}
var newSampleBuffer: CMSampleBuffer?
CMAudioSampleBufferCreateReadyWithPacketDescriptions(
allocator: kCFAllocatorDefault,
dataBuffer: dataBuffer,
formatDescription: formatDesc,
sampleCount: nFrames,
presentationTimeStamp: pts,
packetDescriptions: nil,
sampleBufferOut: &newSampleBuffer
)
return newSampleBuffer
}
}发布于 2022-07-23 11:59:21
LLooggaann的解决方案更简单,工作也很好,但是,如果有人感兴趣,我将最初的解决方案迁移到Swift 5.6:
extension CMSampleBuffer {
func deepCopy() -> CMSampleBuffer? {
var audioBufferList : AudioBufferList = AudioBufferList()
var blockBuffer : CMBlockBuffer?
let sizeOfAudioBufferList = MemoryLayout<AudioBufferList>.size
//Create an AudioBufferList containing the data from the CMSampleBuffer.
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(self,
bufferListSizeNeededOut: nil,
bufferListOut: &audioBufferList,
bufferListSize: sizeOfAudioBufferList,
blockBufferAllocator: nil,
blockBufferMemoryAllocator: nil,
flags: 0,
blockBufferOut: &blockBuffer)
guard audioBufferList.mNumberBuffers == 1 else { return nil } //TODO: Make this generic for any number of buffers
/* Deep copy the audio buffer */
let audioBufferDataSize = Int(audioBufferList.mBuffers.mDataByteSize)
let audioBuffer = audioBufferList.mBuffers
let audioBufferDataCopyPointer = UnsafeMutableRawPointer.allocate(byteCount: audioBufferDataSize, alignment: 1)
defer {
audioBufferDataCopyPointer.deallocate()
}
memcpy(audioBufferDataCopyPointer, audioBufferList.mBuffers.mData, audioBufferDataSize)
let copiedAudioBuffer = AudioBuffer(mNumberChannels: audioBuffer.mNumberChannels,
mDataByteSize: audioBufferList.mBuffers.mDataByteSize,
mData: audioBufferDataCopyPointer)
/* Create a new audio buffer list with the deep copied audio buffer */
var copiedAudioBufferList = AudioBufferList(mNumberBuffers: 1, mBuffers: copiedAudioBuffer)
/* Copy audio format description, to be used in the new sample buffer */
guard let sampleBufferFormatDescription = CMSampleBufferGetFormatDescription(self) else { return nil }
/* Create copy of timing for new sample buffer */
var duration = CMSampleBufferGetDuration(self)
duration.value /= Int64(numSamples)
var timing = CMSampleTimingInfo(duration: duration,
presentationTimeStamp: CMSampleBufferGetPresentationTimeStamp(self),
decodeTimeStamp: CMSampleBufferGetDecodeTimeStamp(self))
/* New sample buffer preparation, using the audio format description, and the timing information. */
let sampleCount = CMSampleBufferGetNumSamples(self)
var newSampleBuffer : CMSampleBuffer?
guard CMSampleBufferCreate(allocator: kCFAllocatorDefault,
dataBuffer: nil,
dataReady: false,
makeDataReadyCallback: nil,
refcon: nil,
formatDescription: sampleBufferFormatDescription,
sampleCount: sampleCount,
sampleTimingEntryCount: 1,
sampleTimingArray: &timing,
sampleSizeEntryCount: 0,
sampleSizeArray: nil,
sampleBufferOut: &newSampleBuffer) == noErr else { return nil }
//Create a CMBlockBuffer containing a copy of the data from the AudioBufferList, add to new sample buffer.
let status = CMSampleBufferSetDataBufferFromAudioBufferList(newSampleBuffer!,
blockBufferAllocator: kCFAllocatorDefault,
blockBufferMemoryAllocator: kCFAllocatorDefault,
flags: 0,
bufferList: &copiedAudioBufferList)
guard status == noErr else { return nil }
return newSampleBuffer
}
}https://stackoverflow.com/questions/46908485
复制相似问题