视频转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
质量压缩上海需要改进,各位可根据自己需要进行修改。
网友评论