AVPlayer 播放更新标签导致问题

AVPlayer play with update label cause an issue

我在 AVPlayer 播放和同时更新标签时遇到问题。

我有计时器可以根据播放器的进度更新标签,但它会把我的视频卡在同一个位置...检查下图...按钮单击后计时器启动并导致问题..

代码:

func playVideo() {
    let path = NSBundle.mainBundle().pathForResource("videoname", ofType:"mp4")
    let fileURL = NSURL(fileURLWithPath: path!)
    
    moviePlayer = AVPlayer(URL: fileURL)
    
    //  Play the video
    moviePlayer!.play()
}

@IBAction func progresss(sender: UIButton) {
    self.meterTimer = NSTimer.scheduledTimerWithTimeInterval(0.1,
        target:self,
        selector:"updateAudioMeter:",
        userInfo:nil,
        repeats:true)
}

func updateAudioMeter(timer:NSTimer) {
    lbltime.text = "\(CMTimeGetSeconds(moviePlayer!.currentItem.currentTime()))"
}  

示例项目link

Source code

Note:please add video in bundle if you are use sample project.I just delete video because of file size

问题

我已经为 Objective-C 编写了示例代码,您可以在 swift 中相应地为您的项目转换相同的代码。

// Implement following code in AVPlayer observer method for `AVPlayerStatusReadyToPlay` state

[avPlayer addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC)
                                       queue:NULL
                                  usingBlock:
 ^(CMTime time)
 {
     // update label value here, it keeps invoking periodically internally.
     CMTime playerDuration = [self playerItemDuration];
 }]; 


// Method to get Player current time 
- (CMTime)playerItemDuration
{
    AVPlayerItem *thePlayerItem = [avPlayer currentItem];
    if (thePlayerItem.status == AVPlayerItemStatusReadyToPlay)
    {

        return([avPlayerItem duration]);
    }

    return(kCMTimeInvalid);
}

如果你只是想更新它然后调用 playerItemDuration 来获取当前时间,但是让它 asynchronous 过程。

根据您的示例代码,问题出在函数以下:

override func viewDidLayoutSubviews() {
    let layer = AVPlayerLayer(player: moviePlayer)
    layer.frame = self.viewPlayer.frame
    self.viewPlayer.layer.addSublayer(layer)
}

这将在每次标签更新时调整图层视图的大小,因此只需删除该代码并将其添加到 playVideo 方法中,您的方法将是:

func playVideo() {

    let path = NSBundle.mainBundle().pathForResource("video", ofType: "MOV")
    let url  = NSURL.fileURLWithPath(path!)
    moviePlayer = AVPlayer(URL: url)
    moviePlayer!.allowsExternalPlayback = false

    var introPlayerLayer = AVPlayerLayer(player: moviePlayer)
    viewPlayer.layer.addSublayer(introPlayerLayer)
    introPlayerLayer.frame = viewPlayer.bounds
    moviePlayer!.play()
}

并在 viewDidAppear 中调用此方法而不是 viewDidLoad 方法,您的完整代码将是:

import UIKit
import MediaPlayer
import AVFoundation

class ViewController: UIViewController {

    var moviePlayer : AVPlayer?
    var meterTimer : NSTimer!
    @IBOutlet weak var viewPlayer: UIView!
    @IBOutlet weak var lbltime: UILabel!

    override func viewDidAppear(animated: Bool) {
        playVideo()
    }

    func playVideo() {

        let path = NSBundle.mainBundle().pathForResource("video", ofType: "MOV")
        let url  = NSURL.fileURLWithPath(path!)
        moviePlayer = AVPlayer(URL: url)
        moviePlayer!.allowsExternalPlayback = false

        var introPlayerLayer = AVPlayerLayer(player: moviePlayer)
        viewPlayer.layer.addSublayer(introPlayerLayer)
        introPlayerLayer.frame = viewPlayer.bounds
        moviePlayer!.play()
    }

    @IBAction func progresss(sender: UIButton) {

        moviePlayer?.seekToTime(kCMTimeZero)
        moviePlayer?.addPeriodicTimeObserverForInterval(CMTimeMakeWithSeconds(1, 1), queue: nil, usingBlock: {
            (CMTime) -> Void in

            self.updateProgressBar()
        })

    }

    func updateProgressBar(){
        var timeNow = Int(self.moviePlayer!.currentTime().value) / Int(self.moviePlayer!.currentTime().timescale)

        var currentMins = timeNow / 60
        var currentSec = timeNow % 60

        var duration: String = "\(currentMins):\(currentSec)"

        self.lbltime.text = duration
    }
}