When creating a custom video player using the AVPlayer
+ AVPlayerLayer
+ AVPictureInPictureController
for a iPhone running iOS 14 (beta 7) the video does not automatically enter picture-in-picture-mode when the app enters the background after player.start()
is called from a UIButton action.
The issue does not reproduce using the AVPlayerViewController
which seems to indicate a problem with the AVPictureInPictureController
on iOS 14 in general, but I was wondering if anyone else had run into this problem and know of any workarounds. I've also filed this problem with Apple under rdar://8620271
Sample code.
import UIKit
import AVFoundation
import AVKit
class ViewController: UIViewController {
private let player = AVPlayer(url: URL(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")!)
private var pictureInPictureController: AVPictureInPictureController!
private var playerView: PlayerView!
private var playButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
playerView = PlayerView(frame: CGRect(x: 0, y: 44, width: view.bounds.width, height: 200))
playerView.backgroundColor = .black
playerView.playerLayer.player = player
view.addSubview(playerView)
playButton = UIButton(frame: CGRect(x: view.bounds.midX - 50, y: playerView.frame.maxY + 20, width: 100, height: 22))
playButton.setTitleColor(.blue, for: .normal)
playButton.setTitle("Play", for: .normal)
playButton.addTarget(self, action: #selector(play), for: .touchUpInside)
view.addSubview(playButton)
pictureInPictureController = AVPictureInPictureController(playerLayer: playerView.playerLayer)
do {
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.playback)
try audioSession.setMode(.moviePlayback)
try audioSession.setActive(true)
} catch let e {
print(e.localizedDescription)
}
}
@objc func play() {
player.play()
}
}
class PlayerView: UIView {
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
var playerLayer: AVPlayerLayer! {
return layer as? AVPlayerLayer
}
}
The root cause of the problem ended up being twofold:
AVAudioSession.sharedInstance().setActive(true)
must be called before the AVPictureInPictureController
is initialised.
The frame size for the AVPlayerLayer
must have a aspect ratio no greater than 16/9 (filed as a separate bug, rdar://8689203
)
For iPads, the video must be the same width as the device (in any given orientation). No separate rdar, as Apple have acknowledged the other bug already.
(The 2nd issues is not present in the example above)
Apple have acknowledged these bugs, and reported back to me that they have been / will be fixed (a rare case of a radar actually resulting in a reply!)