从视频中截取缩略图生成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 图片处理机制;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容