11

I'm playing Video using AVPlayerLayer in a View. I need to convert View to Image, I tried

[myview.layer renderInContext:context];

but this gives only black image. I wanna convert that view into image with video on that time. This conversion will occur simultaneously 0.05s.

I tried with AVAssetImageGenerator. Which gives me the right image using Asset. But it taking little more time which makes some performance issue on my application. Can any one help me how to reduce the process of converting video to image for particular CMTime.

Below are my coding.

- (UIImage *)currentItemScreenShot
{
    AVPlayer *abovePlayer = [objVC player];
    if(imageGenerator == nil)
    {
        AVAsset *asset = [[[objVC player] currentItem] asset];
        imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    }

    CMTime time = [[abovePlayer currentItem] currentTime];
    if ([imageGenerator respondsToSelector:@selector(setRequestedTimeToleranceBefore:)] && [imageGenerator respondsToSelector:@selector(setRequestedTimeToleranceAfter:)]) {
        [imageGenerator setRequestedTimeToleranceBefore:kCMTimeZero];
        [imageGenerator setRequestedTimeToleranceAfter:kCMTimeZero];
    }

    CGImageRef imgRef = [imageGenerator copyCGImageAtTime:time
                                               actualTime:NULL
                                                    error:NULL];
    if (imgRef == nil) {
        if ([imageGenerator respondsToSelector:@selector(setRequestedTimeToleranceBefore:)] && [imageGenerator respondsToSelector:@selector(setRequestedTimeToleranceAfter:)]) {
            [imageGenerator setRequestedTimeToleranceBefore:kCMTimePositiveInfinity];
            [imageGenerator setRequestedTimeToleranceAfter:kCMTimePositiveInfinity];
        }
        imgRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL];
    }
    UIImage *image = [UIImage imageWithCGImage:imgRef];
    CGImageRelease(imgRef);

    image = [self reverseImageByScalingToSize:image.size :image];
    return image;
}
Ganesh
  • 819
  • 3
  • 13
  • 27

7 Answers7

5

The MPMoviePlayerController makes it easy to get a image from a movie at a certain point in the movie.

    - (UIImage*)imageFromVideoAtPath:(NSString *)path atTime:(NSTimeInterval)time {
    NSURL *videoURL = [NSURL fileURLWithPath:path];
    MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];
    [moviePlayer prepareToPlay];
    UIImage *thumbnail = [moviePlayer thumbnailImageAtTime:time timeOption:MPMovieTimeOptionNearestKeyFrame];
    [moviePlayer stop];
    return thumbnail;
}

Just call this with the path of the video, and at the time you want to get the image.

Maximilian Litteral
  • 3,059
  • 2
  • 31
  • 41
3

Please try below code. It is working perfectly for me.

And refer UIKit Function Reference.

+ (UIImage *) imageWithView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return img;
}

Also try this.

Chetan Bhalara
  • 10,326
  • 6
  • 32
  • 51
  • I tried the same but the img is Black and blank. In your case did you used avplayerlayer on your view? – Ganesh Jan 11 '13 at 10:30
2

you can save your UIView as Image in Document Diretory like:

-(IBAction)ViewTOimage:(id)sender
{


    UIGraphicsBeginImageContext(self.view.bounds.size); //instad of self.view you can set your view IBOutlet name 
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *saveImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
    NSData *imageData = UIImagePNGRepresentation(saveImage);
    NSFileManager *fileMan = [NSFileManager defaultManager];

    NSString *fileName = [NSString stringWithFormat:@"%d.png",1];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
    [fileMan createFileAtPath:pdfFileName contents:imageData attributes:nil];



}
Nitin Gohel
  • 49,482
  • 17
  • 105
  • 144
2

This Code Useful when user want to capture current view ScreenShot and share or save this image....

- (UIImage *)captureView {

//hide controls if needed
    CGRect rect = [self.view bounds];

    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [self.view.layer renderInContext:context];   
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;

}

See my this Answer Also.... My Answer

UPDATE:

AVPlayerItem *item = [AVPlayerItem playerItemWithURL:yourURL];
AVPlayer *player = [AVPlayer playerWithPlayerItem:pItem];

//observe 'status'
[playerItem addObserver:self forKeyPath:@"status" options:0 context:nil];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context
{ 
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItem *item = (AVPlayerItem *)object;
        if (item.status == AVPlayerItemStatusReadyToPlay) {
            AVURLAsset *asset = (AVURLAsset *)item.asset;
            AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
            CGImageRef thumb = [imageGenerator copyCGImageAtTime:CMTimeMakeWithSeconds(10.0, 1.0)
                                                      actualTime:NULL
                                                           error:NULL];
        }
    }   
}
Community
  • 1
  • 1
Paras Joshi
  • 20,427
  • 11
  • 57
  • 70
  • I'm using AVPlayerLayer in this View. If I try to convert that View to image, gives me black image. Did you tried with AVPlayerLayer with that view? – Ganesh Jan 11 '13 at 10:40
  • yes is there prob i tested with my answer and your in AVSimpleEditoriOS demo image capture only Avplayer blackScreen,,( – Nitin Gohel Jan 11 '13 at 10:43
  • @Ganesh see this answer dude http://stackoverflow.com/questions/13046936/avplayerlayer-get-image-to-uiimageview-buffer after let me know that u get it or not?? – Paras Joshi Jan 11 '13 at 10:54
  • @ParasJoshi Ok I will try with this,and let you know. – Ganesh Jan 11 '13 at 10:57
  • 1
    @ParasJoshi copyNextSampleBuffer does not work. It always give nil values – Ganesh Jan 11 '13 at 11:08
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/22575/discussion-between-ganesh-and-paras-joshi) – Ganesh Jan 11 '13 at 11:38
2
-(UIImage *)imagefromview {
    UIGraphicsBeginImageContext(view.frame.size);
    [[self imageFromView:view] drawInRect:view.frame];
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultingImage;
}
Amit Battan
  • 2,968
  • 2
  • 32
  • 68
2

I one of the project i used the below code to take an image from playing video might this help you too... take a look and try adjusting the code with your's.

#import <AVFoundation/AVFoundation.h>

@property (nonatomic,retain) AVCaptureStillImageOutput * resultImageOutput;

- (UIImage*)stillImageFromVideo
{  
    AVCaptureConnection *videoConnection = nil;
    for (AVCaptureConnection *connection in [[self resultImageOutput] connections]) {
        for (AVCaptureInputPort *port in [connection inputPorts]) {
            if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
                videoConnection = connection;
                break;
            }
        }
        if (videoConnection) { 
            break; 
        }
    }

    [[self resultImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
    completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 
         CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer,   
   kCGImagePropertyExifDictionary, NULL);

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];    
        UIImage *image = [[UIImage alloc] initWithData:imageData];
        return image;  
    }
}
Miknash
  • 7,888
  • 3
  • 34
  • 46
spider1983
  • 1,098
  • 1
  • 7
  • 14
2

Try taking a screenshot and clipping. Otherwise you may have to render view and all its subviews recursively.

-(UIImage *)videoScreenCap:(CGRect)cropRect{
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
    UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, [UIScreen mainScreen].scale);
else
    UIGraphicsBeginImageContext(self.window.bounds.size);
    [self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData * data = UIImagePNGRepresentation(image);
    [data writeToFile:@"foo.png" atomically:YES];
CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect);
UIImage * img = [UIImage imageWithCGImage:imageRef]; 
CGImageRelease(imageRef);
return img;
}
Omar
  • 463
  • 3
  • 11
  • I don't want to capture over all window. I just need to capture particular View, which contains AVPlayerLayer as Sublayer. When I render view.layer in a contextref video screen is black. – Ganesh Jan 22 '13 at 03:33