AVPlayerViewController stops after returning from full screen
Asked Answered
G

4

10

I have an AVPlayerViewController which I initialize with an AVPlayer and some AVPlayerItem (iOS 10, Xcode 8, Objective C). The AVPlayerViewController is presented "inline" inside some subview, and everything works perfectly with the native playback controls.

When I press the native fullscreen button, it also works ok and switches to full screen mode (with Done button on top left).

My problem is when I press the Done button to return from full screen, the player for some reason stops playing, resets itself, and if I check .currentItem, I see it's nil.

What's happening here? Why can't AVPlayerViewController maintain its AVPlayerItem in between switching from/to full screen?

Glimmering answered 25/12, 2016 at 20:56 Comment(2)
"What's happening here" Good question. But you have not shown any code at all, so who knows? The behavior you are describing does not normally happen; for example, download and run this example project: github.com/mattneub/Programming-iOS-Book-Examples/tree/master/… When you play the movie and expand to fullscreen and hit Done, we pause and that's all; you can resume from that point. Nothing is "reset". So you must be doing something that resets the AVPlayer. But you have not provided any clue as to what it is.Schwarz
You're right, I should have posted some code. I'm posting my solution with some codeGlimmering
P
17

Since it looks like the current behavior of AVPlayerViewController is to pause when exiting full screen, we can call play() when exiting by implementing the delegate:

class VideoView {

    private var playerViewController: AVPlayerViewController?

    func something() {

        playerViewController = AVPlayerViewController()

        // Other setups

        playerViewController?.delegate = self
    }
}

extension VideoView: AVPlayerViewControllerDelegate {

    func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {

        // The system pauses when returning from full screen, we need to 'resume' manually.
        coordinator.animate(alongsideTransition: nil) { transitionContext in
            self.playerViewController?.player.play()
        }
    }
}
Pentadactyl answered 12/11, 2019 at 12:6 Comment(4)
For those that are finding this question and answer, please be aware that it can be slightly improved as well given that the above solution will always play the video on exit full screen, even if it is paused. I did this by extending AVPlayerViewController, overriding viewWillAppear (which occurs on exit right before willEndFullScreen) and set a "pausedTemporarily" boolean objc_getAssociatedObject I added to the extension if the video is playing (based on timeControlStatus). Then just add a check into the willEndFullScreen for pausedTemporarily and then clear the value. Works great!Auxochrome
Apple's documentation for AVPlayerViewController explicitly states that it shouldn't be subclassed, so I'm not sure that this is a reliable fix for future iOS versions.Dogie
@Dogie There's no subclassing in the example (unless I'm missing something). class VideoView does not inherit from anything and the extension is only extending VideoView. And sure, I'd love to see a cleaner solution. I'm implementing a delegate, that's all.Pentadactyl
Sorry, @bauerMusic—I was replying to @TahoeWolverine’s comment about extending AVPlayerViewController.Dogie
L
2

Following on from the above answer https://mcmap.net/q/1065745/-avplayerviewcontroller-stops-after-returning-from-full-screen and the comment AVPlayerViewController stops after returning from full screen

I found using this extension works if you want to know if the AVPlayerViewController is playing or not

extension AVPlayer {
    var isPlaying: Bool {
        rate != 0 && error == nil
    }
}

 @objc func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        let isPlaying = self.playerViewController.player?.isPlaying ?? false
        // The system pauses when returning from full screen, we need to 'resume' manually.
        coordinator.animate(alongsideTransition: nil) { _ in
            if isPlaying {
                self.playerViewController.player?.play()
            }
        }
    }
Lowery answered 14/5, 2021 at 3:57 Comment(0)
G
0

Using @matt's reference, I saw that what I'd done different was to set the AVPlayerViewController's player property without an AVPlayerItem, and only setting it afterwards (relying on replaceCurrentItemWithPlayerItem().

In other words - from my experience, you should initialize both the AVPlayerViewController AND the AVPlayer with URL or any AVPlayerItem and only then adding the AVPlayerViewController as a child view controller.

Code for using without AutoLayout:

if let playerView = self.playerView {
    let playerItem = AVPlayerItem(url: self.url)
    let player = AVPlayer(playerItem: playerItem)

    let playerVc = AVPlayerViewController()
    playerVc.player = player

    self.addChildViewController(playerVc)
    playerVc.view.frame = playerView.bounds
    playerView.addSubview(playerVc.view)
    playerVc.didMove(toParentViewController: self)

    player.play()
}
Glimmering answered 26/12, 2016 at 19:18 Comment(2)
Hello, @Glimmering I am facing the same issue. I am using the same code as yours. But when I switch to full-screen mode video maintain it's play/pause mode to full-screen. But when I exit full-screen it always pauses to the same duration when exit button is pressed.Meilhac
The question was around auto pause in when user exits full screen mode...Nibelung
H
-1

The above solution will always play the video on exit full screen, even if it is paused.

Add this to fix it :

func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    let 获取播放状态 = self.parent.player.isPlaying
    
       // The system pauses when returning from full screen, we need to 'resume' manually.
       coordinator.animate(alongsideTransition: nil) { transitionContext in
           if 获取播放状态 {
               self.parent.player.play()
           }
       }
   }

And

extension AVPlayer {
    var isPlaying: Bool {
        return rate != 0 && error == nil
    }
}
Hillaryhillbilly answered 6/3, 2022 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.