Objective c - picker to get video path - objective-c

In my app, I allow the user to record videos and I save them in this path:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths[0] stringByAppendingPathComponent:DestFileName];
I want to implement a video picker in my app, but the objective is to get the path of the video. I started with the basic method like this:
UIImagePickerController *videoPicker = [[UIImagePickerController alloc] init];
videoPicker.delegate = self;
videoPicker.modalPresentationStyle = UIModalPresentationCurrentContext;
videoPicker.mediaTypes =[UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];‌​
videoPicker.mediaTypes = #[(NSString*)kUTTypeMovie, (NSString*)kUTTypeAVIMovie, (NSString*)kUTTypeVideo, (NSString*)kUTTypeMPEG4];
videoPicker.videoQuality = UIImagePickerControllerQualityTypeHigh;
[self presentViewController:videoPicker animated:YES completion:nil];
The first problem is that I can not access to my recorded videos, why?
Then, this picker allows the user to play video, and when I choose one video I think that a compressed video is created and sent to our delegate method (the URL goes to a tmp repository).
I don't want to allow the user to play video and I just want the video path, is it possible with this method?
I can also get the list of files in
NSSearchPathForDirectoriesInDomains
with this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *rootPath = path[0];
[[NSFileManager defaultManager] createDirectoryAtPath:rooPath withIntermediateDirectories:YES attributes:nil error:nil];
NSArray* mPaths = [[NSFileManager defaultManager] contentOfDirectoryAtPath:rootPath error:nil];
With this method I can found my recorded videos, but then I have to implement my own custom picker, but it can be difficult and long to implement (need to get the thumbnail for example, possible?).
To summarize:
With the UIImagePickerController, is it possible to prevent the play, to just get the path and to show our recorded videos?
With the NSFileManager, is it possible to easily create a custom video picker with thumbnail, duration etc.)
Thanks for your help

UIImagePickerController is an instance of the iOS Photos App by which you can access all of the Photos/Videos in the Device Gallery and not exclusively those belonging to your App. There is no way to have the UIImagePickerController show only the videos recorded by your App. It is also not possible to have the UIImagePickerController skip the Play/Choose step while picking a File.
Like you mentioned you can definitely write the Video file into the Apps documents directory by means of NSFileManager and hold a reference to the path which you can use for later use. I think you would probably end up creating a Model Class say "Video" with the following attributes;
a) savedPath
b) duration
c) thumbnail etc
You can then use something like a NSKeyedArchiver to encode these objects and store into a File so that you can retrieve this information later.

I finally found the solution using a custom picker, :
To get the list of local videos:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* rootPath = paths[0];
[[NSFileManager defaultManager] createDirectoryAtPath:rootPath withIntermediateDirectories:YES attributes:nil error:nil];
NSArray* mPaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:rootPath error:nil];
To get the duration and the thumbnail:
NSURL *videoURl = [NSURL fileURLWithPath:mPath];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL: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];
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef];
[m_videoFrames addObject:img];
CMTime duration = [asset duration];
int seconds = ceil(duration.value/duration.timescale);
Thanks!

Related

Downloading From Parse on Apple TV

The bounty expires in 3 days. Answers to this question are eligible for a +500 reputation bounty.
user717452 wants to draw more attention to this question.
I have a parse server set up, and as part of it, small PDFs (425KB) are stored on it. I need my Apple TV to be able to display these, but since they change often, it has to come from Parse server, and not just the main bundle where I update it with each update of the app. The issue I'm running into is the lack of an NSDocumentsDirectory on the Apple TV. How do y'all handle this? I've been using the Cache directory, but it seems to only work half the time with the code I am currently using. If I run it at launch from AppDelegate, by the time the PDF is needed, it may not be there, and if I have it set to run this code right when I need it, there is a delay, and sometimes, it simply doesn't show up. Would using NSTemporaryDirectory() be better? UPDATE, no, it doesn't. Works fine on simulator, on Apple TV, have to run the code two times to get it to both download, and draw the PDF
-(void)sermonTime {
//Check if PFFile exists, if so, display PDF, if not, blank time.
if ([self.entry[#"SermonPresIncluded"] isEqualToString:#"NO"]) {
[self blankTime];
}
else {
NSLog(#"SermonTime");
PFFileObject *thumbnail = self.entry[#"SermonPDF"];
[thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [[documentsDirectory stringByAppendingPathComponent:[self.entry valueForKey:#"DateOfService"]] stringByAppendingString:#".pdf"];
[imageData writeToFile:pdfPath atomically:YES];
NSURL *url = [NSURL fileURLWithPath:pdfPath];
self.view.backgroundColor = [UIColor blackColor];
self.arrayOfVerses = #[#"allverses"];
CGPDFDocumentRef pdfDocument = [self openPDF:url];
[self drawDocument:pdfDocument];
}];
}
}
-(void)sermonTime {
// Check if PFFile exists, if so, display PDF, if not, blank time.
if ([self.entry[#"SermonPresIncluded"] isEqualToString:#"NO"]) {
[self blankTime];
}
else {
NSLog(#"SermonTime");
PFFileObject *thumbnail = self.entry[#"SermonPDF"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [[documentsDirectory stringByAppendingPathComponent:[self.entry valueForKey:#"DateOfService"]] stringByAppendingString:#".pdf"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:pdfPath]) {
// Use cached copy of PDF
NSURL *url = [NSURL fileURLWithPath:pdfPath];
self.view.backgroundColor = [UIColor blackColor];
self.arrayOfVerses = #[#"allverses"];
CGPDFDocumentRef pdfDocument = [self openPDF:url];
[self drawDocument:pdfDocument];
} else {
// Download and save the PDF
[thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (error) {
// Handle the error
NSLog(#"Error downloading PDF: %#", error);
[self blankTime];
} else {
[imageData writeToFile:pdfPath atomically:YES];
// Use completion block to signal that the PDF is ready to display
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [NSURL fileURLWithPath:pdfPath];
self.view.backgroundColor = [UIColor blackColor];
self.arrayOfVerses = #[#"allverses"];
CGPDFDocumentRef pdfDocument = [self openPDF:url];
[self drawDocument:pdfDocument];
});
}
}];
}
}
}
Made some changes to the code.
It will first check if the PDF exists cache, it will use the PDF if it exists in cache and will only proceed download if it does not exists. Then, to make sure that PDF is downloaded and saved successfully you can use a completion block. With completion block, it will only proceed to draw it when the block is called to avoid the PDF does't show up.

AVPlayer playerWithURL not working after app restart

I am picking a video from the user photo library and than I save the video in the user Documents Folder to be able to play the video even if the user deletes this video from his photo Library. The URL to this file is stored in Core Data.
Everything works fine until the next time I run the App. Somehow it seems like the URL is no longer valid, which is strange because I am able to delete the video file when [AVPlayer playerWithURL:videoURL] fails.
Here is how I pick the video URL:
- (void) imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
NSURL* videoURL = info[UIImagePickerControllerMediaURL];}
This is how I save the video:
+ (NSURL*) saveVideoInDocumentsFolder:(NSURL*)videoURL name:(NSString*)name {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* pathComponent = [NSString stringWithFormat:#"/%#.%#", name, [videoURL pathExtension]];
NSString* path = [documentsDirectory stringByAppendingPathComponent:pathComponent];
NSError* error = nil;
NSData* videoData = [NSData dataWithContentsOfURL:videoURL options:0 error:&error];
if (error)
return nil;
BOOL success = [videoData writeToFile:path options:NSDataWritingAtomic error:&error];
if (success)
return [NSURL fileURLWithPath:path];
return nil;}
This is how I play the video:
AVPlayer* player = [AVPlayer playerWithURL:videoURL]; // <- AFTER I RESTART THE APP THIS METHOD ALWAYS RETURNS nil!!
AVPlayerViewController* viewController = [[AVPlayerViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
viewController.player = player;
[player play];
Many thanks in advance!
The URL to this file is stored in Core Data
That's the problem. The documents directory URL changes every time you run the app (because you are sandboxed), so it isn't valid the second time. Never never never save an absolute file URL in iOS!
You need to take every time the path directory when close and open app , because when app close it it removes documentDirectory, so you have to take it another time , and if you want to get your video file then save the FILE NAME of that video into preference or Core Data then get documentDirectory path by appending this video name file and you will get your video.
Just have a look: - (code is in swift you can convert it objective c easily)
let fileName = "recording.mp4"
let tempPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let tempDocumentsDirectory: AnyObject = tempPath[0] as AnyObject
let tempDataPath = tempDocumentsDirectory.appendingPathComponent(fileName) as String as String
that FILE NAME you will save in preference or coreData
and when you close and open the app just check do you have FILE NAME save in preference or in core data if yes then take it by appending with documentsDirectory and you will get your video

Unable to import pages and numbers documents with UIDocumentPicker

I'm developing an app that provides the ability to store cloud documents.
This app will have the option to import data from other apps using the new UIDocumentPickerViewController.
Everything works fine and I'm able to show the picker view controller.
This is the code that I'm using to import the file:
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
if (controller.documentPickerMode == UIDocumentPickerModeImport) {
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString* path=[NSString stringWithFormat:#"%#/MyHandyTap/%#/%#",documentsDirectory,self.cartella,[url lastPathComponent]];
BOOL startAccessingWorked = [url startAccessingSecurityScopedResource];
NSURL *ubiquityURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
__block NSData *data;
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
NSError *error;
[fileCoordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
data = [NSData dataWithContentsOfURL:newURL];
[data writeToFile:path atomically:YES];
}];
[url stopAccessingSecurityScopedResource];
}
}
With this code I'm able to import a lot of different file formats (.pdf, .txt, .rtf, .doc etc) however if I try to import files .pages or .numbers files from iCloud the call to [NSData dataWithContentsOfURL:newURL] returns null.
Is it possibile to let users import these kinds of files?
I've red the documentation listed here https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/FileProvider.html#//apple_ref/doc/uid/TP40014214-CH18-SW2
and I've downloaded the example listed here : https://developer.apple.com/devcenter/download.action?path=/wwdc_2014/wwdc_2014_sample_code/newboxanintroductiontoiclouddocumentenhancementsinios8.0.zip
however I'm not able to figure out how to solve this issue.
Thank you in advance for your help
Andrea
Even I did not test it, but likely you get the problems, because documents of type .pages or .numbers are no single files, but bundles. So you cannot read them with -dataWithContentsOfURL:.
Did you check copying with -copyItemAtURL:toURL:error: (NSFileManager)?

MPMoviePlayerViewController not working

I have been roaming the internet for a solution I really don't know what am I doing wrong. I have been with this problem a few days now. I save the video at the following path that should be accessible to the application (Right?)
//NSDocumentDirectory doesn't work either.
NSArray *newPath = NSSearchPathForDirectoriesInDomains(NSMoviesDirectory,
NSUserDomainMask, YES);
NSString *moviesDirectory = [NSString stringWithFormat:#"%#/WebSurg",
[newPath objectAtIndex:0]];
// Check if the directory already exists
if (![[NSFileManager defaultManager] fileExistsAtPath:moviesDirectory]) {
// Directory does not exist so create it
[[NSFileManager defaultManager] createDirectoryAtPath:moviesDirectory
withIntermediateDirectories:YES attributes:nil error:nil];
}
I show the contents of this directory in a tableView in the application. When a row is tapped it should play the video. But it doesn't. It shows me the MPMoviePlayerViewController modal view and then hides it after probably what is 1 second. This is the code I use to play it:
I tried two ways of getting the path to no avail.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *moviesPath = NSSearchPathForDirectoriesInDomains(NSMoviesDirectory,
NSUserDomainMask, YES);
NSString *moviesDirectory = [NSString stringWithFormat:#"%#/WebSurg",
[moviesPath objectAtIndex:0]];
NSString *movie = [self.tableData objectAtIndex:indexPath.row];
NSString *moviePath = [NSString stringWithFormat:#"%#/%#",
moviesDirectory, movie];
NSURL *movieURL = [NSURL fileURLWithPath:moviePath];
NSLog(#"MOVIEPATH: %#", moviePath);
NSString *alternatePath = [NSString stringWithFormat:#"%#/%#",
[[NSBundle mainBundle] resourcePath], movie];
NSURL *alternateMoviePath = [NSURL fileURLWithPath:moviePath];
movieViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:alternateMoviePath];
movieViewController.moviePlayer.movieSourceType= MPMovieSourceTypeFile;
NSLog(#"Movie Load State: %d", [[movieViewController moviePlayer] loadState]);
NSLog(#"Alternate movie Path: %#", alternatePath);
[self presentMoviePlayerViewControllerAnimated:movieViewController];
[movieViewController.moviePlayer play];
[self checkAndPlay];
}
- (void) checkAndPlay {
if ([[self.movieViewController moviePlayer] loadState] == MPMovieLoadStateUnknown) {
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:
#selector(checkAndPlay) userInfo:nil repeats:NO];
} else {
[self.movieViewController setModalTransitionStyle:
UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:movieViewController animated:YES];
}
}
And these are the results of the console:
2012-10-08 10:14:52.392 WebsurgTemplates[3722:17903] MOVIEPATH: /Users/THISISME/Library/Application Support/iPhone Simulator/5.0/Applications/E075DBE3-BFEA-4F6A-9DFA-2CC912E14863/Movies/WebSurg/FirstVideo.mp4
2012-10-08 10:14:52.459 WebsurgTemplates[3722:17903] Movie Load State: 0
2012-10-08 10:14:52.460 WebsurgTemplates[3722:17903] Alternate movie Path: /Users/THISISME/Library/Application Support/iPhone Simulator/5.0/Applications/E075DBE3-BFEA-4F6A-9DFA-2CC912E14863/WebsurgTemplates.app/FirstVideo.mp4
I would greatly appreciate any suggestions and help!!
UPDATE
I made no progress so far. I managed to log some other data to the console, some info that may help more at solving this problem. I tried to make a blank project taking the direct download of the video as link to play the video but it didn't work. What happens is exactly the same thing. jaydee3 said that maybe it was due because I had probably no access to NSMoviesDirectory. So I changed to NSDocumentDirectory but that didn't solve the problem. I checked that the file exists and the format in which it is saved so it can be readable by the player. Still it doesn't work. I don't know what am I doing wrong. Thanks again for the suggestions/help.
Here the results of the debug. more complete:
if ([[NSFileManager defaultManager] fileExistsAtPath:moviePath]) {
NSLog(#"FILE EXISTS");
CFStringRef fileExtension = (__bridge CFStringRef) [moviePath pathExtension];
CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
if (UTTypeConformsTo(fileUTI, kUTTypeImage)) NSLog(#"It's an image");
else if (UTTypeConformsTo(fileUTI, kUTTypeMovie)) NSLog(#"It's a movie");
else if (UTTypeConformsTo(fileUTI, kUTTypeText)) NSLog(#"It's text");
}
RESULTS
[6343:17903] MOVIEPATH: /Users/myname/Library/Application Support/iPhone Simulator/5.0/Applications/E075DBE3-BFEA-4F6A-9DFA-2CC912E14863/Documents/FirstVideo.mp4
[6343:17903] FILE EXISTS
[6343:17903] It's a movie
Okay so I managed to solve the problem and find the culprit.
In a brief note it was because the downloaded movie wasn't being saved properly (I am currently investigating the possible reasons why). And because of this the player was trying to play a file that existed, was in the correct format and the correct name but that was empty. I found this out by logging all the file sizes after download and transfer and play.
Now being more descriptive the issue was that I was downloading the movie to the NSCachesDirectory and then saving it to the NSDocumentDirectory. I found this because I started to wonder if it really found the file and if the file was "edible". It now plays the movie fine as I download it directly to the NSDocumentDirectory. Now I have to solve just in case the connection goes down. As saving in the NSCachesDirectory solved that automatically. I am open to suggestions on that. here is the code that didn't work to transfer the data from the NSCachesDirectory to NSDocumentDirectory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
// HERE I changed NSCachesDirectory to NSDocumentDirectory fixed it
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSString *downloadPath = [cachesDirectory stringByAppendingPathComponent:
#"DownloadedVideo.mp4"];
NSArray *newPath = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *moviesDirectory = [NSString stringWithFormat:#"%#",
[newPath objectAtIndex:0]];
self.downloadOperation = [ApplicationDelegate.mainDownloader downloadVideoFrom:
#"http://www.blablabla.web/iphone/download.php"
toFile:downloadPath];

How to write items to a directory and call them, Objective c

Hi I have a bunch of photos that I download from the web and I want to store them in a directory so I dont have to reload photos already downloaded, I am having trouble understanding how exactly to do this and store the photos and reload them from the directory and such. This is what I have so far. Could someone please explain the steps involved and how to do it? Thanks
-(void) savePhotoInCache: (NSData*) photoToSave{
//I dont know if u need bundle ID?
// NSString * bundleID = [[NSBundle mainBundle] bundleIdentifier];
NSFileManager *fm = [[NSFileManager alloc] init];
NSArray * directoryPaths = [fm URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSLog(#"%#", directoryPaths);
NSURL* dirPath = nil;
//Does this create a file in my cache Directory to store my photos?
dirPath = [[directoryPaths objectAtIndex:0] URLByAppendingPathComponent:[NSString stringWithFormat:#"photos.jpg"]];
NSError* theError = nil;
[fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES attributes:nil error:&theError];
// Saves the photo to the file?
[photoToSave writeToURL: dirPath atomically:NO];
NSLog(#"%#", dirPath);
//I get a deprecated warning, new version needs encoding, but I did not specify encoding in writeToURL so what do I use?
NSString * contents = [NSString stringWithContentsOfURL:dirPath ];
//After this how to I access my files and check what the contents of the file are? also, how do I limit the amount of information it stores? thanks
}
check this to how to get saved contents like this:
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dirPath error:nil];
Now filter contains like this:
NSPredicate *fltr = [NSPredicate predicateWithFormat:#"self ENDSWITH '.jpg'"];
NSPredicate *fltr1 = [NSPredicate predicateWithFormat:#"self ENDSWITH '.png'"];
NSArray *onlyJPGs = [dirContents filteredArrayUsingPredicate:fltr];
NSArray *onlyPNGs = [dirContents filteredArrayUsingPredicate:fltr1];
To get all image content
for(NSString *fileName in dirContents)
{
NSString *imgPath = [dirPath stringByAppendingFormat:fileName];
UIImage *img = [UIImage imageWithContentsOfFile:imgPath];
//You have image use it where u want
}
If u have many images then use lazy loading of images
You are not required to handle everything by yourself. I would rather use EGO Image Loader which does pretty everything for you. it saves (cached) images in application bundle directory and reuse them whenever you need it. As far as study the classes, it uses the image url as primary key (to retrieve the image from cache).
Its pretty fast and Asynchronous.
Just add it to your project and call it like this:(This is ARC, so I don't use -release)
UIImageView *imageView = [[EGOImageView alloc] initWithPlaceholderImage:[UIImage imageNamed:#"placeholder.png"]];
imageView.frame = CGRectMake(0.0f, 44.0f, 320.0f,54.0f);
imageView.imageURL = [NSURL URLWithString:#"www.example.com/1.jpg"] ;
[self.view addSubview:imageView];
I hope it's useful.