9

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?

mllm
  • 17,068
  • 15
  • 53
  • 64
  • 1
    "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: https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/bk2ch15p660EmbeddedAVKit 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. – matt Dec 26 '16 at 01:01
  • You're right, I should have posted some code. I'm posting my solution with some code – mllm Dec 26 '16 at 19:02

4 Answers4

14

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()
        }
    }
}
bauerMusic
  • 5,470
  • 5
  • 38
  • 53
  • 2
    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! – TahoeWolverine Jun 17 '20 at 19:25
  • 1
    Apple's documentation for `AVPlayerViewController` [*explicitly* states that it shouldn't be subclassed](https://developer.apple.com/documentation/avkit/avplayerviewcontroller#overview), so I'm not sure that this is a reliable fix for future iOS versions. – NRitH Aug 04 '21 at 14:43
  • 2
    @NRitH 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. – bauerMusic Aug 04 '21 at 16:45
  • Sorry, @bauerMusic—I was replying to @TahoeWolverine’s comment about extending `AVPlayerViewController`. – NRitH Aug 05 '21 at 17:18
2

Following on from the above answer https://stackoverflow.com/a/58818395/196555 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()
            }
        }
    }
daihovey
  • 3,485
  • 13
  • 66
  • 110
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()
}
mllm
  • 17,068
  • 15
  • 53
  • 64
  • 3
    Hello, @mllm 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. – Vivek Shah Dec 29 '17 at 06:25
  • The question was around auto pause in when user exits full screen mode... – Mohammad Reza Koohkan Dec 25 '19 at 21:51
-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
    }
}
闪电狮
  • 367
  • 2
  • 9