After launching a video using MPMoviePlayerController's initWithContentURL:, is it possible to cache the downloaded video so that the next time the video is played it can be loaded via a local file:// URI? I understand that it's possible to do my own downloading and then launch the movie player, however I would like to take advantage of the player's ability to start prior to completion of preload.
one trick, is to start the download to disk - (using atomic : YES), wait 10 seconds, and point the movie player to the local disk path. it will "download" while playing the incomplete file.
next time, just check if the file exists first.
I got this working pretty well on WIFI connections, but on 3G there were all kinds of crashyness.
worse, there were issues with incomplete local files. let me know if it is worth it.
I haven't tested this, but it may be possible to override [NSURLCache sharedURLCache] with a custom disk-only cache implementation. If MPMoviePlayerController uses NSURLRequest, it could work.
Related
Hello All I have been working on a project for a while:
I have a non standard MP4 video file I want to play off a server in a IPhone App (I am using Flash builder to create it).
Due to a combination of server problems (not correctly identifying MIME type and cant be changed) and IPhone limitations (e.g. not being able to force the iplayer to play files with wrong extension), I have had to setup a process that reads the file in, saves it locally and then point the video player at the local file.
Although this sort of works, i am having an issue with some of the files that are large (94mb for a 17 min video) and a slow server - which takes 120 seconds to transfer the whole file.
I thought that if you started playing the video, then the transfer rate would be faster than the playback rate so the video would play ok.
However sometimes the video just crashes, which i am guessing is a result of the video reading beyond what has been written.
If the video played the internal file using progressive download I think it would probably not crash but resume once more date had been read but understand that progressive download is triggered by a url extension beginning with HTTP://
Can you make an internal file play using progressive download ? I know this would not normally be expected as logically the system would expect a local file to already be download ?
Any help appreciated
Thanks
Toby
try this to know download file is complete or not
HCDownload
it is very easy to use only write its delegate method.
Edit
also see StitchedStreamPlayer
I am using the AFNetworking suite in my app. In the app you can record a message, which uploads to a server. I need to be able to play that audio file either by streaming it or chaching it, an ideas on how to do either?
Cheers
Honestly, I would just use AVPlayer and load the remote URL. Per Apple's documentation:
AVPlayer works equally well with local and remote media files, providing you with appropriate information about readiness to play or about the need to await additional data before continuing.
It's certainly possible to use AFNetworking to do this, but I trust that Apple's built-in AVPlayer will be more than suitable to your needs, and certainly worth a shot before rolling your own.
If you want to play a mp3 that is located on the server you can use Matt Galagher's Audiostreamer (http://cocoawithlove.com/2009/06/revisiting-old-post-streaming-and.html).
If you want to play a locally saved file you can use AVAudioPlayer (http://developer.apple.com/library/IOS/#documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html).
If that is not what you want please give us some more datails.
I have an iPad app which has a network connection from another iPad. On the client iPad, I want to be able to take data from a NSInputStream (which comes from the server iPad), and play it in MpMoviePlayer as it downloads from the server iPad.
I know that I can download the entire video, save it to a file, and open it in media player, but I want to be able to start playing before the full file has been downloaded.
I have NOT tried saving a chunk of it to the file and playing it, then adding to the file as it becomes available in the stream, because a) the file is likely to get locked, and b) the movieplayer is likely to open the file and read it into an internal cache, so adding to the file later won't (I don't think) play the new content. I'm willing to try it down the road, if nobody has any brilliant ideas, but I give it a very low likelihood of working - I'd guess a 10% chance of success.
If MpMoviePlayer had an initWithData method, I would simply give it a NSMutableData, and add to the data as it became available to the stream, but I don't see a method like that. Does anyone have any ideas for how I can do this?
Ok, I'm trying to let a user choose songs from their iPod library to listen to, but I still want to receive remote control notifications (headphones, lock screen osd, etc.) in my app so I can do some extra things. So far I can get either iPod music playing, or headphone events, but not both simultaneously.
Here's what I know so far...
If you use the MPMusicPlayer, you can easily have programmatic access to the entire music library. However, it, not your app, receives the remote notifications regardless if you use applicationMusicPlayer or ipodMusicPlayer.
If you use AVAudioPlayer (Apple's recommended player for most sounds in your app), you can easily get remote notifications, but it doesn't natively have access to the iPod library.
AVAudioPlayer can be initialized with an asset URL, and tracks in the iPod library (type MPMediaItem) do have a URL property that returns a NSURL instance which the documentation says its explicitly for use with AVAsset objects, but when you try initializing the AVAudioPlayer with that NSURL, it fails. (I used the 'now playing' track in iPod which was a MP3 and it did return a valid NSURL object but initialization failed. Even worse, when it was an Audible.com file, the NSURL property flat-out returned nil.)
If you try using an instance of the AVAudioPlayer to get remote events (say, with a blank sound file), then simultaneously use the MPMusicPlayer class to play iPod music, you have remote control access until you actually start iPod playback at which time you lose it since your audio session gets deactivated and the system audio session becomes active.
If you try the same as #4 but you instead set the audio session's category to a mixable variant, your session doesn't get deactivated, but you still lose remote control capability once the iPod starts playing.
In short, whenever MPMusicPlayer is playing, I can't seem to get remote events, and I don't know of any other way to play content from the iPod's library other than by using MPMusicPlayer.
ANY suggestions on how to get around this would be welcome. Creative or flat-out crazy. Don't care so long as it works.
Anyone? Anyone? Bueller? Bueller?
M
HA! Solved! I knew it was possible! (Thanks Async-games.com support!)
Here's how to play iPod music in your app, with background support, and with your app receiving the remote control notifications.
You have to use AVPlayer (but not AVAudioPlayer. No idea why that is!) initialized with the asset URL from the MPMediaItem you got from the library picker (or current item in the MPMusicPlayerController or wherever), then set the audio session's category to Playable (do NOT enable the mixing override or you'll lose the remote events!) and add the appropriate keys to your info.plist file telling the OS your app wants to support background audio.
Done and done!
This lets you play items from your iPod library (except Audible.com files for some reason!) in the background and still get remote events. Granted since this is your audio player which is separate from, and will interrupt the iPod app, you have to do more work, but those are the breaks!
Damn though... I just wished it worked with Audible.com files. (For those interested, the reason it doesn't is the asset URL for an audible file returns nil. Stinks! But what can ya do!)
This is probably not going to be of any use anymore for the OP, but as it may be for people finding this page through googling, I will post it anyway.
An alternative (but rather ugly) approach, if you are only interested in the music remote control events and still want to be able to play the audible.com files...
Just keep using the MPMusicPlayer and track its notifications (now playing and state changed). To keep receiving these notifications in the background, you can do the "background thread magic" described in various places to keep your app from being suspended. You are not going to receive the remote controls directly (as the iPod player is receiving them), but by tracking the changes in "now playing" you can infer the ControlPreviousTrack and ControlNextTrack events, and by tracking the playbackState, you can infer the TogglePlayPause command.
The downside is that you are app is going to be running at all times for no good reason (although, to be fair, if iOS is programmed correctly, a background thread doing nothing should consume almost no battery).
Another alternative: use a MPMoviePlayer? I have checked that it works fine in the background, and should receive remote control events as well. It can play MPMediaItem natively, so hopefully the Audible.com files as well...
There is no way around this. If the users iPod app is playing an iPod selection, then all remote events are going to go to the iPod, not your app.
One think I noticed about MPMediaItemPropertyAssetURL is that, although the object returned is in NSURL but the absoluteString is something like this:
ipod-library://item/item.mp3?id=580807975475997900
Which is not what AVAudioPlayer want. What AVAudioPlayer want is NSURL object that is created from a file with a valid file path.
And I have no idea how to get file path from MPMediaItem. So I guess maybe AVPlayer is the way to go if you want to play iPod track without using MPMusicPlayer.
I'm writing an app, part of which allows the user stream/play videos. I want to restrict the functionality so that they can only stream videos if they have a WiFi connection. I will then save the video so that when they have a 3G only (or lesser) connection they can't stream videos and can only replay videos that are saved on the phone.
Ideally, I'd like to get MPMoviePlayerController to stream/play the movie and then access the movie data and save it. However, the MPMoviePlayerController api doesn't seem to support access to the movie data.
I'd like to avoid and download-then-play scenario. Any ideas?
Two solutions come to mind.
Both this solutions require that the file is in a format that can be played progressive, e.g. that you don't need the whole file to be able to play it (but that would be a prerequisite anyway).
use a thread to download the data and append it to a file, and play the file from another thread. Now, that requires that you can handle EOF events in the MPMoviePlayerController and pause the playing until the cache file is appended to and then resume for the same point.
So far what I've seen people doing this it doesn't work because MPMoviePlayerController can't handle the EOF event. (not tested it my self yet) [Caching videos to disk after successful preload by MPMoviePlayerController
Skip the playing from a file and setup a local HTTP server and stream from that (on localhost). This is also not tested.
The idea is that MPMoviePlayerController would handlle the event of missing data better from a HTTP stream then from reading the file directly.
Downside might be that it is less efficient, but I think that is a minor increase in CPU. I don't know if the network interface would handle it, but I'm assuming it's not an issue.
I leave this answer as a wiki, because I don't have a working solution but I too want one.
There is a way to make this work, but you have to write your own HTTP Live Streaming downloader.
Basically, you parse the .m3u8 file (it's a pretty simple standard, but can get tricky with alternate streams and the possibility that the stream will simply drop out and need a new playlist to continue) and then download the chunks in .ts format to your local storage, say the Documents folder or Caches etc.
Then you'll have to set up a local HTTP server to allow the MPMoviePlayerController or AVPlayer to access the files over HTTP (since they won't touch a local file path), including a re-coded playlist file pointing to the local files, which you'll have to create yourself from the original playlist(s).
CocoaHTTPServer works great for this.
Once you've done all that, it works great. It's unavoidable that you get a little delay while you download the first chunk or two before presenting your local HTTP URL to the movie player, but after that you get seamless download, recording and preview playback.
Good luck!
the iPhone is using progressive download so it will not save on the device. For that you need to explicitly download it and then play the video from your local folder.