从视频中截取缩略图生成gif图片

作者: 辉的书 | 来源:发表于2017-11-08 15:12 被阅读21次

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

    相关文章

      网友评论

        本文标题:从视频中截取缩略图生成gif图片

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