Why AVAssetImageGenerator generateCGImagesAsynchronouslyForTimes crashes the app - ios

I am trying to extract 2 frames per second from a video using generateCGImagesAsynchronouslyForTimes. But my app crashes. I am monitoring the memory usage but its not going any way up than 14 mb.
Here is the code:
- (void) createImagesFromVideoURL:(NSURL *) videoUrl atFPS: (int) reqiuredFPS completionBlock: (void(^) (NSMutableArray *frames, CGSize frameSize)) block
{
NSMutableArray *requiredFrames = [[NSMutableArray alloc] init];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.requestedTimeToleranceAfter = kCMTimeZero;
generator.requestedTimeToleranceBefore = kCMTimeZero;
generator.appliesPreferredTrackTransform = YES;
UIImage *sampleGeneratedImage;
for (Float64 i = 0; i < CMTimeGetSeconds(asset.duration) * reqiuredFPS ; i++)
{
CMTime time = CMTimeMake(i, reqiuredFPS);
NSError *err;
CMTime actualTime;
CGImageRef image = [generator copyCGImageAtTime:time actualTime:&actualTime error:&err];
if (! err)
{
sampleGeneratedImage = [[UIImage alloc] initWithCGImage:image];
break;
}
}
//Get the maximum size from 1 frame
generator.maximumSize = [self getMultipleOf16AspectRatioForCurrentFrameSize:sampleGeneratedImage.size];
NSMutableArray *requestedFrameTimes = [[NSMutableArray alloc] init];
for (Float64 i = 0; i < CMTimeGetSeconds(asset.duration) * reqiuredFPS ; i++)
{
CMTime time = CMTimeMake(i, reqiuredFPS);
[requestedFrameTimes addObject:[NSValue valueWithCMTime:time]];
}
[generator generateCGImagesAsynchronouslyForTimes:[requestedFrameTimes copy] completionHandler:^(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
if (image)
{
UIImage *generatedImage = [UIImage imageWithCGImage:image];
[requiredFrames addObject:generatedImage];
}
if (CMTimeCompare(requestedTime, [[requestedFrameTimes lastObject] CMTimeValue]) == 0)
{
NSLog(#"Image processing complete");
dispatch_async(dispatch_get_main_queue(), ^{
block(requiredFrames, generator.maximumSize);
});
}
else
{
NSLog(#"Getting frame at %lld", actualTime.value/actualTime.timescale);
}
}];
}

Related

Not getting the value in asset when loading the video from gallery using ALAssetLibrary

I want to display the thumbnail of videos by using ALAssetLibrary and for displaying the video from gallery to my app , i filtered all videos from ALAssetsFilter .
But still i am getting the null value in asset of type ALAsset.
Please tell me what i am doing wrong with my code.
Appreciate for the help.
-(void)loadAssets{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group setAssetsFilter:[ALAssetsFilter allVideos]];
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *asset, NSUInteger index, BOOL *innerStop) {
if (asset)
{
dic = [[NSMutableDictionary alloc] init];
ALAssetRepresentation *defaultRepresentation = [asset defaultRepresentation];
NSString *uti = [defaultRepresentation UTI];
videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
NSString *title = [NSString stringWithFormat:#"video %d", arc4random()%100];
UIImage *image = [self imageFromVideoURL:videoURL];
[dic setValue:image forKey:#"image"];
[dic setValue:title forKey:#"name"];
[dic setValue:videoURL forKey:#"url"];
[allVideos addObject:asset];
}
}];
[_collectionView reloadData];
}
failureBlock:^(NSError *error)
{
NSLog(#"error enumerating AssetLibrary groups %#\n", error);
}];
}
- (UIImage *)imageFromVideoURL:(NSURL*)videoURL
{
UIImage *image = nil;
AVAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];;
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
imageGenerator.appliesPreferredTrackTransform = YES;
// calc midpoint time of video
Float64 durationSeconds = CMTimeGetSeconds([asset duration]);
CMTime midpoint = CMTimeMakeWithSeconds(durationSeconds/2.0, 600);
// get the image from
NSError *error = nil;
CMTime actualTime;
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:midpoint actualTime:&actualTime error:&error];
if (halfWayImage != NULL)
{
// cgimage to uiimage
image = [[UIImage alloc] initWithCGImage:halfWayImage];
[dic setValue:image forKey:#"ImageThumbnail"];//kImage
NSLog(#"Values of dictonary==>%#", dic);
NSLog(#"Videos Are:%#",allVideos);
CGImageRelease(halfWayImage);
}
return image;
}
Use this code may this will help you to generate thumbnail image-- -
-(UIImage*)loadImage {
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:self.videoURL options:nil];
AVAssetImageGenerator *generate = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generate.appliesPreferredTrackTransform = YES;
NSError *err = NULL;
CMTime time = CMTimeMake(1, 60);
CGImageRef imgRef = [generate copyCGImageAtTime:time actualTime:NULL error:&err];
return [[UIImage alloc] initWithCGImage:imgRef];
}
I have Create the Thumbnail image from Video, its working for me and the code is below,
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSLog(#"store url %#",videoURL);
AVAsset *avAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
if ([[avAsset tracksWithMediaType:AVMediaTypeVideo] count] > 0)
{
AVAssetImageGenerator *imageGenerator =[AVAssetImageGenerator assetImageGeneratorWithAsset:avAsset];
Float64 durationSeconds = CMTimeGetSeconds([avAsset duration]);
CMTime midpoint = CMTimeMakeWithSeconds(durationSeconds/2.0, 600);
NSError *error;
CMTime actualTime;
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:kCMTimeZero actualTime:&actualTime error:&error];
if (halfWayImage != NULL)
{
NSString *actualTimeString = (NSString *)CFBridgingRelease(CMTimeCopyDescription(NULL, actualTime));
NSString *requestedTimeString = (NSString *)CFBridgingRelease(CMTimeCopyDescription(NULL, midpoint));
NSLog(#"Got halfWayImage: Asked for %#, got %#", requestedTimeString, actualTimeString);
UIImage *img=[UIImage imageWithCGImage:halfWayImage];
playButton.hidden=NO;
self.myimageView.image= img; //[self scaleImage:img maxWidth:(img.size.width/5) maxHeight:(img.size.height/5)];
}
}
Finally got the thumbnail image, hope its helpful

Objective-C: Getting PNG Thumbnail from Movie with NSData

I have the following code to attempt to get a screenshot of a video file from NSData. I can confirm the NSData is valid and not nil, however both dataString and movieURL are returning nil.
- (UIImage *)imageFromMovie:(NSData *)movieData {
// set up the movie player
NSString *dataString = [[NSString alloc] initWithData:movieData encoding:NSUTF8StringEncoding];
NSURL *movieURL = [NSURL URLWithString:dataString];
// get the thumbnail
AVURLAsset *asset1 = [[AVURLAsset alloc] initWithURL:movieURL 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];
return(one);
}
EDIT: Here's a look at where/how I'm getting the NSData from the UIImagePicker
if ([mediaType isEqualToString:#"ALAssetTypeVideo"]) {
ALAssetsLibrary *assetLibrary=[[ALAssetsLibrary alloc] init];
[assetLibrary assetForURL:[[info objectAtIndex:x] valueForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *rep = [asset defaultRepresentation];
unsigned long DataSize = (unsigned long)[rep size];
Byte *buffer = (Byte*)malloc(DataSize);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:DataSize error:nil];
//here’s the NSData
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
} failureBlock:^(NSError *err) {
NSLog(#"Error: %#",[err localizedDescription]);
}];
}
Possible, you have problems with encoding.
NSString instance method -(id)initWithData:data:encoding returns nil if data does not represent valid data for encoding.(https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/occ/instm/NSString/initWithData:encoding:)
Try to use correct encoding in -(id)initWithData:data:encoding method.
You are trying to convert the movie data to NSURL, that's why you are getting a nil url.
In your implementation, you can get the thumbnail in the following way:
AVURLAsset *asset1 = [[AVURLAsset alloc] initWithURL:[[info objectAtIndex:x] valueForKey:UIImagePickerControllerReferenceURL] 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];
Download my sample project before reading this answer from:
https://drive.google.com/open?id=0B_exgT43OZJOWl9HMDJCR0cyTW8
I know it's been a really long time since you posted this question; but, I found it, can answer it, and am reasonably confident that, unless you used the sample code provided by the Apple Developer Connection web site that does what you're asking, you still need answer. I base that solely on this fact: it's hard to figure out.
Nonetheless, I have a basic, working project that addresses your question; however, before looking at it, check out a video I made of it running on my iPhone 6s Plus:
<iframe width="640" height="360" src="https://www.youtube.com/embed/GiF-FFKvy5M?rel=0&controls=0&showinfo=0" frameborder="0" allowfullscreen></iframe>
As you can see, the poster frame for every asset in my iPhone's video collection is displayed in UICollectionViewCell; in the UICollectionViewController (or the UICollectionView / datasource delegate:
void (^renderThumbnail)(NSIndexPath *, CustomCell *) = ^(NSIndexPath *indexPath, CustomCell *cell) {
[[PHImageManager defaultManager] requestAVAssetForVideo:AppDelegate.assetsFetchResults[indexPath.section] options:nil resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
cell.asset = [asset copy];
cell.frameTime = [NSValue valueWithCMTime:kCMTimeZero];
}];
};
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PHAsset *phAsset = AppDelegate.assetsFetchResults[indexPath.section];
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellReuseIdentifier forIndexPath:indexPath];
cell.representedAssetIdentifier = phAsset.localIdentifier;
CGFloat hue = (CGFloat)indexPath.section / 5;
cell.backgroundColor = [UIColor colorWithHue:hue saturation:1.0f brightness:0.5f alpha:1.0f];
if ([cell.representedAssetIdentifier isEqualToString:phAsset.localIdentifier]) {
NSPurgeableData *data = [self.thumbnailCache objectForKey:phAsset.localIdentifier];
[data beginContentAccess];
UIImage *image = [UIImage imageWithData:data];
if (image != nil) {
cell.contentView.layer.contents = (__bridge id)image.CGImage;
NSLog(#"Cached image found");
} else {
renderThumbnail(indexPath, cell);
}
[data endContentAccess];
[data discardContentIfPossible];
}
// Request an image for the asset from the PHCachingImageManager.
/*[AppDelegate.imageManager requestImageForAsset:phAsset
targetSize:cell.contentView.bounds.size
contentMode:PHImageContentModeAspectFill
options:nil
resultHandler:^(UIImage *result, NSDictionary *info) {
// Set the cell's thumbnail image if it's still showing the same asset.
if ([cell.representedAssetIdentifier isEqualToString:phAsset.localIdentifier]) {
cell.thumbnailImage = result;
}
}];*/
return cell;
}
In the UICollectionViewCell subclass:
#implementation CustomCell
- (void)prepareForReuse {
[super prepareForReuse];
_asset = nil;
_frameTime = nil;
_thumbnailImage = nil;
[self.contentView.layer setContents:nil];
[[self contentView] setContentMode:UIViewContentModeScaleAspectFit];
[[self contentView] setClipsToBounds:YES];
}
- (void)dealloc {
}
- (void)setAsset:(AVAsset *)asset {
_asset = asset;
}
- (void)setFrameTime:(NSValue *)frameTime {
_frameTime = frameTime;
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(concurrentQueue, ^{
AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_asset];
imageGenerator.appliesPreferredTrackTransform = YES;
imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
[imageGenerator generateCGImagesAsynchronouslyForTimes:#[frameTime] completionHandler:^(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
dispatch_sync(dispatch_get_main_queue(), ^{
self.thumbnailImage = [UIImage imageWithCGImage:image scale:25.0 orientation:UIImageOrientationUp];
});
}];
});
}
- (void)setThumbnailImage:(UIImage *)thumbnailImage {
_thumbnailImage = thumbnailImage;
self.contentView.layer.contents = (__bridge id)_thumbnailImage.CGImage;
}
#end
The NSCache is set up like this:
self.thumbnailCache = [[NSCache alloc] init];
self.thumbnailCache.name = #"Thumbnail Cache";
self.thumbnailCache.delegate = self;
self.thumbnailCache.evictsObjectsWithDiscardedContent = true;
self.thumbnailCache.countLimit = AppDelegate.assetsFetchResults.count;
The PHAssets were acquired this way:
- (PHFetchResult *)assetsFetchResults {
__block PHFetchResult *i = self->_assetsFetchResults;
if (!i) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumVideos options:nil];
self->_assetCollection = smartAlbums.firstObject;
if (![self->_assetCollection isKindOfClass:[PHAssetCollection class]]) self->_assetCollection = nil;
PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
allPhotosOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
i = [PHAsset fetchAssetsInAssetCollection:self->_assetCollection options:allPhotosOptions];
self->_assetsFetchResults = i;
});
}
return i;
}

Video thumbnail does not appear in collection view

self.url = [self grabFileURL:#"video.mov"];
NSLog(#"The URL is: %#", self.url);
AVURLAsset *asset1 = [[AVURLAsset alloc] initWithURL:self.url 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];
CaptureViewController *cv = [[CaptureViewController alloc]init];
[cv.thumbnail setImage:one];
NSLog(#"The thumbnail is: %#", one);
one = [UIImage imageNamed:#"vid.png"];
videoGallery = [NSArray arrayWithObjects:#"vid.png", nil];
Edit:
- (NSURL*)grabFileURL:(NSString *)fileName {
// find Documents directory
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
// append a file name to it
documentsURL = [documentsURL URLByAppendingPathComponent:fileName];
return documentsURL;
}
No output error in NSLog but the thumbnail still doesn't show up in collection view controller. What have I missed ?
-(void)generateImageForImageView:(UIImageView *) imageView withURL:(NSString *) VideoURL
{
NSURL *url = [NSURL URLWithString:VideoURL];
AVURLAsset *asset1 = [[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator *generate1 = [[AVAssetImageGenerator alloc] initWithAsset:asset1];
generate1.appliesPreferredTrackTransform = YES;
NSError *err = NULL;
CMTime time = [asset1 duration];
time.value = 0;
CGImageRef oneRef = [generate1 copyCGImageAtTime:time actualTime:NULL error:&err];
UIImage *one = [[UIImage alloc] initWithCGImage:oneRef];
[imageView setImage:one];
imageView.contentMode = UIViewContentModeScaleToFill;
}
use this method hope it will be useful to you, its work for me

Extraction Video frames with Av foundation

i use this method to generate the frames of the video
-(NSMutableArray *)generateThumbnailsFromUrl:(NSURL *)videoURl{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURl options:nil];
Float64 durationFrames = CMTimeGetSeconds([asset duration]) * 30.0;
AVMutableComposition *myComp = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [myComp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error = nil;
BOOL ok = NO;
CGImageRef imgRef;
UIImage *currentImg;
CMTime time,startTime,endTime;
CMTimeRange myRange;
AVAssetTrack *sourceVideoTrack;
NSMutableArray* frameArray = [[NSMutableArray alloc] init];
AVAssetImageGenerator *generate = [[AVAssetImageGenerator alloc] initWithAsset:myComp];
#try {
for (int i = 0; i < floor(durationFrames); i++) {
startTime = CMTimeMake(i, 30);
endTime = CMTimeMake(i+1, 30);
myRange = CMTimeRangeMake(startTime, endTime);
sourceVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
ok = [compositionVideoTrack insertTimeRange:myRange ofTrack:sourceVideoTrack atTime:kCMTimeZero error:&error];
if (!ok) {
// Deal with the error.
NSLog(#"error %# on %d",error,i);
}else{
time = CMTimeMake(0,1);
imgRef = [generate copyCGImageAtTime:time actualTime:NULL error:&error];
if(imgRef != nil)
{
currentImg = [[UIImage alloc] initWithCGImage:imgRef];
if(currentImg!=nil)
[frameArray addObject:currentImg];
}
}
currentImg=nil;
CGImageRelease(imgRef);
ok=NO;
}
}
#catch (NSException *exception) {
NSLog(#"exption is %#",exception);
}
return frameArray;}
but i have a serious problem in this line exactly imgRef = [generate copyCGImageAtTime:time actualTime:NULL error:&error];
sometimes in the middle of execution freeze here , without exception , result and without continue execution !
anyone can help me or explain to me the problem ?
and is there is a way to check if the execution of the command is more a specific time and kill that command ?
According to this solution
you could
[imageGenerator generateCGImagesAsynchronouslyForTimes:times completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
if (result == AVAssetImageGeneratorSucceeded)
{
UIImage *generatedImage = [[UIImage alloc] initWithCGImage:image];
[imagesArray addObject:generatedImage];
}
}];

Getting a thumbnail of a *.mov video IOS

I want to get a thumbnail of videos (*.mov) which taken with iPhone/iPAD. I am trying to use AVFoundation library for this and getting this error:
couldn't generate thumbnail, error:Error Domain=AVFoundationErrorDomain Code=-11822 "Cannot Open" UserInfo=0x15d90a30 {NSLocalizedDescription=Cannot Open, NSLocalizedFailureReason=This media format is not supported.}
Code:
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir=[paths objectAtIndex:0];
NSString *videoPath=[documentDir stringByAppendingPathComponent:[NSString stringWithFormat:#"videos/%#.mov",videoName]];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:videoPath options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform=TRUE;
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);
}
self.img.image=[UIImage imageWithCGImage:im];
};
CGSize maxSize = CGSizeMake(320, 180);
generator.maximumSize = maxSize;
[generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];
I recorded videos with my app and want to show a thumbnail of them.
Here it is... (Picked up from this link- Getting video snapshot for thumbnail)
- (UIImage *)thumbnailImageFromURL:(NSURL *)videoURL {
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL: videoURL options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
NSError *err = NULL;
CMTime requestedTime = CMTimeMake(1, 60); // To create thumbnail image
CGImageRef imgRef = [generator copyCGImageAtTime:requestedTime actualTime:NULL error:&err];
NSLog(#"err = %#, imageRef = %#", err, imgRef);
UIImage *thumbnailImage = [[UIImage alloc] initWithCGImage:imgRef];
CGImageRelease(imgRef); // MUST release explicitly to avoid memory leak
return thumbnailImage;
}
I don't have enough reputation to comment but the example above is missing CGImageRelease(imageRef)...
The final methode should look like:
- (UIImage*)loadImage {
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:vidURL options:nil];
AVAssetImageGenerator *generate = [[AVAssetImageGenerator alloc] initWithAsset:asset];
NSError *err = NULL;
CMTime time = CMTimeMake(1, 60);
//Grab image
CGImageRef imgRef = [generate copyCGImageAtTime:time actualTime:NULL error:&err];
NSLog(#"err==%#, imageRef==%#", err, imgRef);
UIImage* finalImage = [[UIImage alloc] initWithCGImage:imgRef];
CGImageRelease(imageRef);
return finalImage;
}
Took me while to realize... So maybe it will help somebody.
You can generate in swift in two ways 1. AVAssetImageGenerator 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)")
}
}
You need to check if each video segment is empty in video track.
+ (UIImage*)getVideoPreViewImage:(AVAsset *)asset atTimeSec:(double)timeSec
{
if (!asset) {
return nil;
}
AVAssetTrack *videoTrack = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;
NSArray<AVAssetTrackSegment *> *segs = videoTrack.segments;
if (!segs.count) {
return nil;
}
CMTime currentStartTime = kCMTimeZero;
for (NSInteger i = 0; i < segs.count; i ++) {
if (!segs[i].isEmpty) {
currentStartTime = segs[i].timeMapping.target.start;
break;
}
}
CMTime coverAtTimeSec = CMTimeMakeWithSeconds(timeSec, asset.duration.timescale);
if (CMTimeCompare(coverAtTimeSec, asset.duration) == 1 || CMTimeCompare(coverAtTimeSec, currentStartTime) == -1) {
coverAtTimeSec = currentStartTime;
}
AVAssetImageGenerator *assetGen = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
assetGen.requestedTimeToleranceBefore = kCMTimeZero;
assetGen.requestedTimeToleranceAfter = kCMTimeZero;
assetGen.appliesPreferredTrackTransform = YES;
NSError *error = nil;
CGImageRef image = [assetGen copyCGImageAtTime:coverAtTimeSec actualTime:NULL error:&error];
if (error) {
return nil;
}
UIImage *videoImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);
return videoImage;
}

Resources