16

I am selecting video clip from library. And i want to create thumbnail image of it. I have applied this code. But the image appeared rotated. I want its original view.

- (UIImage*)testGenerateThumbNailDataWithVideo {

    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:appDelegate.videoURL options:nil];
    AVAssetImageGenerator *generate = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    NSError *err = NULL;
    CMTime time = CMTimeMake(1, 60);
    CGImageRef imgRef = [generate copyCGImageAtTime:time actualTime:NULL error:&err];
    [generate release];
    NSLog(@"err==%@, imageRef==%@", err, imgRef);
    UIImage *currentImg = [[[UIImage alloc] initWithCGImage:imgRef] autorelease];
    static BOOL flag = YES; 
    if (flag) { 
        NSData *tmpData =   UIImageJPEGRepresentation(currentImg, 0.8);
        NSString *path = [NSString stringWithFormat:@"%@thumbNail.png", NSTemporaryDirectory()];
        BOOL ret = [tmpData writeToFile:path atomically:YES]; 
        NSLog(@"write to path=%@, flag=%d", path, ret);
        flag = NO;
    }
    return currentImg;
}
DipakSonara
  • 2,598
  • 3
  • 29
  • 34
  • possible duplicate of [Getting thumbnail from a video url or data in IPhone SDK](http://stackoverflow.com/questions/1347562/getting-thumbnail-from-a-video-url-or-data-in-iphone-sdk) – Avt Aug 08 '15 at 21:30

3 Answers3

39

Try using AVAssetImageGenerator instead. Apple discusses using AVAssetImageGenerator to create thumbnails here. Here is sample code, which grabs a single thumbnail image. You will need to include the AVFoundation framework. And also add CoreMedia framework

AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:vidPath options:nil];
AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
gen.appliesPreferredTrackTransform = YES;
CMTime time = CMTimeMakeWithSeconds(0.0, 600);
NSError *error = nil;
CMTime actualTime;

CGImageRef image = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
UIImage *thumb = [[UIImage alloc] initWithCGImage:image];
CGImageRelease(image);
[gen release];

One more solution is

-(void)generateImage
{
    AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:self.url options:nil];
    AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    generator.appliesPreferredTrackTransform=TRUE;
    [asset release];
    CMTime thumbTime = CMTimeMakeWithSeconds(0,30);

    AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){
        if (result != AVAssetImageGeneratorSucceeded) {
            NSLog(@"couldn't generate thumbnail, error:%@", error);
        }
        [button setImage:[UIImage imageWithCGImage:im] forState:UIControlStateNormal];
        thumbImg=[[UIImage imageWithCGImage:im] retain];
        [generator release];
    };

    CGSize maxSize = CGSizeMake(320, 180);
    generator.maximumSize = maxSize;
    [generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];

}

Or

ALAsset
display image from URL retrieved from ALAsset in iPhone

Community
  • 1
  • 1
Chetan Bhalara
  • 10,326
  • 6
  • 32
  • 51
  • Just a hint. I needed to be very precise about the time to get the image. You can set requestedTimeToleranceAfter and requestedTimeToleranceBefore equal to kCMTimeZero. – SlowTree Feb 06 '12 at 18:09
  • Hey man this is great, the code is getting the image, but what I am trying to do is get the image of the video 10 times per second, and I have been playing around with the time variable and loops but can't get it to work? I have the full question here with a bounty on it if you wouldn't mind taking a look. Thanks so much http://stackoverflow.com/questions/29425455/ios-take-multiple-screen-shots – iqueqiorio Apr 11 '15 at 13:27
  • gen.appliesPreferredTrackTransform = YES; worked for me. If I dont use this, images came out rotated. – nr5 Jul 02 '17 at 04:19
4

Swift 5:

func previewImageForLocalVideo(at url: URL) -> UIImage? {
    let asset = AVAsset(url: url)
    let imageGenerator = AVAssetImageGenerator(asset: asset)
    imageGenerator.appliesPreferredTrackTransform = true

    var time = asset.duration
    //If possible - take not the first frame (it could be completely black or white on camara's videos)
    time.value = min(time.value, 2)

    do {
        let imageRef = try imageGenerator.copyCGImage(at: time, actualTime: nil)
        return UIImage(cgImage: imageRef)
    } catch let error as NSError {
        print("Image generation failed with error \(error)")
        return nil
    }
}
DZoki019
  • 382
  • 2
  • 13
Avt
  • 16,927
  • 4
  • 52
  • 72
  • are you sure time.value is the frame number and not the seconds? – Sam Nov 19 '15 at 20:17
  • @Sam Yes, I am. Check https://developer.apple.com/library/mac/documentation/CoreMedia/Reference/CMTime/index.html#//apple_ref/swift/struct/c:@SA@CMTime . `value/timescale = seconds.` – Avt Nov 20 '15 at 00:03
  • A better way of getting the time would be to use the functions for manipulating CMTime described here https://developer.apple.com/library/prerelease/ios/documentation/CoreMedia/Reference/CMTime/index.html#//apple_ref/c/func/CMTimeMultiplyByFloat64 replace your `time.value = min(time.value, 2)` with `time = CMTimeMultiplyByFloat(time, 0.5)` for a clearer, more accurate answer. – Tim Bull Feb 01 '16 at 23:52
  • @TimBull your solution will return a frame in the middle of a video. In my solution I want to use the first frame but it sometimes does not work well for some videos on some devices (I do not know why). So I use the second frame expecting it to be the same (or almost the same) as the first one. – Avt Feb 12 '16 at 08:24
1

This will solve the rotation issue

generate.appliesPreferredTrackTransform = YES
mwhs
  • 5,878
  • 2
  • 28
  • 34
Amal T S
  • 3,327
  • 2
  • 24
  • 57