Laurence Wingo
Laurence Wingo

Reputation: 3952

How to update uilabel using AVPlayer addperiodictimeobserverforinterval function?

I'm attempting to update a UILabel with the AVPlayer remaining time. I was able to set the UILabel with the video's current time remaining as soon as the video starts but that number doesn't change as the video progresses. I searched Apple's documentation and found this block that observes the time of the video but this resource and other questions on Stackoverflow don't necessarily point out how to update a UILabel using this function.

Here is my code that compiles but I'm unsure of how to move forward:

import UIKit
import AVKit
import AVFoundation

extension UIView {
    func fadeTransition(duration:CFTimeInterval) {
        let animation:CATransition = CATransition()
        animation.timingFunction = CAMediaTimingFunction(name:
            kCAMediaTimingFunctionEaseInEaseOut)
        animation.type = kCATransitionFade
        animation.duration = duration
        self.layer.add(animation, forKey: kCATransitionFade)
    }
}

class MeetTheAuthorViewController: UIViewController {




    @IBOutlet weak var videoTimeRemainingLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        //playBackgroundMusic("bensound-jazzyfrenchy-castlesbackground.mp3")
        // Do any additional setup after loading the view.


    }

    func btn_clicked(_ sender: UIBarButtonItem) {
        // Do something
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "videoSegue"
        {
            //set up the player
            let videoURL = Bundle.main.url(forResource: "The Atlanta Goat_ Part One-HD", withExtension: "mp4")
            let videoViewController = segue.destination as! AVPlayerViewController
            videoViewController.player = AVPlayer(url: videoURL!)
            videoViewController.player?.play()

            //this code is an attempt to have a uilabel update with the time remaining in video
            let videoDuration = CMTimeGetSeconds((videoViewController.player?.currentItem?.asset.duration)!)
            let videoCurrentTime = videoViewController.player?.currentItem?.currentTime()
            let timeRemainingInVideo = videoDuration - CMTimeGetSeconds(videoCurrentTime!)

            videoTimeRemainingLabel.fadeTransition(duration: 0.4)
            videoTimeRemainingLabel.text = String(describing: timeRemainingInVideo)


            /*after the code above which updates the label initially, this code below is an attempt to update the UILabel over time as the video plays
            */
            func addPeriodicTimeObserver() {
                // Invoke callback every half second
                let interval = CMTime(seconds: 0.5,
                                      preferredTimescale: CMTimeScale(NSEC_PER_SEC))
                // Queue on which to invoke the callback
                let mainQueue = DispatchQueue.main
                // Add time observer
                var timeObserverToken =
                    videoViewController.player?.addPeriodicTimeObserver(forInterval: interval, queue: mainQueue) {
                        [weak self] time in
                        // update player transport UI
                }
            }
            //end of attempt to update time remaining label

            NotificationCenter.default.addObserver(self, selector: #selector(MeetTheAuthorViewController.playerDidFinishPlaying),
                                                             name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: videoViewController.player?.currentItem)



        }
    }

    func playerDidFinishPlaying() {
        print("Video Finished")
        self.dismiss(animated: true, completion: nil)
    }



}

Upvotes: 0

Views: 1384

Answers (2)

Willjay
Willjay

Reputation: 6459

Update UI should be in the main thread

videoViewController.player?.addPeriodicTimeObserver(forInterval: interval, queue: nil, using: { (time) in
        let currentTime = floor(CMTimeGetSeconds(time))
        print(currentTime)
        // update UI should be in main thread
        DispatchQueue.main.async {
            videoTimeRemainingLabel.text = String(currentTime)
        }
    })

Upvotes: 0

Jerry
Jerry

Reputation: 4480

Where you have the comment // update player transport UI, you need to recalculate timeRemainingInVideo and update the label.

Upvotes: 1

Related Questions