Stop downloading stream on MPMoviePlayerController - ios

I have a MPMoviePlayerController, in which I open a movie stream located on Amazon S3. Now, I am calling [[self moviePlayerController] prepareToPlay]; once the stream URL is set so that the user can see the first frame and the movie is ready to play whenever the user wants to. This is done in viewDidLoad.
However, when I do a "prepareToPlay", it actually goes and keep downloading the movie stream. I don't want that because it uses a lot of bandwidth for nothing on my servers if the user doesn't actually play it fully. Is there a way to just load the first second or so?

Related

How to handle invalid url with MPMoviePlayerController

The app I am working on using MPMoviePlayerController to play video at remote urls. When I reuse the player to play more than one video and the url doesn't point to a video, the controller doesn't send any notification back. I've tried MPMoviePlayerPlaybackDidFinishNotification, MPMoviePlayerPlaybackStateDidChangeNotification and MPMoviePlayerLoadStateDidChangeNotification. None of them was sent.
I also tried to do a custom time out function and calls the player's stop function like below. But, nothing happens. MPMoviePlayerController just seems dead there and doing nothing.
[self performSelector:#selector(checkTimeout) withObject:theMovie afterDelay:15];
-(void) checkTimeout {
[self.moviePlayer stop];
}
Does anyone know how to handle invalid url with MPMoviePlayerController?
I found a kind of solution myself.
It seems MPMoviePlayerController has problem playing more than one urls. If the 2nd url doesn't point to a video or invalid, the player doesn't do anything. So, I ended up creating a new instance of the MPMoviePlayerController for every url and listening to MPMoviePlayerPlaybackDidFinishNotification.
If you did not receive notification on invalid urls, then you should run a timer of duration max(initialplaybacktime, 0) and once you do not receive MPMoviePlayerReadyForDisplayDidChange notification within this time, generate an error that video is not available.

Any reasons why AVQueuePlayer would sometimes work/sometimes not?

I'm creating a video player view where I download URLs from the Internet to play using an AVQueuePlayer. It generally works pretty fine except sometimes I'll get the play icon slashed out and the AVQueuePlayer breaks.
I'm not sure what triggers this broken AVQueuePlayer state.
I create new AVQueuePlayers on viewappear and on viewdisappear I run these lines on the player
ViewAppear
if (self.player == nil){
self.player = AVQueuePlayer()
}
ViewDisappear
self.player.pause()
self.player.replaceCurrentItemWithPlayerItem(nil)
The main thing I'm curious of are there any potential reasons why a AVQueuePlayer will sometimes work and sometimes not? (It'll stop working after I trigger viewAppear, viewDisappear, viewAppear, etc. a few times)
Checking the network requests, when I do get the play button of death, no videos are streamed at all (0 network activity).
Potential reasons:
1)I'm thinking it might have something to do with the number of AVPlayers instantiated and I'm just not removing them correctly?
2) I also build the app on my phone a lot and close it while running it. Maybe this breaks the phone's avplayer over time?
Any directions for this type of behavior are appreciated.
EDIT: Interestingly enough, once in a while, it breaks so hard that I break every single app that plays video. Snapchat and Youtube don't work either after a certain point. I'm not sure how I broke every single player.
UPDATE: Getting this generic error for BOTH the AVPlayer & AVPlayerItem
Optional(Error Domain=AVFoundationErrorDomain Code=-11819 "Cannot Complete Action" UserInfo={NSLocalizedDescription=Cannot Complete Action, NSLocalizedRecoverySuggestion=Try again later.})

AVQueuePlayer unable to play local MP3 files

I'm currently writing an iOS app that allows users to stream music from soundcloud. Currently I am able to stream just fine from Soundcloud, in booth forefront and background app states. I have an issue when I download an MP3 files and attempt to play it and have continuously playback when the app in in the background, more specifically in the locked screen or the screen is off.
When I play a downloaded file and lock the screen, the audio continues to play for a while. Usually it plays for 2 -3 mins. After that playback will stop and any other downloaded mp3 files in the playlist will not playback until the user returns to the app. Items in the playlist that are not downloaded will playback perfectly if the user has an internet connection, regardless if a downloaded item failed to play previously.
There are times when I receive the following error:
AVPlayerItemStatusFailed: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not becompleted" UserInfo=0x170270500 {NSUnderlyingError=0x170059380 "The operation couldn’t be completed. Operation not permitted", NSLocalizedFailureReason=An unknown error occurred (1), NSLocalizedDescription=The operation could not be completed}
I will additionally get the following notification from the AVPlayerItem
Notification: NSConcreteNotification 0x1700538c0 {name = AVPlayerItemDidPlayToEndTimeNotification; object = AVPlayerItem: 0x178009300, asset = AVURLAsset: 0x17822aaa0, URL = file:///var/mobile/Applications/51118E74-3334-4EFC-B148-B485DE675F9E/Documents/Downloads/SC_165903784.mp3}
This notification is received when the first item that is playing stop playing. It doesn't make sense that I get this notification when it doesn't finish playing to end of its duration.
My guess is that because the app is in background mode there is a limited time set for reading files, but I somehow doubt that.
I'm using the following to create a AVPlayerItem from a Local file.
NSURL* url = [NSURL fileURLWithPath:song.downloadFilePath];
[AVPlayerItem playerItemWithURL:url];
I have tried building my own AVQueuePlayer and also using iOS Hysteria Player, but both instances have given me the same bug for offline download playback.
Any insights or solutions are greatly appreciated.
Thanks!
Are you playing your files from the Documents directory? (Or anywhere besides the app bundle?)
If so, be sure to save the files to the directory using
[fileToSave writeToFile:filePath options:NSDataWritingFileProtectionNone error:nil];.
The NSDataWritingFileProtectionNone is the critical bit! What's going on, at least in my case, is this: iOS is trying to be secure, and so is by default enabling file protection on the files you add to the Documents directory (and also the other non-app-bundle directories as well, I believe). By adding NSDataWritingFileProtectionNone, you're requesting the system to no longer enable this protection on your files.
From Apple's iOS Documentation:
If you protect a file, your app must be prepared to lose access to
that file. When complete file protection is enabled, your app loses
the ability to read and write the file’s contents when the user locks
the device.
Now, as soon as I read that, I was almost positive that this was the cause for my app not being able to continue playback once the device was locked. For security's sake, iOS seems to default to automatically putting files under protection… but this keeps everything, including your app, from being able to access it while the device is locked. My bug was that it only played part of the song as soon as the device was locked, and that makes sense… since its access to the actual song file was revoked, it was only able to play the part of the song that had already been buffered into RAM!
This was the fix for a month-long problem I've been pulling my hair out to try to solve. I sincerely hope it fixes the issue for you too.
I believe this issue is caused by the limitation of AVQueuePlayer, and HysteriaPlayer using AVQueuePlayer as core player so that's why.
I've seen AVQueuePlayer document mentioned (I can't find it unfortunately) that it can't handle the queue mixed with local and remote audios.
There's some workarounds:
Use AVPlayer
Don't use AVQueuePlayer, handle the queue by yourself and feed it to AVPlayer.
Separate two AVQueuePlayer
One for local media, one for remote media. Insert and use PlayerItem and Player properly.
I would patch HysteriaPlayer to meet this requirement a month later, you can come back that time.

Getting warning while recording " MP AVAudioSessionDelegateMediaPlayerOnly end interruption"

I have been recording video successfully in my app using AVAssetWriter for long time but today I start to see some strange warning comes when I stop recording,
Scenario:
I record the video & can record again the video multiple times [NO WARNINGS]
I play the video in MPMoviePlayerController [NO WARNINGS]
I record the video after playing the video and once I click stop recording I get the warning
Warning:
MP AVAudioSessionDelegateMediaPlayerOnly end interruption. Interruptor <RecorderServer> category <(null)> resumable <0>, _state = 0
Does anyone know what might be the issue or had similar issue like I have?
It feels like I have solved my problem, although it was not a big issue just a minor mistake which I did,when I play video in MPMoviePlayerController , after I finish playing video using the notification, i was not releasing the player object, I thought it would be enough to unregister from the notification but it helped when i set the self.player=nil;
Seems that your audio session category is set to kAudioSessionCategory_MediaPlayback when you play which is ok. Change it to a suitable category for recording.
Look the different available categories here http://developer.apple.com/library/ios/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/AudioSessionCategories/AudioSessionCategories.html#//apple_ref/doc/uid/TP40007875-CH4-SW1

AVPlayer (and MPMoviePlayerController) tries to buffer the whole (streaming) video, runs out of memory

I'm a new iOS developer, I'm working on a video player app for a video sharing site, where sometimes a recording consists of two video streams (one showing the presenter, the other showing the recording of his screen). I'm trying to play this second video with AVFoundation, creating an AVPlayer. With some videos it works very well, but with some others it runs out of memory. After lot of investigating I figured that it tries to buffer the whole video into the memory.
I've spent hours googling it, but couldn't find anything.
I created a small project just to demonstrate this:
github project. It sets up two AVPlayer's, for two different video streams, and updates the UI to show the loadedTimeRanges of the players' AVPlayerItem. For the first video it only buffers ~60 seconds, which is nice, but for the second video it keeps buffering.
self.player1 = [AVPlayer playerWithURL:url1];
self.player2 = [AVPlayer playerWithURL:url2];
and the two text labels:
self.data1.text = [NSString stringWithFormat:#"Player 1 loadedTimeRanges: %#",
self.player1.currentItem.loadedTimeRanges];
self.data2.text = [NSString stringWithFormat:#"Player 2 loadedTimeRanges: %#",
self.player2.currentItem.loadedTimeRanges];
Maybe this could be important: The over-buffering video does not have an audio track, just a video.
UPDATE: I reproduced the problem with using MPMoviePlayerController instead of AVPlayer, and checking the playableDuration property. With the first movie it stops around 60 seconds, with the second movie it keeps going and then it runs out of memory.
UPDATE2: I got the actual video files and put them up to Dropbox, and tried to stream those: then I don't have the problem! It buffers the whole movie, but it does not run out of memory. It only runs out of memory if I stream them from the original site (our video sharing site). The URLs are there in the github project.
I'm really looking forward to any hints what could cause this.
Thank you!
This problem is indeed caused by the lack of an audio track for video streams sent from Wowza media server. (I have inferred from your stream URLs that you're using Wowza media server to stream your videos).
To verify this issue, I created a 5 minute video file with no audio track.
mplayer -nolirc -vo null -ao null -frames 0 -identify test_60.mp4
...
Opening video decoder: [ffmpeg] FFmpeg's libavcodec codec family
Selected video codec: [ffh264] vfm: ffmpeg (FFmpeg H.264)
==========================================================================
ID_VIDEO_CODEC=ffh264
Audio: no sound
Starting playback...
...
Then I added a mp3 track to that video file using mp4box.
MP4Box -new -add test_60.mp4 -add test_music.mp3 test_60_music.mp4
And verified that there was indeed an audio track.
mplayer -nolirc -vo null -ao null -frames 0 -identify /tmp/test_60_music.mp4
...
AUDIO: 44100 Hz, 2 ch, floatle, 320.0 kbit/11.34% (ratio: 40000->352800)
ID_AUDIO_BITRATE=320000
ID_AUDIO_RATE=44100
ID_AUDIO_NCH=2
Selected audio codec: [ffmp3float] afm: ffmpeg (FFmpeg MPEG layer-3 audio)
==========================================================================
AO: [null] 44100Hz 2ch floatle (4 bytes per sample)
ID_AUDIO_CODEC=ffmp3float
Starting playback...
...
Then, I put both the test_60.mp4 and test_60_music.mp4 in the Wowza content directory, and tested them. I actually wrote a small test app similar to yours to examine the loadedTimeRanges, but just loading the videos via safari from the device should be sufficient to see the difference.
I opened wowza_server:1935/vod/mp4:test_60.mp4/playlist.m3u8 and pressed pause as soon as it started playing. The buffer indicator kept increasing until the full 5 minute video was loaded.
Then, I opened wowza_server:1935/vod/mp4:test_60_music.mp4/playlist.m3u8 and did the same, but only the first 1/5th (roughly 1 minute) was loaded.
So it seems like a problem with the Wowza server's packetization - note this problem does not happen for me on adobe (flash) media server 5.0. Only 60 seconds is buffered regardless of whether the video contains an audio track.
Hope that's helpful. I've asked for input from Wowza folks at the Wowza forums

Resources