Objective-C 動画を複数のサムネイル画像に分割する

公開: 2015-04-10 03:41
更新: 2016-04-29 06:03

動画から複数のサムネイル画像を生成したいです。

そんな訳でこんな関数を用意しました。

-(NSArray *)sliceMovie:(NSURL *)url count:(NSInteger)count
{
        AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:url options:nil];
        if(![asset tracksWithMediaCharacteristic:AVMediaTypeVideo]) {
                return nil;
        }
        AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
        imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
        imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
        Float64 duration = CMTimeGetSeconds([asset duration]);
        NSError *error;
        CMTime actualTime;
        NSMutableArray *images = [NSMutableArray array];
        for(NSInteger i = 0; i < count; i++) {
                CMTime point = CMTimeMakeWithSeconds(duration/count*i, NSEC_PER_SEC);
                CGImageRef image = [imageGenerator copyCGImageAtTime:point actualTime:&actualTime error:&error];
                if(!error) {
                        [images addObject:[UIImage imageWithCGImage:image]];
                        CGImageRelease(image);                
                }
        }
        return images;
}

使い方はこんな感じです。

NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"movie.mp4"]; //動画までのパス
NSArray *images = [self sliceMovie:[NSURL fileURLWithPath:path] count:10]; //10枚に分割します

AVURLAssetやAVAssetImageGeneratorを使用するので、
「AVFoundation.framework」のインポートが必要です。




ただcopyCGImageAtTimeだとちょっと遅いという意見もあるので、

遅いなーと思った場合はgenerateCGImagesAsynchronouslyForTimesを使うと速くなりそう。

-(void)sliceMovie:(NSURL *)url count:(NSInteger)count completion:(void (^)(NSArray *))completion
{
        AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:url options:nil];
        if(![asset tracksWithMediaCharacteristic:AVMediaTypeVideo]) {
                if(completion) completion(nil);
                return;
        }
        AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
        imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
        imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
        Float64 duration = CMTimeGetSeconds([asset duration]);

        NSMutableArray *times = [NSMutableArray array];
        for(NSInteger i = 0; i < count; i++) {
                CMTime point = CMTimeMakeWithSeconds(duration/count*i, NSEC_PER_SEC);
                [times addObject:[NSValue valueWithCMTime:point]];
        }
        
        __block NSInteger c = 0;
        NSMutableArray *images = [NSMutableArray array];
        [imageGenerator generateCGImagesAsynchronouslyForTimes:times completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
                c++;
                if(error) return;
                [images addObject:[UIImage imageWithCGImage:image]];
                if(c == count) {
                        if(completion) completion(images);
                }
        }];
}

使い方はこんな感じ

NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"movie.mp4"]; //動画までのパス
[self sliceMovie:[NSURL fileURLWithPath:path] count:10 completion:^(NSArray *images) {
        
}];

小さい動画サイズや切り出す枚数が小さいとほぼ同じですが、

大体の条件下ではこちらの方が速かったです。



この記事をシェア
この記事にコメントする
書き込む
あっきぃ(@appstars_aki)
Web、iOSなフリーランサーです。好きなものはお寿司です。でもお寿司は高いので普段は雑草とか拾ったドングリを食べています。お仕事や意味もなく毎月お小遣いをくれる人を探してます。

お仕事の依頼や自分で作ったアプリのレビューを希望しちゃう方はaki@appstars.jpまでご連絡ください。