美文网首页
视频抽帧并合成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