在iOS中访问所有电影帧的最佳方法

我试图编辑现有的电影与顶部的附加效果,因此我需要能够扫描所有电影帧,获得他们作为UIImage,应用效果,然后或者更新该帧或写入到新的电影。 我发现有人build议使用AVAssetImageGenerator。 下面是我最后编辑的样品,我如何做到这一点:

-(void)processMovie:(NSString*)moviePath { NSURL* url = [NSURL fileURLWithPath:moviePath]; AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil]; float movieTimeInSeconds = CMTimeGetSeconds([movie duration]); AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset]; generator.requestedTimeToleranceBefore = generator.requestedTimeToleranceAfter = kCMTimeZero; generator.appliesPreferredTrackTransform=TRUE; [asset release]; // building array of time with steps as 1/10th of second NSMutableArray* arr = [[[NSMutableArray alloc] init] retain]; for(int i=0; i<movieTimeInSeconds*10; i++) { [arr addObject:[NSValue valueWithCMTime:CMTimeMake(i,10)]]; } AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){ if (result == AVAssetImageGeneratorSucceeded) { UIImage* img = [UIImage imageWithCGImage:im]; // use img to apply effect and write it in new movie // after last frame do [generator release]; } }; [generator generateCGImagesAsynchronouslyForTimes:arr completionHandler:handler]; } 

这种方法有两个问题:

  1. 我需要猜测电影有什么时间步长,或者在我的例子中假设它的电影10FPS。 实际的时间步长不是均匀分布的,有时我们跳过了帧。
  2. 扫描帧的速度很慢。 如果电影以高分辨率录制,我会花费大约0.5秒来为每一帧检索UIImage。

这似乎不自然。 问:是否有更好的方法来扫描电影的所有原始帧?

终于find了我正在寻找的东西。 下面是我的代码,扫描电影中的所有样本。 顺便说一句,使用AVAssetImageGenerator工作,但非常缓慢。 这种方法很快。

 inputUrl = [NSURL fileURLWithPath:filePath]; AVURLAsset* movie = [AVURLAsset URLAssetWithURL:inputUrl options:nil]; NSArray* tracks = [movie tracksWithMediaType:AVMediaTypeVideo]; AVAssetTrack* track = [tracks firstObject]; NSError* error = nil; AVAssetReader* areader = [[AVAssetReader alloc] initWithAsset:movie error:&error]; NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; AVAssetReaderTrackOutput* rout = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:options]; [areader addOutput:rout]; [areader startReading]; while ([areader status] == AVAssetReaderStatusReading) { CMSampleBufferRef sbuff = [rout copyNextSampleBuffer]; if (sbuff) { dispatch_sync(dispatch_get_main_queue(), ^{ [self writeFrame:sbuff]; }); } } 

你可以得到video的帧速率。 看看这里的代码: 给定一个电影的URL,如何检索它的信息?

你只需要获得AVAssetTrack及其nominalFrameRate。

虽然这可能无法帮助您解决跳帧问题,但您可以在AVAssetTrack上使用nominalFrameRate来实现预期结果。