Objective c [AVAssetWriterInput RequestMediaDataWhenRepayonQueue:usingBlock:]内存问题
我正在编写一个库,使用AVFoundation将资产导出到文件中。我创建了一个读写器,将输入和输出连接到它们,然后在输入上调用Objective c [AVAssetWriterInput RequestMediaDataWhenRepayonQueue:usingBlock:]内存问题,objective-c,ios,memory-management,avfoundation,Objective C,Ios,Memory Management,Avfoundation,我正在编写一个库,使用AVFoundation将资产导出到文件中。我创建了一个读写器,将输入和输出连接到它们,然后在输入上调用requestMediaDataWhenRepayonQueue方法来开始提取数据。提供给此方法的块回调看起来有点像: [input requestMediaDataWhenReadyOnQueue:queue usingBlock:^{ while ([input isReadyForMoreMediaData]) { CMSampleBuffe
requestMediaDataWhenRepayonQueue
方法来开始提取数据。提供给此方法的块回调看起来有点像:
[input requestMediaDataWhenReadyOnQueue:queue usingBlock:^{
while ([input isReadyForMoreMediaData]) {
CMSampleBufferRef buffer;
// The track has some more data for us
if ([reader status] == AVAssetReaderStatusReading
&& (buffer = [output copyNextSampleBuffer])) {
BOOL result = [input appendSampleBuffer:buffer];
CFRelease(buffer);
if (!result) {
// handle error
break;
}
// The track is finished, for whatever reason
} else {
[input markAsFinished]; ⬅
switch ([reader status]) {
// inspect the status and act accordingly
}
}
}
}];
这在iOS 5上非常有效,但在iOS 4上,代码在标记为⬅ 箭。经过一些拨弄后,我觉得在将输入标记为完成后,该块立即以某种方式被破坏了。执行错误行之前完全有效的self
指针不知何故会变成0xfff…
或调试器报告的一些垃圾值。但是之前指向它的对象是好的,正如僵尸工具所确认的,它不会被释放
我遗漏了什么?看到了相同(类似)的问题。iOS5快乐,iOS4.3.5,不快乐。有兴趣了解你最终发现了什么
通过在requestmeDatWhenRepayonQueue块之前显式保留writer、writer输入、reader、reader输出,并在else子句的末尾显式释放所有四个,解决了这个问题
医生说标记完成后,“块应该退出。”也许他们不是在开玩笑。如果您不执行退出操作,则这是一个错误。不过,上述解决方法似乎有效
更新:我仍然发现,即使在保留和释放所有资产对象之后,它偶尔也会崩溃。正如您的问题所观察到的,在您将writer输入标记为finished后不久,它就会崩溃,就好像块本身正在被释放一样。而不仅仅是将块作为函数的一部分传递。我创建了一个复制的块特性,该特性是长寿命对象的一部分。我用Block_copy初始化它,只在长寿命对象的析构函数中释放它。这似乎奏效了。从那以后,我再也没有见过任何4.3.5崩溃。尝试将[self-retain]作为块的第一行,将[self-release]作为块的最后一行 另一个关键问题是,如果应用程序在READYONQUEUE时使用RequestMediaDataWhen挂起(进入后台),则需要显式覆盖所有[reader status]值,因为当应用程序重新启动时,它将失败。在某些情况下,我发现该块在带有失败状态标志的情况下运行了多次。在其他类似代码的帖子中,有很多AV变量被保留,然后在代码块的末尾被释放。因为块可以运行多次,所以当应用程序进入后台状态时,这种方法不起作用 我发现以下内容在“切换”(上图)中效果良好:
除了“自我”,什么都不保留。如果需要,程序块应自动保留变量。您能发布此解决方案的代码吗?有同样的问题。你解决了这个问题吗?
case AVAssetReaderStatusReading:
break;
case AVAssetReaderStatusCompleted:
[videoWriterInput markAsFinished];
//do something else, like add an audio stream
[videoWriter finishWriting];
break;
case AVAssetReaderStatusFailed:
[videoWriterInput markAsFinished];
[videoWriter finishWriting];
break;
case AVAssetReaderStatusCancelled:
case AVAssetReaderStatusUnknown:
[videoWriterInput markAsFinished];
[videoWriter cancelWriting];
break;
}
dispatch_sync(dispatch_get_main_queue(), ^{
//hide any progress indicators
});
break;