Reinitializing AVQueuePlayer without haing to create new AVPlayerLayer - ios

while playing remote HLS videos,
I am re-initializing AVQueue player which is already initialized with items by using
(AVQueuePlayer *)initWithItems:(NSArray<AVPlayerItem *> *)items
However, by doing this sound plays in background but the AVPlayerLayer is stuck at the last frame of the previous video, the video does not update. In order to make sure that video gets updated, I need to remove the previous layer for UIView of video player, re-create the new AVPlayerLayer and assign it to the UIView for player using following :
[oldAVPlayerLayer removeFromSuperLayer]
[newAVPlayerLayer playerLayerWithPlayer: myAVQueuePlayer]
[myViewForPlayerLayer addSublayer : newAVPlayerLayer]
This causes a flicker on the screen, which is okay if the device was just an iPhone/iPad, but problem is with abrupt Airplay behaviour, causing the UISlider for sound to show in the remote controls.
Is there a way to re-initialize the AVQueuePlayer without recreating or reassigning the AVPlayerLayer?

Ended up using AVPlayer instead of AVQueuePlayer, and using method
replaceCurrentItemWithPlayerItem
Does not cause the glitch in airplay, and saves the memory as well since the items are instantiated as and when required.

Related

How to stop downloading a streaming HLS video after navigating away from AVPlayer view?

I am trying to play a HLS stream using AVPlayer. The player plays the stream fine, however, after navigating away from the player view, it does not seem to stop downloading data for the HLS stream. I see a network data spinner on the status bar for a few minutes after navigating away from the AVPlayer view.
I have tried cancelPendingSeeks, cancelLoading, and tried removing the AVPlayerLayer from its superlayer using removeFromSuperLayer, however, none of these seems to solve the issue — there is still a spinner on the status bar.
This spinner is seen on actual device, but there is no spinner on the simulator. I am certain the video is being downloaded; I can see the data usage in network monitoring apps. How can I fix this?
Call pause on your AVPlayer object, then replace the item with a nil item, and set your video player to nil.
[anAVPlayerObject pause];
[anAVPlayerObject replaceCurrentItemWithPlayerItem:nil];
anAVPlayerObject = nil;

Change the view that a video is playing on

In my app the user can play a video and leave the screen and it will continue to play in the background (just the audio). They can then return to continue to watch the video. This means that the view the video is in is destroyed and then recreated at a later point. Whenever the view is recreated and the player is set on it's AVPlayerLayer there is a noticeable lag in the video and more importantly the audio.
Does anyone know how to eliminate this lag?
The key to making this work without any lag / delay in the audio or video is to store the view with the AVPlayerLayer outside of the view. When reloading the controller, instead of creating a new view and assigning its player to the same player, simply attach the old view to the new view controller's view.
The view stays in memory as long as the video is still playing, that way a new AVPlayerLayer is not created and assigned to. It is the reassigning that causes the lag.

Creating new AVPlayer while in background does not work?

I'm playing music with an AVPlayer. Now at a certain time a NSTimer fires and I'dlike to fade over to another track. So I start fading out my AVPlayer and create a new AVPlayer instance to play the next song.
When on foreground this works as expected. But when my app is on background. The playing track fades out but the new AVPlayer instance does not start playing. Is it just not possible to create a new AVPlayer instance on background? or how can I make it play? Or is there another way to overlap two tracks?
I could do the playback with AVQeueuPalyer, but then I can't let tracks overlap. Any suggestions?
-- EDIT --
If it was not clear, I am able to play background audio as long as I want. Just creating a new AVPlayer instance in background does not work.
The correct way to do what I wanted seems to be AVMutableComposition. With that I don't need multiple AVPlayers and a few other benefits. For more details: I summarized it in a blogpost: http://www.postblog.me/2012/03/playing-multiple-overlapping-audio-tracks-in-background/
Try adding a key named "UIBackgroundModes" (array) to your app's Info.plist and add the value "audio" inside it. Then call
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:NULL];
And then you should be able to play audio in the background (you should link to the AVFoundation framework).

AVplayer full removal video out of memory

I know there have been a few hints on Stackoverflow about this issue but I haven't found a very satisfying answer to my problem.
I want to completely remove a video playing with AVPlayer in an AVPlayerLayer class from memory. I have read your are actually not allowed to call dealloc of the class containing the AVPlayerLayer. But even when I do so, the video remains in memory (cfr the sound does not stop playing).
Some people hint that you should pause the player, or just load in a new video, but I want it gone...
I need this because when rotating the device, I want the video kicked out of memory and a new video loaded in for the new orientation. I need to destroy the video completely because the parent view it is in also needs to be destroyed.
This is the structure I have
UIView
-> UIScrollView
-> UIviewWithPlayer
->AVPlayerLayer
In UIscrollView I call release and removefromsuperview on UIViewWithPlayer. In UIviewWithPlayer I call release and removefromsuperview on AVPlayerLayer. But that does not seem to work.
Thank you very much in advance for your help.

Previous frame is shown when I set the paused time and call play on MPMoviePlayerController

I am using MPMoviePlayerController to play the movie in iPhone. When I switch to some other UIViewController I pause the movie. When I come back to MPMoviePlayerController, user should be able to resume from the point where it was paused.
When I switch to some other UIViewController:
Pause the movie
Cache the movie time when it was paused.
Remove the view of MPMoviePlayerController from its superview due to some flickering issue.
When I come back,
a) create and add the view of MPMoviePlayerController to the superview
b) Set the cached time to the MPMoviePlayerController
c) Call play on MPMoviePlayerController.
Sometimes, the previous frame (which is far by the frame where it was paused by observable amount) is shown when I call play.
How do I solve this?

Resources