thumbnailImageAtTime: now deprecated - What's the alternative?

12,360

Solution 1

Managed to find a great way using AVAssetImageGenerator, please see code below...

AVURLAsset *asset1 = [[AVURLAsset alloc] initWithURL:partOneUrl options:nil];
AVAssetImageGenerator *generate1 = [[AVAssetImageGenerator alloc] initWithAsset:asset1];
generate1.appliesPreferredTrackTransform = YES;
NSError *err = NULL;
CMTime time = CMTimeMake(1, 2);
CGImageRef oneRef = [generate1 copyCGImageAtTime:time actualTime:NULL error:&err];
UIImage *one = [[UIImage alloc] initWithCGImage:oneRef];
[_firstImage setImage:one];
_firstImage.contentMode = UIViewContentModeScaleAspectFit;

Within header file, please import

#import <AVFoundation/AVFoundation.h>

It works perfect and I've been able to call it from viewDidLoad, which was quicker than calling the deprecated thumbNailImageAtTime: from the viewDidAppear.

Hope this helps anyone else who had the same problem.

* **Update for Swift 5.1 ****

Useful function...

    func createThumbnailOfVideoUrl(url: URL) -> UIImage? {
        let asset = AVAsset(url: url)
        let assetImgGenerate = AVAssetImageGenerator(asset: asset)
        assetImgGenerate.appliesPreferredTrackTransform = true

        let time = CMTimeMakeWithSeconds(1.0, preferredTimescale: 600)
        do {
            let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil) 
            let thumbnail = UIImage(cgImage: img)
            return thumbnail
        } catch {
          print(error.localizedDescription)
          return nil
        }
    }

Solution 2

The requestThumbnailImagesAtTimes:timeOption: method will post a MPMoviePlayerThumbnailImageRequestDidFinishNotification notification when an image request completes. Your code that needs the thumbnail image should subscribe to this notification using NSNotificationCenter, and use the image when it receives the notification.

Solution 3

The problem is that you have to specify float values in requestThumbnailImagesAtTimes.

For example, this will work

[self.moviePlayer requestThumbnailImagesAtTimes:@[@14.f] timeOption:MPMovieTimeOptionNearestKeyFrame];

but this won't work:

[self.moviePlayer requestThumbnailImagesAtTimes:@[@14] timeOption:MPMovieTimeOptionNearestKeyFrame];

Solution 4

The way to do it, at least in iOS7 is to use floats for your times

NSNumber *timeStamp = @1.f;
[moviePlayer requestThumbnailImagesAtTimes:timeStamp timeOption:MPMovieTimeOptionNearestKeyFrame];

Hope this helps

Solution 5

Jeely provides a good work around but it requires an additional library that isn't necessary when the MPMoviePlayer already provides functions for this task. I noticed a syntax error in the original poster's code. The thumbnail notification handler expects an object of type NSNotification, not a dictionary object. Here's a corrected example:

-(void)MPMoviePlayerThumbnailImageRequestDidFinishNotification: (NSNotification*)note
{
    NSDictionary * userInfo = [note userInfo];
    UIImage *image = (UIImage *)[userInfo objectForKey:MPMoviePlayerThumbnailImageKey];
    if(image!=NULL)
        [thumbView setImage:image];
}
Share:
12,360

Related videos on Youtube

Jim Tierney
Author by

Jim Tierney

iOS &amp; Android developer since 2012 Objective-c Swift Kotlin React-native An active SO user eager to help other developers where I can and enjoy reading solutions, up-voting the good ones, especially the ones who give a little explanation as to why it's a solution. #SOreadytohelp

Updated on June 10, 2022

Comments

  • Jim Tierney
    Jim Tierney about 2 years

    Until iOS7 update I was using...

    UIImage *image = [moviePlayer thumbnailImageAtTime:1.0 timeOption:MPMovieTimeOptionNearestKeyFrame];
    

    ...with great success, so that my app could show a still of the video that the user had just taken.

    I understand this method, as of iOS7 has now deprecated and I need an alternative. I see there's a method of

    - (void)requestThumbnailImagesAtTimes:(NSArray *)playbackTimes timeOption:(MPMovieTimeOption)option
    

    though how do I return the image from it so I can place it within the videoReview button image?

    Thanks in advance, Jim.

    ****Edited question, after trying notification centre method***

    I used the following code -

    [moviePlayer requestThumbnailImagesAtTimes:times timeOption:MPMovieTimeOptionNearestKeyFrame];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(MPMoviePlayerThumbnailImageRequestDidFinishNotification::) name:MPMoviePlayerThumbnailImageRequestDidFinishNotification object:moviePlayer];
    

    I made the NSArray times of two NSNumber objects 1 & 2.

    I then tried to capture the notification in the following method

    -(void)MPMoviePlayerThumbnailImageRequestDidFinishNotification: (NSDictionary*)info{
    
    UIImage *image = [info objectForKey:MPMoviePlayerThumbnailImageKey];
    

    Then proceeded to use this thumbnail image as the button image as a preview.... but it didn't work.

    If you can see from my coding where I've went wrong your help would be appreciated again. Cheers

  • Jim Tierney
    Jim Tierney over 10 years
    Hi Greg, thanks for taking the time to reply to my question. I've went to the notification documentation, though I must still be implementing the method of it wrong as it's not working - I put the following as the notification code...
  • John Riselvato
    John Riselvato over 10 years
    This works perfect! The only thing I can say to improve this answer is make sure you import this #import <AVFoundation/AVFoundation.h>
  • Julian B.
    Julian B. over 10 years
    To add to @JohnRiselvato's comment you also have to add the following libraries to your project: CoreMedia and AVFoundation.
  • iqueqiorio
    iqueqiorio about 9 years
    Hey man, thanks I was just wondering how to do this if I wanted one frame at 1sec in and another at 3 seconds in?
  • David Zorychta
    David Zorychta about 8 years
    ^ I don't believe this is correct if you have an ALAsset and not an AVAsset
  • Abha
    Abha about 7 years
    @Jim Tierney I am getting nil image. Please tell me what is the problem. Same code I have done