AVAssetReaderTrackOutput在copyNextSampleBuffer上挂起

时间:2016-09-08 12:29:17

标签: ios avfoundation

我遇到了AVAssetWritter的问题。有时我的视频编写会话就会挂起。检查当前在我的设备上运行的线程后,我发现整个视频处理正在等待copyNextSampleBuffer返回。我不知道是什么原因导致了这个问题。有没有人成功地克服了这个问题?

下面是从乐器捕获的线程转储。它以mach_msg_trap结束。 Thread stack

视频处理循环

while ([self.assetWriterVideoInput isReadyForMoreMediaData] && !(*completedOrFailed) && !self.cancelled)
    {
        @autoreleasepool {


            CMSampleBufferRef sampleBuffer = [self.assetReaderVideoOutput copyNextSampleBuffer];



            CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
            CVPixelBufferRef croppedBuffer = NULL;
            NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                                     [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
            CVPixelBufferCreate(kCFAllocatorDefault, self.outputSize.width, self.outputSize.height, CVPixelBufferGetPixelFormatType(pixelBuffer), (__bridge CFDictionaryRef) options, &croppedBuffer);
            CIImage *img = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer];

            // img processing


            [self.context render:img toCVPixelBuffer:croppedBuffer];


            if (sampleBuffer != NULL)
            {

                BOOL success = [self.avPixelAdaptor appendPixelBuffer:croppedBuffer withPresentationTime:sampleTime];

                CFRelease(sampleBuffer);
                sampleBuffer = NULL;
                *completedOrFailed = !success;
            }
            else
            {
                *completedOrFailed = YES;
            }
            CVPixelBufferRelease(croppedBuffer);
        }
    }
}

更新

资产阅读器的源资源是AVMutableComposition,它由指向照片库的几个AVURLAsset组成(即url =“assets-library://asset/asset.MOV?id = 4CA9A2C6-F2D4-4FDF-AAEC-6335B9BD840A&安培; EXT = MOV“)。从每个源资源获取2秒,这是在0.6s的源资产之后开始的。如果所有源资源都从0开始,那么视频处理永远不会挂起。

摘要

主要问题是:导致copyNextSampleBuffer永远等待退出的条件是什么?文档没有提到这种情况。

2 个答案:

答案 0 :(得分:0)

我没有看到您将输入标记为已完成并在您的代码中结束了会话,如下所示。你打电话给这些终结者了吗?

//Finish the session:
[writerInput markAsFinished];
[videoWriter endSessionAtSourceTime:totalDuration];

[videoWriter finishWritingWithCompletionHandler:^{

// Handle videoWriter.status here

}];

答案 1 :(得分:0)

此错误也可能出现在 AVPlayerAVAssetExportSession 上。我的解决方案可用于 AVPlayerItemAVAssetExportSession

我花了一段时间才明白发生了什么。我仍然不是 100% 确定,但这就是我想出来的:

问题在于视频的源时间和目标时间映射。我猜你是否检查 videoTrack.segments(例如第一个)segment.timeMapping.source.start 将不等于 segment.timeMapping.target.start。默认情况下,在内部,AVVideoComposition 将从您的原始资产组合继承 sourceTrackIDForFrameTiming,以及有关时间、帧率等的所有内容,这将导致错误。如果您不设置用于导出的 videoComposition,它将执行相同的操作。我可以猜测资产阅读器的某些内部逻辑会破坏此特定案例的时间计算。

因此,为了修复,您可以为 sourceTrackIDForFrameTiming 设置 AVVideoComposition

作为 assetReaderVideoOutput,您应该使用带有 AVAssetReaderVideoCompositionOutputvideoComposition

您可以像这样创建 videoComposition,例如:

    let videoComposition = AVMutableVideoComposition(propertiesOf: mutableComposition)

    //MARK: - The most important thing
    videoComposition.sourceTrackIDForFrameTiming = kCMPersistentTrackID_Invalid

    videoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
    videoComposition.renderScale  = 1.0
    videoComposition.renderSize = CGSize(width: 720.0, height: 1280.0)
    
    let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compositionVideoTrack)
    
    let mainInstruction = AVMutableVideoCompositionInstruction()
    mainInstruction.timeRange = CMTimeRange(start: .zero, duration: composition.duration)
    mainInstruction.layerInstructions = [layerInstruction]
    
    videoComposition.instructions = [mainInstruction]

在此处根据您的需要更改硬编码值。您还可以在不设置 sourceTrackIDForFrameTiming 的情况下使用 let videoComposition = AVMutableVideoComposition() 初始值设定项,在我的测试中,这也有效。将 videoComposition 分配给 assetReaderVideoOutput。并导出。

就是这样!