Closed Reactor13 closed 2 years ago
Thanks for the confirmation. We will try to address the correction as soon as possible.
@Reactor13 @uakihir0 I was experiencing this issue too, and I had to do some weird magic to get it working ... seems Apple has changed something in their internal implementation of AVPictureInPictureController(contentSource:
method. Here's what fixed it for me:
It seems that by initializing the AVPictureInPictureController
with an empty contentSource
, followed by again setting the contentSource
within another DispatchQueue.main.async
got it working. Hope this helps somehow!
if self.pipController == nil {
// Initializing the pipController with an empty content source allows some
// unknown internal process to properly setup the `AVPictureInPictureController`
// before starting the picture-in-picture (`startPictureInPicture`)
self.pipController = AVPictureInPictureController(
contentSource: AVPictureInPictureController.ContentSource(
sampleBufferDisplayLayer: AVSampleBufferDisplayLayer(),
playbackDelegate: self)
)
self.pipController?.canStartPictureInPictureAutomaticallyFromInline = false
self.pipController?.delegate = self
self.pipController?.requiresLinearPlayback = false
}
// Once the `AVPictureInPictureController` has been initialized with an empty `contentSource`
// the setting of it's actual `contentSource`, together with `startPictureInPicture`
// is dispatched to the main queue asynchronously in order for it to work properly.
// Without placing self.pipController?.contentSource = contentSource within the execution block
// the PiP window shows a gray screen and endless loader.
DispatchQueue.main.async {
self.pipController?.contentSource = contentSource
self.pipController?.startPictureInPicture()
}
I have fixed this issue by adding pipController.requiresLinearPlayback = true
to this part of code:
💁♂️
if (pipController.isPictureInPicturePossible) {
/// Start asynchronously after processing is complete
/// (will not work if run here synchronously)
DispatchQueue.main.async { [weak self] in
pipController.startPictureInPicture()
pipController.requiresLinearPlayback = true
if let ti = refreshInterval {
self?.setRenderInterval(ti)
}
}
} else {
/// It will take some time for PiP to become available.
pipPossibleObservation = pipController.observe(
\AVPictureInPictureController.isPictureInPicturePossible,
options: [.initial, .new]) { [weak self] _, change in
guard let self = self else { return }
if (change.newValue ?? false) {
pipController.startPictureInPicture()
pipController.requiresLinearPlayback = true
self.pipPossibleObservation = nil
if let ti = refreshInterval {
self.setRenderInterval(ti)
}
}
}
}
@cohen72 @Reactor13
Thank you all so much!
I too have found that I can solve this problem by generating AVPictureInPictureController
with lazy as follows. Presumably this problem is an OS bug caused by iOS 16.
I have also confirmed here that requiresLinearPlayback
cures the problem. This is fine as a fix, but since PiP using controls is also possible, I'm going to fix it as follows.
private lazy var pipController: AVPictureInPictureController? = {
if UIPiPView.isUIPiPViewSupported(), #available(iOS 15.0, *) {
let controller = AVPictureInPictureController(contentSource: .init(
sampleBufferDisplayLayer: pipBufferDisplayLayer,
playbackDelegate: self))
controller.delegate = self
return controller
} else {
print("[UIPiPView] UIPiPView cannot be used on this device or OS.")
return nil
}
}()
Thank you for this awesome library )
HI
Unfortunately, the library stopped working on iOS 16. Only a gray screen is displayed. Any ideas how to fix it?