首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >[AVAssetWriterInput requestMediaDataWhenReadyOnQueue:usingBlock:]的内存问题

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

Stack Overflow用户
提问于 2012-01-24 00:07:44
回答 2查看 3.3K关注 0票数 3

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

代码语言:javascript
复制
[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…或调试器报告的一些无用的值。但是之前指向它的对象是好的,正如僵尸工具所确认的那样,它不会被释放。

我遗漏了什么?

EN

回答 2

Stack Overflow用户

发布于 2012-01-24 11:47:44

看到相同(类似)的问题。iOS5快乐,iOS4.3.5,不快乐。有兴趣了解你最终找到了什么。

通过在requestMedatWhenReadyOnQueue块之前显式保留写入器、写入器输入、读取器和读取器输出,并在else子句的末尾显式释放所有四个,从而解决了这一问题。

文档中确实提到,在标记为完成之后,“该块应退出”。也许他们不是在开玩笑。如果你做了除退出之外的任何事情,那就是一个错误。不过,上面的变通方法似乎是可行的。

更新:我仍然发现它偶尔会崩溃,即使在保留和释放所有资产对象之后也是如此。正如您的问题所观察到的,在您将编写器输入标记为完成后不久,它就崩溃了,就好像块本身正在被释放一样。而不是仅仅将块作为函数的一部分进行传递。我创建了一个复制的块特性,它是long lived对象的一部分。我用Block_copy初始化它,并且只在长寿对象的析构函数中释放它。这似乎起到了作用。从那以后,我再也没有见过4.3.5崩溃。

票数 1
EN

Stack Overflow用户

发布于 2012-05-10 11:04:18

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

另一个关键问题是,如果应用程序使用requestMediaDataWhenReadyOnQueue挂起(进入后台),您需要显式地覆盖所有读卡器状态值,因为它将在应用程序重启时失败。在某些情况下,我发现块运行不止一次,并带有一个失败状态标志。在其他具有类似代码的帖子中,会保留大量AV变量,然后在代码块的末尾释放这些变量。因为块可以多次运行,所以这种方法在应用程序进入后台状态的情况下不起作用。

我发现下面这些在“开关”(上面)中工作得很好:

代码语言:javascript
复制
                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;

除了"self“之外,没有任何东西被保留。如果需要,块应该自动保留变量。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8974679

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档