【问题标题】:iOS - video frame processing optimizationiOS - 视频帧处理优化
【发布时间】:2014-06-27 22:14:57
【问题描述】:

在我的项目中,我需要将视频的每一帧的一部分复制到一个唯一的结果图像上。

捕获视频帧并不是什么大问题。它会是这样的:

// duration is the movie lenght in s.
// frameDuration is 1/fps. (or 24fps, frameDuration = 1/24)
// player is a MPMoviePlayerController
for (NSTimeInterval i=0; i < duration; i += frameDuration) {
    UIImage * image = [player thumbnailImageAtTime:i timeOption:MPMovieTimeOptionExact];

    CGRect destinationRect = [self getDestinationRect:i];
    [self drawImage:image inRect:destinationRect fromRect:originRect];

    // UI feedback
    [self performSelectorOnMainThread:@selector(setProgressValue:) withObject:[NSNumber numberWithFloat:x/totalFrames] waitUntilDone:NO];
}

当我尝试实现drawImage:inRect:fromRect: 方法时,问题就来了。
我试过this code,它:

  1. 使用CGImageCreateWithImageInRect 从视频帧中创建一个新的CGImage 以提取图像块。
  2. 在 ImageContext 上创建一个 CGContextDrawImage 来绘制块

但是当视频达到 12-14 秒时,我的 iPhone 4S 宣布他的第三次内存警告并崩溃。我已经使用 Leak 工具分析了该应用程序,它根本没有发现任何泄漏...

我在 Quartz 方面不是很强。有没有更好的优化方法来实现这一点?

【问题讨论】:

    标签: ios optimization mpmovieplayercontroller video-processing


    【解决方案1】:

    最后,我保留了代码中的 Quartz 部分并更改了检索图像的方式。

    现在我使用 AVFoundation,这是一个更快的解决方案。

    // Creating the tools : 1/ the video asset, 2/ the image generator, 3/ the composition, which helps to retrieve video properties.
    AVURLAsset *asset = [[[AVURLAsset alloc] initWithURL:moviePathURL
                                                 options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], AVURLAssetPreferPreciseDurationAndTimingKey, nil]] autorelease];
    AVAssetImageGenerator *generator = [[[AVAssetImageGenerator alloc] initWithAsset:asset] autorelease];
    generator.appliesPreferredTrackTransform = YES; // if I omit this, the frames are rotated 90° (didn't try in landscape)
    AVVideoComposition * composition = [AVVideoComposition videoCompositionWithPropertiesOfAsset:asset];
    
    // Retrieving the video properties
    NSTimeInterval duration = CMTimeGetSeconds(asset.duration);
    frameDuration = CMTimeGetSeconds(composition.frameDuration);
    CGSize renderSize = composition.renderSize;
    CGFloat totalFrames = round(duration/frameDuration);
    
    // Selecting each frame we want to extract : all of them.
    NSMutableArray * times = [NSMutableArray arrayWithCapacity:round(duration/frameDuration)];
    for (int i=0; i<totalFrames; i++) {
        NSValue *time = [NSValue valueWithCMTime:CMTimeMakeWithSeconds(i*frameDuration, composition.frameDuration.timescale)];
        [times addObject:time];
    }
    
    __block int i = 0;
    AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){
        if (result == AVAssetImageGeneratorSucceeded) {
            int x = round(CMTimeGetSeconds(requestedTime)/frameDuration);
            CGRect destinationStrip = CGRectMake(x, 0, 1, renderSize.height);
            [self drawImage:im inRect:destinationStrip fromRect:originStrip inContext:context];
        }
        else
            NSLog(@"Ouch: %@", error.description);
        i++;
        [self performSelectorOnMainThread:@selector(setProgressValue:) withObject:[NSNumber numberWithFloat:i/totalFrames] waitUntilDone:NO];
        if(i == totalFrames) {
            [self performSelectorOnMainThread:@selector(performVideoDidFinish) withObject:nil waitUntilDone:NO];
        }
    };
    
    // Launching the process...
    generator.requestedTimeToleranceBefore = kCMTimeZero;
    generator.requestedTimeToleranceAfter = kCMTimeZero;
    generator.maximumSize = renderSize;
    [generator generateCGImagesAsynchronouslyForTimes:times completionHandler:handler];
    

    即使是很长的视频,它也需要时间,但它永远不会崩溃!

    【讨论】:

    • 嗨马丁,图像提取的方式是完美的,但在应用程序中,如果视频持续时间超过 30 秒,则应用程序崩溃并显示内存警告。你有其他方式或任何改变吗?谢谢
    • 嗨。它不应该因长视频而崩溃。检查您的代码,也许您在处理程序块中包含泄漏。您无法将所有提取的图像保留在内存中,因为设备没有足够的内存空间。
    • @iBhavik 你找到解决办法了吗
    【解决方案2】:

    除了 Martin 的回答之外,我还建议缩小通过该调用获得的图像的大小;也就是添加属性[generator.maximumSize = CGSizeMake(width,height)];让图片尽可能的小,这样就不会占用太多内存

    【讨论】:

      猜你喜欢
      • 2017-04-07
      • 2011-03-29
      • 1970-01-01
      • 2012-12-31
      • 1970-01-01
      • 2016-11-07
      • 2015-08-28
      • 2015-06-12
      相关资源
      最近更新 更多