AVSampleBufferDisplayLayer 中的画中画未加载

Col*_*384 0 uikit ios swift avkit

我正在尝试为我的 iOS 应用程序支持画中画,并且我需要显示视图的内容,而不是视频。因此,我尝试使用库来记录视图并以AVSampleBufferDisplayLayer. 它有效,视图的内容显示在缓冲区显示层中,但是当我尝试使用 PIP 时,只显示加载指示器。这是我的代码:

import UIKit
import AVKit

class View: UIView {
    
    override class var layerClass: AnyClass {
        AVSampleBufferDisplayLayer.self
    }
}

class ViewController: UIViewController, AVPictureInPictureSampleBufferPlaybackDelegate {
    
    func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, setPlaying playing: Bool) {
        
    }
    
    func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
        .init(start: .zero, duration: self.buffers.first?.duration ?? .indefinite)
    }
    
    func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
        false
    }
    
    func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, didTransitionToRenderSize newRenderSize: CMVideoDimensions) {
        
    }
    
    func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, skipByInterval skipInterval: CMTime, completion completionHandler: @escaping () -> Void) {
        
    }

    @IBOutlet weak var playerView: View!
    
    @IBOutlet weak var textView: UITextView!
    
    var pipController: AVPictureInPictureController?
        
    var glimpse: Glimpse!
    
    var isRecording = false
    
    var buffers = [CMSampleBuffer]()
    
    @IBAction func pip() {
        pipController?.startPictureInPicture()
    }
    
    func startRecording() {
        glimpse = Glimpse()
        glimpse.startRecording(textView, withCallback: { url in
            if let url = url {
                do {
                    DispatchQueue.main.async {
                        (self.playerView.layer as! AVSampleBufferDisplayLayer).flush()
                        
                        if self.pipController == nil {
                            self.pipController = AVPictureInPictureController(contentSource: .init(sampleBufferDisplayLayer: self.playerView.layer as! AVSampleBufferDisplayLayer, playbackDelegate: self))
                            self.pipController?.requiresLinearPlayback = true
                        }
                    }
                    
                    let reader = try AVAssetReader(asset: AVAsset(url: url))
                    let output = AVAssetReaderTrackOutput(track: reader.asset.tracks.first!, outputSettings: nil)
                    reader.add(output)
                    reader.startReading()
                    
                    while let buffer = output.copyNextSampleBuffer() {
                        self.buffers.append(buffer)
                    }
                    
                    try FileManager.default.removeItem(at: url)
                } catch {
                    print(error)
                }
            }
        })
        
        isRecording = true
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        var i = 0
        _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
            self.textView.text += "Hello World! (\(i))\n"
            if self.isRecording {
                self.glimpse.stop()
                self.startRecording()
            }
            i += 1
        })
        
        let layer = playerView.layer as! AVSampleBufferDisplayLayer
        layer.requestMediaDataWhenReady(on: .global()) {
            if let buffer = self.buffers.first {
                layer.enqueue(buffer)
                self.buffers.remove(at: 0)
            }
        }
        
        startRecording()
    }
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,我每秒修改 UITextView 的内容并录制它的视频。然后我提取CMSampleBuffers 以将它们显示在AVSampleBufferDisplayLayer.

我附上了两个屏幕截图,第一个显示了文本视图的内容如何成功显示在中AVSampleBufferDisplayLayer,第二个显示了启用 PIP 时如何不显示任何内容。

画中画已禁用

画中画启用

我究竟做错了什么?

小智 5

返回错误的播放时间范围时,我也经历过同样的行为。确保您返回.positiveInfinity一段时间,否则您的图层将被加载指示器覆盖。

    func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
        return CMTimeRange(start: .negativeInfinity, duration: .positiveInfinity)
    }
Run Code Online (Sandbox Code Playgroud)

记录在这里:

https://developer.apple.com/documentation/avkit/avpictureinpicturesamplebufferplaybackdelegate/3750337-pictureinpicturecontrollertimera?changes=la