AVPlayer is in the ReadyToPlay status but unable to start a playback - ios

Here is my code to start the video:
let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let playerAV = AVPlayer(url: videoURL! as URL)
let playerLayerAV = AVPlayerLayer(player: playerAV)
playerLayerAV.frame = ...
self.view.layer.addSublayer(playerLayerAV)
playerAV.play()
I can see the video preview, I can also see it's being loaded, I can even move the slider and see that preview is changing to the time I'm choosing. But if I hit play - nothing happens. I tried to press "play" button manually, I tried to call .play programmatically, the state of the "Play" button changes to "||" but then switches back to ">" right away.
I'm also tracking debug info related to the player state and I notice the following. Right when I created a player the status is below:
Status: ReadyToPlay
TimeControl: WaitingToPlayAtSpecifiedRate
ReasonToWait: AVPlayerWaitingToMinimizeStallsReason
Time: {0/1 = 0.000}
Rate: 1
Loaded Time Ranges: [Location=0,Length=0]
And it almost instantly changes its TimeControl: Paused and Rate: 0:
Status: ReadyToPlay
TimeControl: Paused
ReasonToWait:
Time: {0/1 = 0.000}
Rate: 0
Loaded Time Ranges: [Location=0,Length=0]
In both cases, it shows that playerItem.LoadedTimeRanges has one element but length and locations are 0 when the UI shows that the video has been completely loaded and ready to play.

Turned out that there is no issue with the video, views or controllers setup. The video is loaded and ready to play and paused right away because of a mode of the share audioSession. It was previously set to .record to process another app use-case.
The solution is to restore an original audioSession mode which includes playback and the video will play without any issues.

Related

AVPlayer video is freezing for some reason on rate 1

I am trying to play local videos in my app using AVPlayer and AVPlayerViewController. The problem is that when I try to play the video at some parts the video just starts freezing and playing 1 or 2 frames per second, while the audio sounds perfectly fine. It is not a heavy video (4.5 MB, 35 seconds long), it was exported at 25 fps(using adobe premiere).
I tried a couple of things to fix it, some of them fixed the freezes, but are not a good solution:
I exported the video at 15 frames per second, this made it run fine, but it was choppy since it was 15 fps.
I tried exporting the video at 150% speed, it ran smoothly.
Setting the rate to 0.75 made the video run smoothly.
Setting the rate higher made it freeze way more often.
For some reason when I started the video half way through at 15 seconds it didn't freeze.
This is what the code looks like:
let videoURL: URL = Bundle.main.url(forResource: currentComic?.getVideo(), withExtension: "mp4")!
player = AVPlayer(url: videoURL)
videoPlayerController.player = player
videoPlayerController.showsPlaybackControls = true
videoPlayerController.videoGravity = AVLayerVideoGravity.resizeAspectFill
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
self.present(videoPlayerController, animated: true, completion: nil)
var item = videoPlayerController.player!.currentItem
var previousPageCMTimeTag = CMTimeMakeWithSeconds(0, preferredTimescale: 1)
videoPlayerController.player!.seek(to: previousPageCMTimeTag)
videoPlayerController.player!.play()
player.rate = 1
videoPlayerController is a variable of AVPlayerViewController, and player is a variable of AVPlayer. I really hope someone can help me with this; it has been driving me crazy for the past few days.
I recently ran into the same issue and spent about a week diagnosing it.
Setting showsPlaybackControls while the AVPlayerViewController is onscreen will cause the video to freeze while the player continues playing audio-only.
The documentation for this property warns that setting this property while the player is visible "creates or destroys user interface elements", but we never thought it would destroy video playback entirely!
It's hard to tell if your code is doing this without seeing how else videoPlayerController is used, but make sure your AVPlayerViewController is not onscreen when mutating this property.

AVPlayerItem doesn't play video even its status is `readyToPlay` and `isPlaybackLikelyToKeepUp` is true

I'm playing live video with AVPlayer and AVPlayerItem. I'm observing AVPlayerItem's status, isPlaybackLikelyToKeepUp, and AVPlayerItemPlaybackStalled. I'm also observing AVPlayer's rate.
While I'm testing I found really weird thing happened.
While AVPlayer plays video normally(AVPlayerItem.status == readyToPlay and AVPlayerItem.isPlaybackLikelyToKeepUp == true), if I press home button, the AVPlayer.rate becomes 0.0. It means player stopped playing.
When app got back to foreground and I press play button, it is still AVPlayerItem.status == readyToPlay and AVPlayerItem.isPlaybackLikelyToKeepUp == true but paused and after a while it starts to play.
What I want is to know the player is paused or playing. In this case, even player is not playing video, the status indicates it is playing. (AVPlayerItem.status == readyToPlay, AVPlayerItem.isPlaybackLikelyToKeepUp == true, AVPlayer.rate == 1.0)
I checked AVPlayerItem's loadedTimeRanges and item.loadedTimeRanges.first is not nil(loadedTimeRanges has only one item) and its start and duration are not 0.
What should I check?
I'm adding little more.
This symptom only happens with streaming(m3u8) not with vod(mp4).
So I guess it is a problem of buffered data. While player is playing, buffer has data to play and the data is still valid. After app goes background and back to foreground, player's buffer still has data so isPlaybackLikelyToKeepUp == true, AVPlayerItem.status == readyToPlay. However when I try to play, AVPlayer flushes buffer because it is old.
It looks like the only way so far is create new AVPlayerItem and set when app is back to foreground.
What is the exact problem I'm encountering and want to know how to avoid it.
This is the repo I'm working on.
https://github.com/trick14/SLPlayer
The upper one is live and bottom one is VOD. After loading is done, play and go background and foreground couple times. And if you try to play, all status looks normal but player is stalled.
I have a similar experience long time ago.
At that time, I've stored the status of playing and the playback location when user press home button.
When return to the foreground, I used the stored information to restore or play the location.
I hope you were helpful.

Audio Start Delay For The First Time - ios Swift

I am creating an application with five buttons. When I click on each button each audio will play. It is working. Now my problem is when I click first button audio play with 1 second delay(App stuck for 1 second) and play. Next time clicks a button audio play without any delay. What could be the issue here?
I am using the following code to play an audio
var currentAudio = try? AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sample_audio", ofType: "mp3")!));
currentAudio!.stop()
currentAudio!.currentTime = 0
currentAudio!.play();
Please someone help me to finds this issue.
You could use AVAudioPlayer's .prepareToPlay() method to preload the player's buffers, it will increase AVAudioPlayer's performance (faster start).
The idea is to prepare the player some time before actually playing it:
currentAudio?.prepareToPlay()
then later, in your play function, it will start immediately:
currentAudio?.play()

Play video in reverse using AVPlayer and Swift on IOS 9

I have a recorded video clip that I want to play in reverse.
Playing forward is fine but as soon as I seek to the end of the video file and set the rate of playback to -1.0 the video clip seeks to the end of the clip (I see this in the timeline bar above the video) but does not play in reverse.
After I present the player view controller I check if it is ready to use:
print("readyForDisplay = \(playerViewController.readyForDisplay)")
This tells me that all is ready to prepare to play.
I check if reverse play is possible:
let reversePlay = playerViewController.player!.currentItem?.canPlayReverse
print("reversePlay = \(reversePlay)")
This returns TRUE
I then seek to the end of the clip and set the play back rate to -1.0 for reverse play.
playerViewController.player!.seekToTime(playerViewController.player!.currentItem!.asset.duration)
playerViewController.player!.rate = -1.0
I believe having got this far it is ready to play because if I add the following:
let status : AVPlayerItemStatus? = playerViewController.player!.currentItem?.status
if status == AVPlayerItemStatus.ReadyToPlay {
print("Ready to play")
}
It shows me that the clip is ready to play, so I am assuming that seeking to the end of clip (which is only 2 seconds long) has completed.
I then play the clip:
playerViewController.player!.play()
It plays fine if I don't seek to the end and attempt to change the rate to set it to reverse play.
What am I missing here?
I decided to add some logging after launching the video and found that the rate was -1 before launching and 1 immediately after so it seems that the rate is reset to 1.
Could this be a bug?
Anyway setting the rate immediately after the request to play the video has the desire effect.

iOS managing AVPlayer buffer prompt

I use AVPlayer to play a video that is on the internet. So my question is how can I give proper prompt to the user when he needs to wait? (e.g. an animating UIActivityIndicatorView whenever he needs to wait for the player to load some more data or seek to a specific time)
I spinning the UIActivityIndicatorView whenever I set a new playerItem to my AVPlayer, then I observe status of the playerItem, when it becomes AVPlayerItemStatusReadyToPlay, I stop the spinning and start play. So whenever a new playerItem is set on my AVPlayer, a spinning will be there until it is ready to play.
I also want to give my user the spinning when he needs to wait for the playerItem to load more buffer when network connection is bad. I tried observing playbackBufferEmpty and playbackLikelyToKeepUp but did not work as I expected. I also messed with the rate property of my AVPlayer, still not work quite well.

Resources