美文网首页
视频抽帧并合成Gif图片

视频抽帧并合成Gif图片

作者: ZYiDa | 来源:发表于2019-02-14 14:48 被阅读13次

视频转GIF分为两步

第一步:通过抽帧操作获取指定帧然后转化为需要的image

第二步:通过循环添加合成gif图片

有一个概念需要提前知道:视频总帧数=帧率*视频时长,这个有助于理解下面的内容。

以下内容部分参考自百度搜索

MakeGifs.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

struct VideoInfo {
    double duration;//视频时长
    NSInteger fileSize;//视频文件大小
};

@interface GetVideoInfo : NSObject
+ (void)getVideoInfoWithPath:(NSURL *)videoUrl resultInfo:(void(^)(struct VideoInfo videoInfo))resultInfo;
@end

@interface MakeGifs : NSObject

//对视频进行抽帧
+ (void)getThumbnailImagesWithVideo:(NSURL *)videoUrl frameRate:(NSInteger)frameRate complete:(void(^)(NSArray *images))complete;

//开始合成
+ (void)composeGifWithImageArray:(NSArray *)imageArray imgQuality:(double)imgQuality gifDelayTime:(double)delayTime complete:(void(^)(NSString *gifFilePath))complete;

//保存Gif
+ (void)savePhotoWithData:(NSData *)data completion:(void (^)(NSError *error))completion;
@end

NS_ASSUME_NONNULL_END

MakeGifs.m

#import "MakeGifs.h"
#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <Photos/Photos.h>
#import <Photos/PHPhotoLibrary.h>
@implementation GetVideoInfo

+ (void)getVideoInfoWithPath:(NSURL *)videoUrl resultInfo:(void(^)(struct VideoInfo videoInfo))resultInfo{
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoUrl options:nil];
    CMTime time = [asset duration];
    CGFloat seconds = ceil(time.value/time.timescale);
    NSInteger fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:videoUrl.absoluteString error:nil].fileSize;
    struct VideoInfo info;
    info.duration = seconds;
    info.fileSize = fileSize;
    resultInfo(info);
}

@end

@interface MakeGifs ()

@end

@implementation MakeGifs

//抽帧操作
+ (UIImage*)thumbnailImageForVideo:(NSURL *)videoURL atTime:(NSTimeInterval)time frameRate:(NSInteger)frameRate{
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
    NSParameterAssert(asset);
    AVAssetImageGenerator *assetImageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    assetImageGenerator.appliesPreferredTrackTransform = YES;
    assetImageGenerator.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
    
    CGImageRef thumbnailImageRef = NULL;
    CFTimeInterval thumbnailImageTime = time;
    CFTimeInterval thumbnailFrameRate = frameRate;
    NSError *thumbnailImageGenerationError = nil;
    thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:CMTimeMake(thumbnailImageTime, thumbnailFrameRate) actualTime:NULL error:&thumbnailImageGenerationError];
    if (!thumbnailImageRef){
        NSLog(@"thumbnailImageGenerationError %@", thumbnailImageGenerationError);
    }
    
    UIImage *thumbnailImage = thumbnailImageRef ? [[UIImage alloc] initWithCGImage:thumbnailImageRef] : nil;
    return thumbnailImage;
}

//循环抽帧,获取需要的图片组
+ (void)getThumbnailImagesWithVideo:(NSURL *)videoUrl frameRate:(NSInteger)frameRate  complete:(void(^)(NSArray *images))complete{
    NSMutableArray *videoImages = [NSMutableArray array];
    [GetVideoInfo getVideoInfoWithPath:videoUrl resultInfo:^(struct VideoInfo videoInfo) {
        
        for (int i = 0; i < videoInfo.duration * frameRate; i++) {
            UIImage *image = [MakeGifs thumbnailImageForVideo:videoUrl atTime:i frameRate:frameRate];
            if (image != nil) {
                [videoImages addObject:image];
            }
        }
    }];
    complete(videoImages);
}

//开始合成Gif
+ (void)composeGifWithImageArray:(NSArray *)imageArray imgQuality:(double)imgQuality gifDelayTime:(double)delayTime complete:(void(^)(NSString *gifFilePath))complete{
    //创建gif路径
    NSString *imagepPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString * gifPath = [imagepPath stringByAppendingString:@"/make.gif"];
    
    //图像目标
    CGImageDestinationRef destination;
    
    CFURLRef url=CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)gifPath, kCFURLPOSIXPathStyle, false);
    //通过一个url返回图像目标
    destination = CGImageDestinationCreateWithURL(url, kUTTypeGIF, imageArray.count, NULL);
    
    //设置gif的信息,播放间隔时间,基本数据,和delay时间,可以自己设置
    NSDictionary *frameProperties = [NSDictionary
                                     dictionaryWithObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithFloat:delayTime], (NSString *)kCGImagePropertyGIFDelayTime, nil]
                                     forKey:(NSString *)kCGImagePropertyGIFDictionary];
    
    //设置gif信息
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:2];
    
    //颜色
    [dict setObject:[NSNumber numberWithBool:YES] forKey:(NSString*)kCGImagePropertyGIFHasGlobalColorMap];
    
    //颜色类型
    [dict setObject:(NSString *)kCGImagePropertyColorModelRGB forKey:(NSString *)kCGImagePropertyColorModel];
    
    //颜色深度
    [dict setObject:[NSNumber numberWithInt:8] forKey:(NSString*)kCGImagePropertyDepth];
    
    //是否重复
    [dict setObject:[NSNumber numberWithInt:1] forKey:(NSString *)kCGImagePropertyGIFLoopCount];
    
    NSDictionary * gifproperty = [NSDictionary dictionaryWithObject:dict forKey:(NSString *)kCGImagePropertyGIFDictionary];
    
    //合成gif
    for (UIImage * img in imageArray)
    {
        NSData *data = UIImageJPEGRepresentation(img, imgQuality);
        UIImage *img2 = [UIImage imageWithData:data];
        CGImageDestinationAddImage(destination, img2.CGImage, (__bridge CFDictionaryRef)frameProperties);
    }
    
    CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)gifproperty);
    CGImageDestinationFinalize(destination);
    
    complete(gifPath);
    CFRelease(url);
    CFRelease(destination);
}

//保存合成的Gif图片
+ (void)savePhotoWithData:(NSData *)data completion:(void (^)(NSError *error))completion{
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        
        PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
        options.shouldMoveFile = YES;
        PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
        [request addResourceWithType:PHAssetResourceTypePhoto data:data options:options];
        request.creationDate = [NSDate date];
        
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            if (success && completion) {
                completion(nil);
            } else if (error) {
                NSLog(@"IMAGE_SAVE_ERROR:%@",error.localizedDescription);
                if (completion) {
                    completion(error);
                }
            }
        });
    }];
}
@end

上面的封装只是简单实现了视频转GIF的功能,在GIF质量压缩上海需要改进,各位可根据自己需要进行修改。

相关文章

网友评论

      本文标题:视频抽帧并合成Gif图片

      本文链接:https://www.haomeiwen.com/subject/wdeeeqtx.html