6

I have to extract a thumbnail from a video (from url) and I use this code:

NSString *stringUrl = video.stringurl;
NSURL *url = [NSURL URLWithString:stringUrl];

AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset];
[imageGenerator setRequestedTimeToleranceBefore:kCMTimeZero];
[imageGenerator setRequestedTimeToleranceAfter:kCMTimeZero];

CGImageRef imageRef = [imageGenerator copyCGImageAtTime:playerCurrentTime actualTime:&actualtime error:&error];
UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];

CGImageRelease(imageRef);

But sometime I have an error with copyCGImageAtTime and the thumbnail is not generated. The error is: Error save image Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed"(OSStatus error -12792.)", NSLocalizedFailureReason=An unknown error occurred (-12792)}

Here is the link which I have read a solution but if a use fileURLWithPath: instead of URLWithString: the method add to the end of the url an "-- file://localhost/" that invalidates the url. So I don't know what I can do.

Community
  • 1
  • 1
Anna565
  • 735
  • 2
  • 10
  • 21

6 Answers6

5

If you are using MPMoviePlayerController then you can use this code to generate thumbnail from video URL.

NSString *stringUrl = video.stringurl;
NSURL *url = [NSURL URLWithString:stringUrl];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:url];
UIImage *thumbnail = [player thumbnailImageAtTime:1.0 timeOption:MPMovieTimeOptionNearestKeyFrame];

But, using this code, player will start autoplaying audio. So, you have to stop the player with this code :

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

Update :

Error save image Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed"(OSStatus error -12792.)", NSLocalizedFailureReason=An unknown error occurred (-12792)}

The Error is probably due to use of URLWithString. I think you should use -fileURLWithPath instead of URLWithString.

Sample Code :

NSString *stringUrl = video.stringurl;
NSURL *vidURL = [NSURL fileURLWithPath:stringUrl];

AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:vidURL 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];
UIImage *thumbnail = [UIImage imageWithCGImage:imgRef];
Bhavin
  • 27,155
  • 11
  • 55
  • 94
  • 1
    Thank you but I already have an AVPlayer, not a MPMoviePlayer – Anna565 Sep 09 '13 at 13:29
  • 1
    @Anna565 : Check **Update** in my Answer. – Bhavin Sep 09 '13 at 13:34
  • 1
    I know how I can extract a thumbnail from an AVPlayer, the problem is that the method that I use sometimes works but sometimes gives an error. This is the problem – Anna565 Sep 09 '13 at 13:40
  • 1
    @Anna565 : Check Last Line in my Answer. – Bhavin Sep 09 '13 at 13:50
  • 1
    Yes but if a use fileURLWithPath: instead of URLWithString: the method add to the end of the url an "-- file://localhost/" that invalidates the url. – Anna565 Sep 09 '13 at 13:59
  • 1
    @Anna565 Same problem with the error. I use AVPlayer and some thumbnails does not work and create this error. Did you find out why Anna? – Sam May 22 '16 at 11:40
4

I'm trying as well to grab a screenshot from an HLS variable bitrate stream, I.E. M3U8, and none of the methods provided here worked for me.

I did succeed at the end. First you need to attach an AVPlayerItemVideoOutput to your player:

 self.playerAV = [AVPlayer playerWithURL:localURL];

    NSDictionary* settings = @{ (id)kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] };
    AVPlayerItemVideoOutput* output = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:settings];
    [self.playerAV.currentItem addOutput:output];

Now when you wanna grab the screenshot:

  CVPixelBufferRef pixelBuffer = [output copyPixelBufferForItemTime:player.currentTime itemTimeForDisplay:nil];
            CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];

            CIContext *temporaryContext = [CIContext contextWithOptions:nil];
            CGImageRef videoImage = [temporaryContext
                                     createCGImage:ciImage
                                     fromRect:CGRectMake(0, 0,
                                                         CVPixelBufferGetWidth(pixelBuffer),
                                                         CVPixelBufferGetHeight(pixelBuffer))];

            image = [UIImage imageWithCGImage:videoImage];
            image = [image cropImageToSize:maxSize withProportionDiffLargerThan:IMAGE_PROPORTION_DIFF];

            if ( videoImage )
            {
                CGImageRelease(videoImage);
            }
Vaiden
  • 15,728
  • 7
  • 61
  • 91
3

AVAssetImageGenerator does not work for HSL videos.

I was able to get an image from the HSL video using the sample code below.

Sample code :

CMTime currentTime = _player.currentItem.currentTime;
CVPixelBufferRef buffer = [_videoOutput copyPixelBufferForItemTime:currentTime itemTimeForDisplay:nil];
CIImage *ciImage = [CIImage imageWithCVPixelBuffer:buffer];
UIImage *thumbImage = [UIImage imageWithCIImage:ciImage];
hooni
  • 249
  • 3
  • 9
2

on one of my app i've captured an image from the video url like this:

MPMoviePlayerController *player = [[[MPMoviePlayerController alloc] initWithContentURL:videoURL]autorelease];
UIImage  *thumbnail = [player thumbnailImageAtTime:0.0 timeOption:MPMovieTimeOptionNearestKeyFrame];

just passing the url object as videoURL and with the use of MPMoviePlayerController i successfully able to have the image all the time. hope you too will be able to do this with this simple code

D-eptdeveloper
  • 2,430
  • 1
  • 16
  • 30
2

If you are using AVPlayer, you can get the thumbnail like this:

AVAsset *asset = [AVAsset assetWithURL:sourceURL];
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset];
CMTime time = CMTimeMake(1, 1);
CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL];
UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);  // CGImageRef won't be released by ARC
John Riselvato
  • 12,854
  • 5
  • 62
  • 89
1

I was able to solve the same by using the following approach.

Swift 4.1

func createThumbnailForVideo(atURL videoURL: URL , completion : @escaping (UIImage?)->Void) {
    let asset = AVAsset(url: videoURL)
    let assetImgGenerate = AVAssetImageGenerator(asset: asset)
    assetImgGenerate.appliesPreferredTrackTransform = true
    let time = CMTimeMakeWithSeconds(1, preferredTimescale: 60)
    let times = [NSValue(time: time)]
    assetImgGenerate.generateCGImagesAsynchronously(forTimes: times, completionHandler: {  _, image, _, _, _ in
        if let image = image {
            let uiImage = UIImage(cgImage: image)
            completion(uiImage)
        } else {
            completion(nil)
        }
    })
}
Sayooj
  • 375
  • 3
  • 13
  • Thank you!!! this answer has solved similar problem that appear on slow internet connection, but i should to call completion handler in DispatchQueue.main.async – Dmitriy Grachev Jul 22 '20 at 21:02