MPMoviePlayer load and play movie saved in app documents - iphone

I am writing an application that stores the movies in the photo roll into the local documents folder for the app. I can play remote movies using the MPMoviePlayer, however trying to play a movie stored in the documents folder for the app always returns MPMovieLoadStateUnknown.
The notifications are all getting sent and received from the default notification center (MPMoviePlayerLoadStateDidChangeNotification, MPMoviePlayerPlaybackDidFinishNotification).
An alert box shows up shortly after getting the loadStateUnknown message in the console, saying that the movie could not be played and the app then receives the movie playback completed notification.
I think that it may be a case that the filename (MPMoviePlayer can only take a URL as the asset location) cannot be found. Has anyone dealt with this issue or similar?

Given that none of the other answers seem to resolve the problem, I'm inclined to think that the problem might be with the Documents file path you are producing.
You should be using the following method to generate the path to the application's documents folder:
NSString *userDocumentsPath = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if ([paths count] > 0)
{
userDocumentsPath = [paths objectAtIndex:0];
}

have you tried converting the local file path to a url
[NSURL URLWithString: [NSString stringWithFormat:#"file:/%#//",filePath]];
if there are spaces in you file path, you will have to convert them prior to creating the URL
filePath = [filePath stringByReplacingOccurrencesOfString:#"/" withString:#"//"];
filePath = [filePath stringByReplacingOccurrencesOfString:#" " withString:#"%20"];

The Core Data template converts a file path to a URL like this:
NSURL *storeUrl = [NSURL fileURLWithPath:whatever];
That seems to do all of the correct space escaping and stuff because I'm using this to load a file with a space in the path.

I am not sure if this will help you.
In this tutorial there are some code lines which probably will bring you on the right path:
// Unless state is unknown, start playback
if ([mp loadState] != MPMovieLoadStateUnknown)
...
You will find this snippet in following method:
- (void) moviePlayerLoadStateChanged:(NSNotification*)notification
here is the link to the tutorial:
Tutorial
Hopefully this will help you...

Related

How to save a video taken from camera into SQLite database in iPhone?

I have an application in which there is button named video. When a user clicks on the button a new view opens which consists of 4 other buttons namely take video and browse for video.
When he clicks on take video the camera opens which allows him to take video and the video gets inserted on the view. This all has been done, but there is a problem when the user has taken the video and the video gets inserted on the view. There is a button on the view named add which allows to insert the video into the SQLite database.
I am having a problem on how to bind a video and how to insert the captured video into SQLite database.
I am not sure why you want to save binary data contains captured videos into database. In DB best practice, this is not good idea. I would suggest to save your videos into home folder directory and named the videos into something that you can bind into the database.
For example, user recorded a new video, in database you make a new record and you got generated id, let say ID 10, so you should save the video into home directory like 10.mp4
Hence, you can retreive your video later on based on the same ID value.
:)
Trying to put Roberto's suggestion in code:
1) generate a unique Id (generated by time stamp/ hash / CFUUIDCreate ...) .
CFStringRef uStr = CFUUIDCreateString(kCFAllocatorDefault,CFUUIDCreate(kCFAllocatorDefault));
NSString *uniqueId = [[NSString alloc] initWithString:uStr];
2) save the file in with this unique name. Now save the uniqueId in SQLite DB.
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docsDir sstringByAppendingPathComponent:uniqueId];
NSFileManager *fManager = [NSFileManager defaultManager];
if (![fManager fileExistsAtPath:fileDirPath])
{
// save the file
}
3) In order to get the video, from the uniqueId, try to construct the file path from it as,
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docsDir sstringByAppendingPathComponent:uniqueId];
NSFileManager *fManager = [NSFileManager defaultManager];
if ([fManager fileExistsAtPath:fileDirPath])
{
// access the file
}

Problem when trying to play (with MPMoviePlayerViewController) a video/song that I downloaded and stored in a file

Here is my problem.
I have a MPMoviePlayerViewController that play some videos wich are on the web. That part works.
But in order to play them later, without internet connection, I store them on the phone with that piece of code
NSData * data = [NSData dataWithContentsOfURL:[self dataURL]];
NSArray * documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * baseDocumentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil;
[data writeToFile:[baseDocumentPath stringByAppendingPathComponent:_itemId]
atomically:YES];
That part is ok, I can play the files on my iMac if i take them from the phone.
But after that when i do
NSArray * documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * baseDocumentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil;
videoController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:[baseDocumentPath stringByAppendingPathComponent:file.itemId]]];
There is just a gray Window in the modal viewController. And i get no notifications from the player.
Any ideas?
Thanks.
I came across this very same problem today.
It seems that iOS won't load any media files that have the wrong file extension. IMHO this is pretty stupid behavior, as I'm storing my media files with random names (UUIDs).
A quick workaround was to use the following code to create a symlink to the original file and give it the correct extension. Now iOS will happily load the file.
// Create a symlink for iOS as it won't load any files with the wrong extension
NSString *fixedFileName = [fileName stringByAppendingString:#".mp4"];
[[NSFileManager defaultManager] createSymbolicLinkAtPath:fixedFileName
withDestinationPath:fileName error:NULL];
Hope that helps. We simply ignore the fact that an error occurred, in case the symlink already exists.
Someone found what causes the problem.
The file name has no extension (like .mp4) so the MPMovieController doesn't try to read it (that sounds crazy to me -_- ). If I manually had .mp4 to my video file. the app can read it... I'm gonna append the extension of each file to its name.
Thanks anyway :)

How to save multiple files in bundle in iphone app?

Hi all i am trying to save image in the bundle which i have currently on my view,but the problem is that i can only save one image,if i want to save the another image it replaces the old.I am not getting how to save the multiple images in the bundle then.
Here is my code.
- (void)writeImageToDocuments:(UIImage*)image
{
NSData *png = UIImagePNGRepresentation(image);
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSError *error = nil;
[png writeToFile:[documentsDirectory stringByAppendingPathComponent:#"image.png"] options:NSAtomicWrite error:&error];
}
Please Help me out, how to save multiple images, files e.t.c in bundle
Thanks in advance
You're not saving into a bundle, you're saving into your app's documents directory. There's no bundle aspect to it.
You're using the filename #"image.png" for every file that you save. Hence each new write overwrites the old one. In fact, you write each file twice. To save multiple files, use different file names.
It's also bad form to pass a numeric constant as the 'options:' parameter of NSData writeToFile:options:error: (or indeed, any similar case). The value '3' includes an undefined flag, so you should expect undefined behaviour and Apple can legitimately decline to approve your application. Probably you want to keep the NSAtomicWrite line and kill the one after it.
If you're just looking to find the first unused image.png filename, the simplest solution would be something like:
int imageNumber = 0;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *pathToFile;
do
{
// increment the image we're considering
imageNumber++;
// get the new path to the file
pathToFile = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:
#"image%d.png", imageNumber]];
}
while([fileManager fileExistsAtPath:pathToFile]);
/* so, we loop for as long as we keep coming up with names that already exist */
[png writeToFile:pathToFile options:NSAtomicWrite error:&error];
There's one potential downside to that; all the filenames you try are in the autorelease pool. So they'll remain in memory at least until this particular method exits. If you end up trying thousands of them, that could become a problem — but it's not directly relevant to the answer.
Assuming you always add new files but never remove files then this problem is something you could better solve with a binary search.
File names searched will be image1.png, image2.png, etc.

iPhone pathForResource vs bundlePath

I want to use pathForResource, but it doesn't look like it will create the path if one doesn't exist. Therefore I'm trying to create one manually by doing the following:
NSString *path = [NSString stringWithFormat:#"%#/%#.plist",[[NSBundle mainBundle] bundlePath],#"myFileName"];
I'm creating files dynamically, so I need to access them after I have Build and Run the application. But it puts the project in a unique id folder so the path comes out to something like:
/Users/RyanJM/Library/Application Support/iPhone Simulator/3.0/Applications/80986747-37FD-49F3-9BA8-41A42AF7A4CB/MyApp.app/myFileName.plist
But that unique id changes every time I do a build. What is the proper way to create a path that I can get to every time (even in the Simulator)?
Thanks.
Update: edited the question, hopefully to help anyone who comes across it in the future.
Update: IWasRobbed answered the proper way to get create a path URL. But the the best answer I've been able to find is from Brad Parks. Though, I do wish there was a cleaner way.
With the way you phrased your question, this is how you read a plist that has been included in the bundle before build:
NSString *propertyListPath = [[NSBundle mainBundle] pathForResource:SomeString ofType:#"plist"];
If you want to access the directories that each app has as a unique storage area for a file that you create AFTER build, you use this:
#define kFilename #”data.plist”
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
Then you can check for it and do some data handling here:
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
// do something with data here
}
You would save yourself a lot of trouble if you bought/read Beginning iPhone 3 Development specifically chapter 11 where he goes over data persistence (which is where this example came from). It's a great book.

Simplest way on iPhone to unzip downloaded file?

Goal: download a zipped file, unzip it, and save it in the iPhone app's Documents directory.
The following code makes use of the initWithGzippedData method that was added to NSData in the Molecule app found here:
http://www.sunsetlakesoftware.com/molecules
As adapted to my app:
NSString *sFolder = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *sFileName = [sFolder stringByAppendingPathComponent:#"MyFile.db"];
NSURL *oURL = [NSURL URLWithString: #"http://www.isystant.com/Files/MyFile.zip"];
NSData *oZipData = [NSData dataWithContentsOfURL: oURL];
NSData *oData = [[NSData alloc] initWithGzippedData:oZipData];
[oZipData release];
b = [oData writeToFile:sFileName atomically:NO];
NSLog(#"Unzip %i", b);
Result: A zip file is successfully downloaded. From it a new, supposedly unzipped file is created in the Documents directory with the desired name (MyFile.db) but it has zero bytes.
Anybody see the problem? Or else is there a simpler way to unzip a downloaded file than the one used in the Molecules app?
I think that your problem may be that you are attempting to gzip-deflate a Zip file. Those are two different compression algorithms.
I based the gzip-deflating code in Molecules on this NSData category (the code of which I've copied into this answer) provided by the contributors to the CocoaDev wiki. What you'll want to do is use their -zlibDeflate implementation, which should properly unzip a Zip file.
Unrelated to your problem, instead of using NSHomeDirectory() and appending a path component, the recommended approach for finding the documents directory is the following:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
You should make sure your file is never too big, as you are loading it fully into memory before the unzip starts.