How to loop video with AVPlayerLooper

后端 未结 3 2350
一个人的身影
一个人的身影 2020-12-15 22:57

I try to loop a video in a TV OS app with the AVPlayerLooper because this should get rid of the pause/hicup when playing the video again. I watched the WW

相关标签:
3条回答
  • 2020-12-15 23:08

    Objective-C version:

    @implementation ViewController
    {
        // As explained in accepted answer, the playerLooper must be a
        // member (I put everything as member for simplicity):
        AVPlayerItem *_playerItem;
        AVQueuePlayer *_player;
        AVPlayerLooper *_playerLooper;
        AVPlayerLayer *_playerLayer;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // ...
    
        NSString *videoFile = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"mov"];
        NSURL *videoURL = [NSURL fileURLWithPath:videoFile];
    
        _playerItem = [AVPlayerItem playerItemWithURL:videoURL];
        _player = [AVQueuePlayer queuePlayerWithItems:@[_playerItem]];
        _playerLooper = [AVPlayerLooper playerLooperWithPlayer:_player templateItem:_playerItem];
        _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
        _playerLayer.frame = self.view.bounds;
        [self.view.layer addSublayer:_playerLayer];
        [_player play];
    }
    
    0 讨论(0)
  • 2020-12-15 23:14

    Swift 5 custom class for playing a video looped without any glitches

    import Foundation
    import AVKit
    
    class VideoPlayerLooped {
    
        public var videoPlayer:AVQueuePlayer?
        public var videoPlayerLayer:AVPlayerLayer?
        var playerLooper: NSObject?
        var queuePlayer: AVQueuePlayer?
    
        func playVideo(fileName:String, inView:UIView){
    
            if let path = Bundle.main.path(forResource: fileName, ofType: "mov") {
    
                let url = URL(fileURLWithPath: path)
                let playerItem = AVPlayerItem(url: url as URL)
    
                videoPlayer = AVQueuePlayer(items: [playerItem])
                playerLooper = AVPlayerLooper(player: videoPlayer!, templateItem: playerItem)
    
                videoPlayerLayer = AVPlayerLayer(player: videoPlayer)
                videoPlayerLayer!.frame = inView.bounds
                videoPlayerLayer!.videoGravity = AVLayerVideoGravity.resizeAspectFill
    
                inView.layer.addSublayer(videoPlayerLayer!)
    
                videoPlayer?.play()
            }
        }
    
        func remove() {
            videoPlayerLayer?.removeFromSuperlayer()
    
        }
    }
    

    Usage:

    let videoHolder = UIView()
    videoHolder.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
    
    var myVideoPlayerLooped = VideoPlayerLooped()
    videoPlayerLooped.playVideo(video: "myLocalMovFile", inView: videoHolder)
    
    0 讨论(0)
  • 2020-12-15 23:17

    I fixed the problem myself.

    The playerLooper must be a member variable in the class otherwise it doesn't work because a local variable is gone after the method has been called. So I put this line at the beginning of the class to declare it. I didn't declare it as an AVPlayerLooper because this is only for tvos10.0 and newer versions. I want my class to be adaptive to tvos9.0. This is my working code.

    var playerLooper: NSObject?
    var playerLayer:AVPlayerLayer!
    var queuePlayer: AVQueuePlayer?
    
    
    func playVideo(_ filmName: String){
        if let path = Bundle.main.path(forResource: filmName, ofType: "mov") {
            let url =  URL(fileURLWithPath: path)
    
            if #available(tvOS 10.0, *) {
    
                // Use a new player looper with the queue player and template item
                let playerItem = AVPlayerItem(url: url as URL)
                self.player = AVQueuePlayer(items: [playerItem])
                self.playerLayer = AVPlayerLayer(player: self.player)
                self.playerLooper = AVPlayerLooper(player: self.player! as! AVQueuePlayer, templateItem: playerItem)
                self.view.layer.addSublayer(self.playerLayer!)
                self.playerLayer?.frame = self.view.frame
                self.player?.play()
    
    
            } else {
                // Fallback on earlier versions, this solution has hicup at end
                player = AVPlayer(url: url)
                player?.play()
                loopVideo(player!)
            }
    
        }
    }
    
    func loopVideo(_ videoPlayer: AVPlayer) {
        NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
            if(!self.isStopped){
    
                videoPlayer.seek(to: kCMTimeZero)
                videoPlayer.play()
    
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题