First frame of a video using AVFoundation - objective-c

I'm trying to get the first frame of a video using the classes in AVFoundation. But it appears to not be getting an image at all.
My code currently looks like this
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:videoPath] options:nil];
AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]];
[videoFrame setImage:image];
The value of video path is /var/mobile/Applications/02F42CBF-D8BD-4155-85F2-8CF1E55B5023/Documents/videos/1334300431637030.mp4 which is definitely a video, since I can play it with MPMoviePlayerViewController. I'm not sure what I'm doing wrong but any suggestions would be helpful.
Thanks.

I solved it. Apparently using [NSURL fileURLWithPath:videoPath] instead of [NSURL URLWithString:videoPath] makes all the difference.

I used null0pointer solution but in some videos I recieved the first frame rotated. To resolve this issue I set to TRUE the appliesPreferredTrackTransform property of AVAssetImageGenerator. And this code looks like this:
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
[imageGenerator setAppliesPreferredTrackTransform:TRUE];
UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]];
[self.imageView setImage:image];

Doing this in Swift 4.0:
// Assumes you have a local `fileURL`
var avAsset = AVURLAsset(url: fileURL, options: nil)
var imageGenerator = AVAssetImageGenerator(asset: avAsset)
imageGenerator.appliesPreferredTrackTransform = true
var thumbnail: UIImage?
do {
thumbnail = try UIImage(cgImage: imageGenerator.copyCGImage(at: CMTime(seconds: 0, preferredTimescale: 1), actualTime: nil))
} catch let e as NSError {
print("Error: \(e.localizedDescription)")
}

Related

Red Eye Correction

To add red eye correction effect, I had followed this link:
How to remove red eye from image in iPhone?
Installed above library via pods. Added following code in my class.
UIImage *redEyeImage = [UIImage imageNamed:#"Userimage"];
if (redEyeImage) {
UIImage *newRemovedRedEyeImage = [redEyeImage redEyeCorrection];
if (newRemovedRedEyeImage) {
imgView.image = newRemovedRedEyeImage;
}
}
but I didn't get the required output. Is there anything I am missing? Or is there any other library to implement this concept. Please suggest.
Thanks!
You could set breakpoints on the lines right after both if statements and then run your app and see if they're being hit (perhaps redEyeImage doesn't exist or newRemovedRedEyeImage doesn't.
Another simple way to check is:
UIImage *redEyeImage;
UIImage *newRemovedRedEyeImage;
redEyeImage = [UIImage imageNamed:#"Userimage"];
if (redEyeImage) {
newRemovedRedEyeImage = [redEyeImage redEyeCorrection];
if (newRemovedRedEyeImage) {
imgView.image = newRemovedRedEyeImage;
}
}
NSLog(#"redEyeImage: %#", (redEyeImage != nil ? #"exists" : #"nil"));
NSLog(#"newRemovedRedEyeImage: %#", (newRemovedRedEyeImage != nil ? #"exists" : #"nil"));
then run this and see what the two logs at the bottom print.
Finally I resolved this issue with following code:
UIImage *img = [UIImage imageNamed:#"images.png"];
CIImage *image = [[CIImage alloc]initWithImage:img];
NSLog(#"after ciimage: %#", kCIImageAutoAdjustEnhance);
NSDictionary *options = [NSDictionary dictionaryWithObject:#"NO" forKey:kCIImageAutoAdjustEnhance];
NSLog(#"options: %#", options);
NSArray *adjustments = [image autoAdjustmentFiltersWithOptions:options];
NSLog(#"adjustments: %# ", adjustments);
for (CIFilter * filter in adjustments)
{
[filter setValue:image forKey:kCIInputImageKey];
image = filter.outputImage;
}
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgImage = [context createCGImage:image fromRect:image.extent];
UIImage *enhancedImage = [[UIImage alloc] initWithCGImage:cgImage];
CGImageRelease(cgImage);
self.img.image = enhancedImage;

NSURL of UIImage from UIImagePickerController returns (null)

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editInfo {
userURL = [editInfo objectForKey:UIImagePickerControllerMediaURL];
userImage = image;
userImageView.image=userImage;
[self dismissViewControllerAnimated:YES completion:nil];}
I then take NSURL userURL, and put it in an UIActivityViewController to use to upload the image. However this never works, and always fails as it's trying to upload (null). However, when I use a preset image included in the xcode project and the following code, it always works and uploads correctly:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"kitten.jpg" withExtension:nil];
If it helps, I'm using https://github.com/goosoftware/GSDropboxActivity
When I use UIImagePickerControllerReferenceURL instead of UIImagePickerControllerMediaURL, I get the following error:
[WARNING] DropboxSDK: File does not exist (/asset.JPG)
Failed to upload assets-library://asset/asset.JPG?id=EECAF4D0-A5ED-40E7-8E6F-3A586C0AB06E&ext=JPG
In theory, UIImagePickerControllerMediaURL is only populated for a movie, not an image. If you use the UIImagePickerControllerReferenceURL then the URL that you're given is not a URL for the file system, but rather the assets library. To get the file from that you'll need to use the asset library. Use something like the following :
typedef void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *asset);
typedef void (^ALAssetsLibraryAccessFailureBlock)(NSError *error);
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset){
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
if (iref){
UIImage *myImage = [UIImage imageWithCGImage:iref scale:[rep scale] orientation:(UIImageOrientation)[rep orientation]];
// Do whatever you now want with your UIImage
}
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror){
//failed to get image.
};
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:[filePath objectAtIndex:0] resultBlock:resultblock failureBlock:failureblock];
This takes care of the blocks that will handle your request, but you still need to actually request the resource from the assets library. For that, try this :
ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease];
NSURL myAssetUrl = [NSURL URLWithString:[editInfo objectForKey:UIImagePickerControllerMediaURL]];
[assetslibrary assetForURL:myAssetUrl resultBlock:resultblock failureBlock:failureblock];
And in theory, you should get what you're after :)
The code for this was given by Ramshad and further discussion of it can be found here
Hopefully this will help you with what you're after. Sorry if it's a bit too late :(
Edit
Note that if you're not using ARC, you'll need to tidy up the memory in this example as I haven't included any memory management at all.

Issue on capture screenshot of video

i want to take a screenshot of a video on my ipad app.
I searched on SO, and i found a lot of sample code. I tried everything but nothing seem to work.
I tried all of this methods:
1) Try with : MPMoviePlayerController
- (void) previewWithPlayer:(NSString*)path image:(UIImageView*)imView
{
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:path]];
UIImage *thumbnail = [player thumbnailImageAtTime:1.0 timeOption:MPMovieTimeOptionNearestKeyFrame];
[player stop];
[player release];
imView.image = thumbnail;
}
2) Try with : AVAssetImageGenerator - v1
- (void) generateImage:(NSString*)path image:(UIImageView*)imView
{
AVAsset *asset = [AVAsset assetWithURL:[NSURL URLWithString:path]];
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset];
CMTime time = CMTimeMake(1, 1);
UIImage *thumbnail = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL]];
imView.image = thumbnail;
}
13) Try with : AVAssetImageGenerator - v2
- (void) generateImage:(NSString*)path image:(UIImageView*)imView
{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL URLWithString:path] options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform=TRUE;
[asset release];
CMTime thumbTime = CMTimeMakeWithSeconds(2,30);
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){
if (result != AVAssetImageGeneratorSucceeded) {
NSLog(#"couldn't generate thumbnail, error:%#", error);
}
UIImage *thumbImg = [[UIImage imageWithCGImage:im] retain];
imView.image = thumbImg;
[generator release];
};
CGSize maxSize = CGSizeMake(320, 180);
generator.maximumSize = maxSize;
[generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];
}
But nothig works.
I tried with MOV, MP4, nothing.
Path is correct, video is working.
NSString *fPath = [[NSBundle mainBundle] pathForResource:#"VideoA" ofType:#"mp4"];
NSLog(#"%#", fPath);
[self generateImage:fPath image:_ImgA];
What's could be the problem? My image view show nothing and no error are returned.
iOS is 6.0/5.1, on iPad simulator/device.
Video is 854×480 pixels, H.264, AAC. About 30Mb of size.
please help me because i'm going crazy with this issue.
thanks.
edit
on device return this error:
couldn't generate thumbnail, error:Error Domain=NSURLErrorDomain
Code=-1 "unknown error" UserInfo=0x1e0a2f30
{NSUnderlyingError=0x1e0a3900 "The operation couldn’t be completed.
(OSStatus error -12935.)", NSLocalizedDescription=unknown error}
Solved.
The trick: use fileURLWithPath:, not URLWithString:. Apparently the difference is really, really significant.
thanks to Noah. https://stackoverflow.com/a/4201419/88461

Loading an image from a URL but displaying it progressively

I have a screen that will load around 5 images, but they are huge images. Right now I use a
NSURLRequest
and a:
connectionDidFinishLoading
..for callback to tell me when each image is loaded.
The problem is that images would pop up one by one. Is there a way to have it display the image while it loads?
Thanks
The guts of what you need to do this are available as CGImageSource methods.
First, you use an asynchronous NSURLConnection to get the data. You add received data to a NSMutableData object as it arrives, so the data object gets bigger and bigger til finished.
You also create a progressive image source:
CGImageSourceRef imageSourcRef = CGImageSourceCreateIncremental(dict);
You will find lots of examples here and on google how to set the dictionary required.
Then as the data arrives, you pass the TOTAL data object into this method:
CGImageSourceUpdateData(imageSourcRef, (__bridge CFDataRef)data, NO); // No means not finished
You can then ask the image source for an image, which will be partial as the image is downloading. With a CGImage you can create a UIImage.
When you get the final data, you update the image source on last time:
CGImageSourceUpdateData(imageSourcRef, (__bridge CFDataRef)data, YES);
You then use the image source to get a final image and you're done.
Displaying it while loading ,I don't think UIImageView can load UIImageswith incomplete data while loading.I will go for
AsyncImageView ,
It can deal with all the burden of loading image asynchronous.Also UIActivityIndicator is already added to it.So it will be more user friendly
Use blocks and GCD's dispatch_async method.
Look at this example:
//communityDetailViewController.h
#interface communityDetailViewController : UIViewController {
UIImageView *imgDisplay;
UIActivityIndicatorView *activity;
// the dispatch queue to load images
dispatch_queue_t queue;
}
#end
//communityDetailViewController.m
- (void)loadImage
{
[activity startAnimating];
NSString *url = #"URL the image";
if (!queue) {
queue = dispatch_queue_create("image_queue", NULL);
}
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *anImage = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
[activity stopAnimating];
activity.hidden = YES;
if (anImage != nil) {
[imgDisplay setImage:anImage];
}else{
[imgDisplay setImage:[UIImage imageNamed:#"no_image_available.png"]];
}
});
});
}
You can subclass UIImageView and use this.
-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
imageData = [NSMutableData data];
imageSize = [response expectedContentLength];
imageSource = CGImageSourceCreateIncremental(NULL);
}
-(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
[imageData appendData:data];
CGImageSourceUpdateData(imageSource, (__bridge CFDataRef)imageData, ([imageData length] == imageSize) ? true : false);
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
if (cgImage){
UIImage* img = [[UIImage alloc] initWithCGImage:cgImage scale:1.0f orientation:UIImageOrientationUp];
dispatch_async( dispatch_get_main_queue(), ^{
self.image = img;
});
CGImageRelease(cgImage);
}
}

Create a UIImage with a URL in iOS

To create an UiImage with a image file, I use the code as below:
UIImage *aImage = [[UIImage imageNamed:#"demo.jpg"]autorelease];
If I want to create an UiImage with the URL http://example.com/demo.jpg, how to do that?
Thanks
UPDATE
This is a three step process. First you will create an NSURL object to hold the URL we are attempting to access. We will supply this URL to the NSData class method, +dataWithContentsOfURL: to obtain the image over the network as raw data, then use the +imageWithData: class method on UIImage to convert the data into an image.
NSURL *imageURL = [NSURL URLWithString:#"http://example.com/demo.jpg"];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
Please note that +dataWithContentsOfURL: executes a synchronous network request. If you run this on the main thread, it will block the UI until the image data is received from the network. Best practice is to run any network code on a background thread. If you're targeting OS 4.0+ you could do something like this...
NSURL *imageURL = [NSURL URLWithString:#"http://example.com/demo.jpg"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
self.imageView.image = [UIImage imageWithData:imageData];
});
});
Here's what the same code might look like in Swift:
let image_url = NSURL("http://i.imgur.com/3yY2qdu.jpg")
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
// do some task
let image_data = NSData(contentsOfURL: image_url!)
dispatch_async(dispatch_get_main_queue()) {
// update some UI
let image = UIImage(data: image_data!)
self.imageView.image = image
}
}
For anyone looking to load image from the web the following library may be helpful:
https://github.com/rs/SDWebImage
It's a UIImageView category which handles async loading and image caching from url.