2017-10-31 3 views
1

Appleのサンプルコードを使用して、UICollectionViewCellの背景でビデオを再生しています。AVPlayer各繰り返し後に黒いフラッシュが表示される

私はAVPlayerLooperを使用しています。これは同じビデオの繰り返しです。

ここで私の問題は、ビデオが終わりに達すると、少し黒いビープの画面のフラッシュが表示されます。おそらくビデオが0回になっていて、わかりません。

ここでは、コードです:アップル

// Code from Apple 
class PlayerLooper: NSObject, Looper { 
    // MARK: Types 

    private struct ObserverContexts { 
     static var isLooping = 0 

     static var isLoopingKey = "isLooping" 

     static var loopCount = 0 

     static var loopCountKey = "loopCount" 

     static var playerItemDurationKey = "duration" 
    } 

    // MARK: Properties 

    private var player: AVQueuePlayer? 

    private var playerLayer: AVPlayerLayer? 

    private var playerLooper: AVPlayerLooper? 

    private var isObserving = false 

    private let numberOfTimesToPlay: Int 

    private let videoURL: URL 

    // MARK: Looper 

    required init(videoURL: URL, loopCount: Int) { 
     self.videoURL = videoURL 
     self.numberOfTimesToPlay = loopCount 

     super.init() 
    } 

    func start(in parentLayer: CALayer) { 
     player = AVQueuePlayer() 
     player?.isMuted = true 
     playerLayer = AVPlayerLayer(player: player) 

     guard let playerLayer = playerLayer else { fatalError("Error creating player layer") } 
     playerLayer.frame = parentLayer.bounds 
     parentLayer.addSublayer(playerLayer) 

     let playerItem = AVPlayerItem(url: videoURL) 
     playerItem.asset.loadValuesAsynchronously(forKeys: [ObserverContexts.playerItemDurationKey], completionHandler: {()->Void in 
      /* 
       The asset invokes its completion handler on an arbitrary queue when 
       loading is complete. Because we want to access our AVPlayerLooper 
       in our ensuing set-up, we must dispatch our handler to the main queue. 
      */ 
      DispatchQueue.main.async(execute: { 
       guard let player = self.player else { return } 

       var durationError: NSError? = nil 
       let durationStatus = playerItem.asset.statusOfValue(forKey: ObserverContexts.playerItemDurationKey, error: &durationError) 
       guard durationStatus == .loaded else { fatalError("Failed to load duration property with error: \(String(describing: durationError))") } 

       self.playerLooper = AVPlayerLooper(player: player, templateItem: playerItem) 
       self.startObserving() 
       player.play() 
      }) 
     }) 
    } 

    func stop() { 
     player?.pause() 
     stopObserving() 

     playerLooper?.disableLooping() 
     playerLooper = nil 

     playerLayer?.removeFromSuperlayer() 
     playerLayer = nil 

     player = nil 
    } 

    // MARK: Convenience 

    private func startObserving() { 
     guard let playerLooper = playerLooper, !isObserving else { return } 

     playerLooper.addObserver(self, forKeyPath: ObserverContexts.isLoopingKey, options: .new, context: &ObserverContexts.isLooping) 
     playerLooper.addObserver(self, forKeyPath: ObserverContexts.loopCountKey, options: .new, context: &ObserverContexts.loopCount) 

     isObserving = true 
    } 

    private func stopObserving() { 
     guard let playerLooper = playerLooper, isObserving else { return } 

     playerLooper.removeObserver(self, forKeyPath: ObserverContexts.isLoopingKey, context: &ObserverContexts.isLooping) 
     playerLooper.removeObserver(self, forKeyPath: ObserverContexts.loopCountKey, context: &ObserverContexts.loopCount) 

     isObserving = false 
    } 

    // MARK: KVO 

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
     if context == &ObserverContexts.isLooping { 
      if let loopingStatus = change?[.newKey] as? Bool, !loopingStatus { 
       print("Looping ended due to an error") 
      } 
     } 
     else if context == &ObserverContexts.loopCount { 
      guard let playerLooper = playerLooper else { return } 

      if numberOfTimesToPlay > 0 && playerLooper.loopCount >= numberOfTimesToPlay - 1 { 
       print("Exceeded loop limit of \(numberOfTimesToPlay) and disabling looping"); 
       stopObserving() 
       playerLooper.disableLooping() 
      } 
     } 
     else { 
      super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 
     } 
    } 
} 

私のコレクションビュー電池ルーパー初期

が提供するアップル

protocol Looper { 

    init(videoURL: URL, loopCount: Int) 

    func start(in layer: CALayer) 

    func stop() 
} 

プレーヤールーパークラス別

プロトコル

var looper: Looper? { didSet { configLooper() } } func configLooper() { looper?.start(in: layer) } 

細胞の初期化のための私のコレクションビューのデリゲート

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FirstLaunchCollectionViewCell 
    let videoURL = Bundle.main.url(forResource: "video3", withExtension: "MOV") 
    cell.looper = PlayerLooper(videoURL: videoURL!, loopCount: -1) 
    return cell 
} 

ので-1loopCount集合時間のビデオ再生無限の数。

小さいビデオサイズのファイルを使用しようとしましたが、各繰り返しの最後に黒いフレームが表示されます。

これを引き起こしている可能性がある人はいますか、それとも良い方法がありますか?アップルソースコードは、あなたがそれについて行くことができるもう一つの方法はそうのような仕上げのビデオのためのオブザーバーを追加することですhere

+0

は、あなたのビデオがのフレームで開始または終了いけない確認しました黒? – gadu

+0

はい、私は確認しました - それは黒いフレームで始まりません。 –

+0

最も役立つ回答ではありませんが、私は恐れていますが、これは数年前(iOS8のような)これを修正するために、GitHubサードパーティのビデオプレーヤーSCPlayerを使用して終了しました。あなたの幸運をお祈りしています! AVFoundationは時々楽しいことがあります。ビデオが終わる前にオブザーバを追加して、手動でkCMTimeZeroに戻ってみることもできます。 – gadu

答えて

0

を見つけることができます:

NotificationCenter.default.addObserver(forName: AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: nil, using: { (_) in 
    DispatchQueue.main.async { 
     self.player.seek(to: kCMTimeZero) 
     self.player.play() 
    } 
}) 
関連する問題