captureOutput使用dispatch_async处理sampleBuffer报EXC_BAD_ACCESS如何解决
问题根本原因
- CMSampleBuffer属于Core Foundation类型对象,
AVCaptureOutput的captureOutput:didOutputSampleBuffer:fromConnection:代理方法执行结束后,系统会自动回收传入的sampleBuffer - 直接用
dispatch_async捕获sampleBuffer时,ARC不会自动管理Core Foundation对象的引用计数,也不会自动延长它的生命周期,等异步队列执行block的时候,sampleBuffer已经被释放,访问就触发野指针类的EXC_BAD_ACCESS错误
修复方案
核心逻辑
手动管理sampleBuffer的引用计数,在传入异步block前增加引用计数,使用完成后释放,既可以保证异步访问时buffer有效,也不会出现内存泄漏。
修改后可运行代码
queue1 = dispatch_queue_create("testqueue", DISPATCH_QUEUE_SERIAL); ... -(void) captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection{ // 手动持有sampleBuffer,延长生命周期 CFRetain(sampleBuffer); dispatch_async(queue1, ^{ if(captureOutput == videoOutput){ // 原有像素buffer处理逻辑保持不变 if([writerVideoInput isReadyForMoreMediaData] && recordingAssetWriter.status == AVAssetWriterStatusWriting) { [adaptor appendPixelBuffer:pxBuffer withPresentationTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; } } else if(captureOutput == audioOutput){ if([assetWriterAudioInput isReadyForMoreMediaData] && recordingAssetWriter.status == AVAssetWriterStatusWriting) { [assetWriterAudioInput appendSampleBuffer:sampleBuffer]; } } // 使用完成后手动释放,避免内存泄漏 CFRelease(sampleBuffer); }); }
老旧设备额外优化建议
- 把硬编码的
recordingAssetWriter.status == 1替换为系统枚举AVAssetWriterStatusWriting,避免枚举值变动带来的潜在问题 - 若图像处理逻辑耗时过高,可改用vImage、Metal这类高性能框架做渲染,进一步降低CPU负载
- 当输入源处于不可写入状态时,主动丢弃当前buffer,避免队列堆积过多未处理数据导致内存暴涨
- 可适当降低录制分辨率、帧率,匹配老旧设备的性能上限
内容的提问来源于stack exchange,提问作者reapf
相关产品推荐
相关产品推荐

