[AVAssetWriterInput requestMediaDataWhenReadyOnQueue:usingBlock:]的内存问题

时间:2012-01-23 16:07:44

标签: objective-c ios memory-management avfoundation

我正在编写一个库,使用AVFoundation将资源导出到文件中。我创建了一个读取器,一个写入器,将输入和输出连接到这些,然后在输入上调用requestMediaDataWhenReadyOnQueue方法以开始提取数据。提供给此方法的块回调看起来有点像这样:

[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上,代码在标有⬅箭头的行之后死于EXC_BAD_ACCESS。经过一番探索之后,我觉得在将输入标记为完成后,块会立即以某种方式被销毁。在执行坏行之前完全有效的self指针会以某种方式变为0xfff…或调试器报告的某些垃圾值。但之前指向它的对象很好,正如僵尸工具所证实的那样,它不会被解除分配。

我错过了什么?

2 个答案:

答案 0 :(得分:1)

看到相同(类似)的问题。 iOS5开心,iOS4.3.5,不开心。有兴趣了解您最终找到的内容。

通过在requestMedatWhenReadyOnQueue块之前显式保留writer,writer输入,reader,reader输出并在else子句的最后明确释放所有四个来解决它。

文档确实说标记完成后,“块应该退出”。也许他们不是在开玩笑。如果您执行除退出以外的任何操作,则会出错。上述解决方法似乎有效。

更新:我仍然发现,即使在保留并释放所有资产对象后,它偶尔也会崩溃。正如您的问题所指出的那样,在您将编写器输入标记为已完成之后不久就会崩溃,就好像块本身正在被释放一样。而不是仅仅将块作为函数的一部分传递。我创建了一个复制的块属性,它是长期存在的对象的一部分。我用Block_copy初始化它,只在长寿命对象的析构函数中释放它。这似乎可以解决问题。我从那以后没有看到任何4.3.5崩溃。

答案 1 :(得分:0)

尝试[self retain]作为块的第一行,[self release]作为最后一行。

另一个关键问题是,如果App使用requestMediaDataWhenReadyOnQueue暂停(进入后台),您需要明确覆盖所有[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;

除了“自我”之外,什么都没有保留。如果需要,块应自动保留变量。