Getting a thumbnail from a video url or data in iOS
Asked Answered
A

12

63

I am trying to acquire a thumbnail (of the first frame) from a video taken from iphone 3GS camera so I can display it. How to do this?

Ardine answered 28/8, 2009 at 14:59 Comment(2)
#7501913Action
possible duplicate of Thumbnail image of videoReformatory
A
69

The answer to this question is that one can now with 4.0 iOS get thumbnails using AVFoundation, the following code where the class property url is the movie url, will do the trick (you can get the thumbnail at any time, in the example its at time 0)

-(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];

}
Ardine answered 2/12, 2010 at 0:43 Comment(6)
That code works great. The only downside of AVAssettImageGenerator is that presently it uses keyframes, which are typically spaced at one-second intervals -- so you can't get any finer resolution than that. If you're just trying to make some thumbnails to spread out over a timeline it's probably fine, but if you're trying to read consecutive frames, this won't work. In that case you have to use AVAssetReader, which has some quirks of its own, or MPMovieController, which has thumbnail methods that are frame-accurate.Millenary
Appreciate this thread is old, but just want to add that MPMoviePlayerController (see below) is a much faster option. The code above takes a good 5-10 seconds to generate a thumbnail, whereas MPMovie is almost instant.Deplore
I have try the above method to get thumb image from video but is not giving all thumb like at time 1.5 . @AndyMilburn can you give any sample link to get thumb using AVAssetReader.Sulfurous
@AndyMilburn That's not exactly true, if you set requestedTimeToleranceBefore/After to smaller values you can get more closely spaced thumbnails.Jayme
Gives me the error AVErrorOperationNotSupportedForAsset . plz helpKarrikarrie
@Deplore I've tried this method with 5 different videos at the same time and all thumbnails are ready within a second; one thing to note is that you should use GCD to update the UI.Tameratamerlane
T
73
-(UIImage *)generateThumbImage : (NSString *)filepath
{
    NSURL *url = [NSURL fileURLWithPath:filepath];

    AVAsset *asset = [AVAsset assetWithURL:url];
    AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset];
    imageGenerator.appliesPreferredTrackTransform = YES;
    CMTime time = [asset duration];
    time.value = 0;
    CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL];
    UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);  // CGImageRef won't be released by ARC

    return thumbnail;
}

you can get the frame using the time.value suppose you want to 1 second frame then use the

time.value = 1000 //Time in milliseconds
Table answered 20/1, 2014 at 9:44 Comment(2)
@Diken Shah How Do i Get a thumbnail at n th second of the video. I set time.value=n but still i get the first frameOxyacetylene
To reliably get a thumbnail for different time indexes you need to set the requestedTimeTolerance properties on the imageGenerator, as detailed in this answer. #39525753Evocator
A
69

The answer to this question is that one can now with 4.0 iOS get thumbnails using AVFoundation, the following code where the class property url is the movie url, will do the trick (you can get the thumbnail at any time, in the example its at time 0)

-(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];

}
Ardine answered 2/12, 2010 at 0:43 Comment(6)
That code works great. The only downside of AVAssettImageGenerator is that presently it uses keyframes, which are typically spaced at one-second intervals -- so you can't get any finer resolution than that. If you're just trying to make some thumbnails to spread out over a timeline it's probably fine, but if you're trying to read consecutive frames, this won't work. In that case you have to use AVAssetReader, which has some quirks of its own, or MPMovieController, which has thumbnail methods that are frame-accurate.Millenary
Appreciate this thread is old, but just want to add that MPMoviePlayerController (see below) is a much faster option. The code above takes a good 5-10 seconds to generate a thumbnail, whereas MPMovie is almost instant.Deplore
I have try the above method to get thumb image from video but is not giving all thumb like at time 1.5 . @AndyMilburn can you give any sample link to get thumb using AVAssetReader.Sulfurous
@AndyMilburn That's not exactly true, if you set requestedTimeToleranceBefore/After to smaller values you can get more closely spaced thumbnails.Jayme
Gives me the error AVErrorOperationNotSupportedForAsset . plz helpKarrikarrie
@Deplore I've tried this method with 5 different videos at the same time and all thumbnails are ready within a second; one thing to note is that you should use GCD to update the UI.Tameratamerlane
M
23
NSURL *videoURL = [NSURL fileURLWithPath:url];

MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];

        UIImage *thumbnail = [player thumbnailImageAtTime:1.0 timeOption:MPMovieTimeOptionNearestKeyFrame];

        //Player autoplays audio on init
        [player stop];
        [player release];

Check this link for an alternative: thumbnailImageAtTime: now deprecated - What's the alternative?

Mousseline answered 17/5, 2011 at 6:54 Comment(6)
@Maulik i tried above code to generate image its working fine,but i am not getting video time line how can i get this also do u have any ideaFleda
the thumbnail image is not displaying the time. Can you please edit your code if you know this?Syzygy
will I be able to use this for screen capturing the video and not for creating thumbnail?Einsteinium
I'm using this url sciencentral.com/news/image_db/2024515/… I get nil thumbnail image. please helpKarrikarrie
Isn't this approach much less memory friendly than the AVAssetImageGenerator approach? The way I understand it - the whole video needs to be loaded into memory in order to generate a single image.Dorella
thumbnailImageAtTime: is deprecated now, just FYI to anyone who visits this thread.Meenen
C
14

Best method I've found... MPMoviePlayerController thumbnailImageAtTime:timeOption

Cohbath answered 25/8, 2010 at 3:46 Comment(4)
The best method i would say is using AVFoundationArdine
Actually on testing I find this method is much faster than the AVAsset code listed above.Deplore
I'm using this url sciencentral.com/news/image_db/2024515/… I get nil thumbnail image. please helpKarrikarrie
But in this method first video should play at once than only it gives thumbnail image of frame. So its better use AVURLAsset for getting thumbnail image of any video file.Table
I
14

SWIFT 2.0

You can generate in swift in two ways 1. AVFoundation 2. MPMoviePlayerController

1. 

    func generateThumnail(url : NSURL) -> UIImage{
            var asset : AVAsset = AVAsset.assetWithURL(url) as AVAsset
            var assetImgGenerate : AVAssetImageGenerator = AVAssetImageGenerator(asset: asset)
            assetImgGenerate.appliesPreferredTrackTransform = true
            var error       : NSError? = nil
            var time        : CMTime = CMTimeMake(1, 30)
            var img         : CGImageRef = assetImgGenerate.copyCGImageAtTime(time, actualTime: nil, error: &error)
            var frameImg    : UIImage = UIImage(CGImage: img)!
            
            return frameImg
        }

2. 

    override func viewDidLoad() {
            super.viewDidLoad()
            var moviePlayer         : MPMoviePlayerController!  = MPMoviePlayerController(contentURL: moviePlayManager.movieURL)
            moviePlayer.view.frame   = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width:
                                       self.view.frame.size.width, height: self.view.frame.height)
            moviePlayer.fullscreen   = true
            moviePlayer.controlStyle = MPMovieControlStyle.None
            NSNotificationCenter.defaultCenter().addObserver(self,
        selector: "videoThumbnailIsAvailable:",
        name: MPMoviePlayerThumbnailImageRequestDidFinishNotification,
        object: nil)


        let thumbnailTimes = 3.0
        moviePlayer.requestThumbnailImagesAtTimes([thumbnailTimes],
                timeOption: .NearestKeyFrame)
        }
    
    func videoThumbnailIsAvailable(notification: NSNotification){
        
        if let player = moviePlayer{
            let thumbnail =
            notification.userInfo![MPMoviePlayerThumbnailImageKey] as? UIImage
            
            if let image = thumbnail{
                
                /* We got the thumbnail image. You can now use it here */
                println("Thumbnail image = \(image)")
            }
        }
Irritating answered 9/3, 2015 at 6:55 Comment(2)
solution 1 works in most cases for me but not always do you know why ? #37374508Occidental
Actually i will take a tour on your post in free time. Thanks for your comment :)Irritating
R
8

Swift 2 code:

func previewImageForLocalVideo(url:NSURL) -> 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.copyCGImageAtTime(time, actualTime: nil)
        return UIImage(CGImage: imageRef)
    }
    catch let error as NSError
    {
        print("Image generation failed with error \(error)")
        return nil
    }
}
Reformatory answered 8/8, 2015 at 16:36 Comment(1)
It works in most cases but not always do you know why? #37374508Occidental
I
8

For Swift 3.0

func createThumbnailOfVideoFromFileURL(_ strVideoURL: String) -> UIImage?{

let asset = AVAsset(url: URL(string: strVideoURL)!)
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
assetImgGenerate.appliesPreferredTrackTransform = true
let time = CMTimeMakeWithSeconds(Float64(1), 100)
do {
  let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
  let thumbnail = UIImage(cgImage: img)
  return thumbnail
} catch {
  /* error handling here */
}
return nil   }
Izolaiztaccihuatl answered 23/12, 2016 at 14:39 Comment(0)
B
3

For Swift 5

import AVKit

Code:

// Get Thumbnail Image from URL
fileprivate func getThumbnailFromUrl(_ url: String?, _ completion: @escaping ((_ image: UIImage?)->Void)) {

    guard let url = URL(string: url ?? "") else { return }
    DispatchQueue.main.async {
        let asset = AVAsset(url: url)
        let assetImgGenerate = AVAssetImageGenerator(asset: asset)
        assetImgGenerate.appliesPreferredTrackTransform = true

        let time = CMTimeMake(value: 2, timescale: 1)
        do {
            let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
            let thumbnail = UIImage(cgImage: img)
            completion(thumbnail)
        } catch {
            print("Error :: ", error.localizedDescription)
            completion(nil)
        }
    }
}

Usage :: Take one Image View

@IBOutlet weak var imgThumbnail: UIImageView!

Then after call getThumbnailFromUrl method for thumbnail with URL String as parameter

self.getThumbnailFromUrl(videoURL) { [weak self] (img) in

        guard let _ = self else { return }
        if let img = img {
            self?.imgThumbnail.image = img
        }
    }

pls try this if it is use full then pls comment Thank you

Bruiser answered 4/10, 2019 at 6:40 Comment(1)
I am using this solution is worked fine for me.Thanks Rohan AryanCholinesterase
H
2

Swift 4

func generateThumbnail(for asset:AVAsset) -> UIImage? {
    let assetImgGenerate : AVAssetImageGenerator = AVAssetImageGenerator(asset: asset)
    assetImgGenerate.appliesPreferredTrackTransform = true
    let time = CMTimeMake(value: 1, timescale: 2)
    let img = try? assetImgGenerate.copyCGImage(at: time, actualTime: nil)
    if img != nil {
        let frameImg  = UIImage(cgImage: img!)
       return frameImg
    }
    return nil
}

How to use:

   func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true) {

        switch mediaType {
        case kUTTypeMovie:
            guard info[UIImagePickerController.InfoKey.mediaType] != nil, let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL else { return }
            let asset = AVAsset(url: url)
            guard let img = self.generateThumbnail(for: asset) else {
                print("Error: Thumbnail can be generated.")
                return
            }
            print("Image Size: \(img.size)")
            break
        default:
            break
        }
    }
}
Hopson answered 10/1, 2019 at 4:45 Comment(0)
B
1

Maybe this is useful for someone else who faces the same problem. I needed an easy solution for creating a thumbnail for Images, PDFs and Videos. To solve that problem I've created the following Library.

https://github.com/prine/ROThumbnailGenerator

The usage is very straightforward: var thumbnailImage = ROThumbnail.getThumbnail(url)

It has internally three different implementations and depending on the file extension it does create the thumbnail. You can easily add your own implementation if you need a thumbnail creator for another file extension.

Bustard answered 12/8, 2015 at 13:12 Comment(1)
It works in most cases but not always do you know why? #37374508Occidental
H
1

Swift 2.1 Getting thumbnails at required time intervals

func getPreviewImageForVideoAtURL(videoURL: NSURL, atInterval: Int) -> UIImage? {
    print("Taking pic at \(atInterval) second")
    let asset = AVAsset(URL: videoURL)
    let assetImgGenerate = AVAssetImageGenerator(asset: asset)
    assetImgGenerate.appliesPreferredTrackTransform = true
    let time = CMTimeMakeWithSeconds(Float64(atInterval), 100)
    do {
        let img = try assetImgGenerate.copyCGImageAtTime(time, actualTime: nil)
        let frameImg = UIImage(CGImage: img)
        return frameImg
    } catch {
        /* error handling here */
    }
    return nil
}
Harmonics answered 8/1, 2016 at 11:57 Comment(0)
L
0

You will get Thumbnail Image From URL when you change "fileURLWithPath" to "URLWithString".

In My case it worked like this.

NSURL *url = [NSURL URLWithString:filepath];
AVAsset *asset = [AVAsset assetWithURL:url];
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset];
CMTime time = [asset duration];
time.value = 0;
CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL];
UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);

return thumbnail;
Laxation answered 4/9, 2016 at 6:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.