从视频中截取缩略图生成gif图片
从视频中获取缩略图生成GIF图片,首先需要了解思路和要用到的开发框架,先来说一下思路:
1.在视频中按一定的时间,去截取当前时间的帧(即缩略图),如:每0.1秒获取一张帧图片,连续获取2秒,此时就会获取20张图片;
2.对这20张图片进行合成为GIF图片,并保存到相应路径下面;
3.对路径下面的GIF进行UIImageView播放;
由此可知,难点就在于视频帧的截取、图片的合成、以及imageView播放本地合成的gif的问题;
视频帧的截取:
用到了AVURLAsset,根据videoPath生成AVURLAsset对象asset,根据asset创建AVAssetImageGenerator图片发生器对象,进行帧图片的生成:
首先来看一下一张帧图片的获取:
- (UIImage*) getVideoPreViewImage
{
AVURLAsset *asset= [[AVURLAsset alloc] initWithURL:videoPath options:nil];
AVAssetImageGenerator *gen= [[AVAssetImageGenerator alloc] initWithAsset:asset];
gen.appliesPreferredTrackTransform=YES;
CMTime time=CMTimeMakeWithSeconds(0.0, 600);
NSError *error=nil;
CMTime actualTime;
CGImageRefimage= [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
UIImage *img= [[[UIImage alloc] initWithCGImage:image] autorelease];
CGImageRelease(image);
return img;
}
这里我们需要注意一点:当我们不设置gen.requestedTimeToleranceAfter=kCMTimeZero;
gen.requestedTimeToleranceBefore=kCMTimeZero;的话,我们给定的time和结果的actualTime很有可能是不一致的(请看:传送门 ,当你指定要获取time时刻的帧,如果不设置这两个属性,系统会默认如果在指定time段内有缓存,就从缓存中直接返回结果,但并不准确,这是为了优化性能),如果我们需要精确时间的帧,就需要加上这两句代码;
顺便我们来了解一下CMTime,它一般有两种创建方式:第一种:CMTimeMake(value,timescale),value是当前第几帧,timescale是每秒的帧数,我们可由value/timescale得到视频总秒数seconds;第二种是:CMTimeMakeWithSeconds(second,timescale),可知second是当前时间,second*timescale就是second时间内的总帧数;可用CMTimeShow(actualTime)输出看一下;
fps是指画面每秒传输帧数,即帧率;iOS中的CMTime的timescale为fps*1000;
float fps = [[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] nominalFrameRate];(fps的获取方式)
每0.1秒获取一张帧图,获取前两秒:代码
- (void)getAllImages:(NSString *)videoFilePath
{
_imgAry = [NSMutableArray array];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:videoFilePath] options:nil];
CMTime duration = [asset duration];
CMTime startTime = kCMTimeZero;
NSMutableArray *array = [NSMutableArray array];
CMTime addTime = CMTimeMake(duration.timescale*0.1,duration.timescale);
CMTime selectTime = CMTimeMake(2*duration.timescale,duration.timescale);
while (CMTIME_COMPARE_INLINE(startTime, <, selectTime)) {
[array addObject:[NSValue valueWithCMTime:startTime]];
startTime = CMTimeAdd(startTime, addTime);
}
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform=TRUE;
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){
if (result == AVAssetImageGeneratorSucceeded) {
@autoreleasepool {
UIImage *image = [UIImage imageWithCGImage:im];
NSData *data = UIImageJPEGRepresentation(image, 1);
dispatch_sync(dispatch_get_main_queue(), ^{
[_imgAry addObject:[UIImage imageWithData:data]];
if (_imgAry.count == 20) {
[self makeAnimatedGif];
return ;
}
});
}
}else{
}
};
CGSize videoSize = [QupaiSDK shared].videoSize;
generator.maximumSize = videoSize;
generator.requestedTimeToleranceAfter = kCMTimeZero;
generator.requestedTimeToleranceBefore = kCMTimeZero;
[generator generateCGImagesAsynchronouslyForTimes:array completionHandler:handler];
}
生成gif图片:用到了#import<MobileCoreServices/MobileCoreServices.h>#import<ImageIO/ImageIO.h>框架
主要是每一帧图片的属性设置进行合成:
- (UIImage*) makeAnimatedGif {
static NSUInteger kFrameCount = 20;//16;
NSDictionary *fileProperties = @{
(__bridge id)kCGImagePropertyGIFDictionary: @{
(__bridge id)kCGImagePropertyGIFLoopCount: @0, // 0 means loop forever
}
};
NSDictionary *frameProperties = @{
(__bridge id)kCGImagePropertyGIFDictionary: @{
(__bridge id)kCGImagePropertyGIFDelayTime: @0.1f, // a float (not double!) in seconds, rounded to centiseconds in the GIF data
}
};
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:@"animated.gif"];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypeGIF, kFrameCount, NULL);
CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)fileProperties);
for (NSUInteger i = 0; i < kFrameCount; i++) {
@autoreleasepool {
UIImage *image = _imgAry[i];//[UIImage imageNamed:name];
CGImageDestinationAddImage(destination, image.CGImage, (__bridge CFDictionaryRef)frameProperties);
}
}
if (!CGImageDestinationFinalize(destination)) {
NSLog(@"failed to finalize image destination");
}
CFRelease(destination);
NSLog(@"url=%@", fileURL);
_fileURL = fileURL;
UIImage * img = [UIImage imageWithData:[NSData dataWithContentsOfURL:fileURL]];
return img;
}
从GIF中获取每一张图片用imageview进行动画:
- (NSArray*)sssss{
NSURL *gifImageUrl = _fileURL;//获取Gif图的原数据
CGImageSourceRef gifSource = CGImageSourceCreateWithURL((CFURLRef)gifImageUrl, NULL); //获取Gif图有多少帧
size_t gifcount = CGImageSourceGetCount(gifSource);
NSMutableArray *imageS = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < gifcount; i++) {
//由数据源gifSource生成一张CGImageRef类型的图片
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
UIImage *image = [UIImage imageWithCGImage:imageRef];
[imageS addObject:image]; CGImageRelease(imageRef); }
//得到图片数组
return imageS;
}
- (void)setgifImgView:(NSArray*)images{
//把数组图片通过imageView的动画添加 然后开始动画
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(50, 100, 100, 100)];//初始化
imageView.backgroundColor = [UIColor cyanColor];//背景颜色
imageView.image = images.firstObject;
imageView.animationImages = images;
//动画的总时长(一组动画坐下来的时间 6张图片显示一遍的总时间)
imageView.animationDuration = 3;
imageView.animationRepeatCount = 0;//动画进行几次结束
[imageView startAnimating];//开始动画
imageView.userInteractionEnabled = YES;
[[UIApplication sharedApplication].keyWindow addSubview:imageView];
}
OK,图像的处理需要多了解CoreGraphics框架,多了解SDWebImage 图片处理机制;