«Прекращено из-за проблемы с памятью» при использовании AVPlayerLooper - PullRequest
0 голосов
/ 23 января 2019

Мое приложение вылетает с сообщением «Прервано из-за проблемы с памятью» при использовании AVPlayerLooper для бесконечного зацикливания видео.Эта проблема возникает только на старых устройствах (это не происходит на iPhone 6S и новее) и с очень короткими циклами (короче 1 секунды).

Я пытался использовать AVPlayer и наблюдать AVPlayerItemDidPlayToEndTime, а затемстремление начать вручную, но это решение вызывает короткий перерыв / сбой между каждым циклом, и это вызывает проблемы синхронизации для моей конкретной потребности.Приостановка перед вызовом seek(to: CMTime.zero) не решает проблему.

Вот мой класс Looper:

class Looper: NSObject {
    private var playerItem: AVPlayerItem!
    private var player: AVQueuePlayer!
    private let playerLayer = AVPlayerLayer()
    private var playerLooper: AVPlayerLooper!
    private var isPaused: Bool = false {
        didSet {
            isPaused ? player.pause() : player.play()
        }
    }
    weak var delegate: LooperDelegate?

    required init(videoURL: URL) {
        super.init()
        let asset = AVURLAsset(url: videoURL, options: ["AVURLAssetPreferPreciseDurationAndTimingKey" : true])
        playerItem = AVPlayerItem(asset: asset)
        player = AVQueuePlayer(playerItem: playerItem)
        playerLayer.player = player
        playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)

        player.addObserver(self, forKeyPath: #keyPath(AVPlayer.status), options: [.old, .new], context: nil)
        player.addObserver(self, forKeyPath: #keyPath(AVPlayer.timeControlStatus), options: [.old, .new], context: nil)
        playerLooper.addObserver(self, forKeyPath: #keyPath(AVPlayerLooper.status), options: [.old, .new], context: nil)
    }

    deinit {
        player.removeObserver(self, forKeyPath: #keyPath(AVPlayer.status))
        player.removeObserver(self, forKeyPath: #keyPath(AVPlayer.timeControlStatus))
        playerLooper.removeObserver(self, forKeyPath: #keyPath(AVPlayerLooper.status))
    }

    func add(in parentLayer: CALayer) {
        playerLayer.frame = parentLayer.bounds
        parentLayer.addSublayer(playerLayer)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if object as AnyObject? === self.player &&
            keyPath == #keyPath(AVPlayer.status),
            let statusNumber = change?[.newKey] as? NSNumber,
            AVPlayer.Status(rawValue: statusNumber.intValue)! == .readyToPlay {
            self.delegate?.isReadyToPlay(duration: playerItem.asset.duration.seconds)
            print("Duration: \(playerItem.asset.duration.seconds)")

        } else if object as AnyObject? === self.player &&
            keyPath == #keyPath(AVPlayer.timeControlStatus),
            let oldKey = change?[.oldKey] as? NSNumber,
            let newKey = change?[.newKey] as? NSNumber,
            oldKey != 2 && newKey == 2 {
            self.delegate?.isLooping()
            print("isLooping")

        } else if object as AnyObject? === self.playerLooper &&
            keyPath == #keyPath(AVPlayerLooper.status),
            let statusNumber = change?[.newKey] as? NSNumber {
            if AVPlayerLooper.Status(rawValue: statusNumber.intValue)! == .ready {
                self.delegate?.isReadyForDisplay()
                print("isReadyForDisplay")
            }
        }
    }
}
...