Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVPlayer video still playing after segue to next view controller

I'm currently looping my mp4 video with no playback controls, kind of like a gif but with sound. But I do not know why when I segue to the next view controller, the video is still playing. Does anybody know the simplest method to resolve this issue?

ViewController

import UIKit
import AVKit
import AVFoundation
fileprivate var playerObserver: Any?


class ScoreController: UIViewController {
    @IBOutlet var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()


        let returnValue: Int = UserDefaults.standard.integer(forKey: "userScore")
        label.text = "Your Score: \(returnValue)/30"

        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            let path = Bundle.main.path(forResource: "Innie-Kiss", ofType:"mp4")
            let player = AVPlayer(url: URL(fileURLWithPath: path!))
            let resetPlayer = {
                player.seek(to: kCMTimeZero)
                player.play()
            }
            playerObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil) { notification in resetPlayer() }
            let controller = AVPlayerViewController()
            controller.player = player
            controller.showsPlaybackControls = false
            self.addChildViewController(controller)
            let screenSize = UIScreen.main.bounds.size
            let videoFrame = CGRect(x: 0, y: 130, width: screenSize.width, height: (screenSize.height - 130) / 2)
            controller.view.frame = videoFrame
            self.view.addSubview(controller.view)
            player.play()
        } catch {
        }
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
    }
    fileprivate var player: AVPlayer? {
        didSet { player?.play() }
    }
    deinit {
        guard let observer = playerObserver else { return }
        NotificationCenter.default.removeObserver(observer)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()  
    }
    @IBAction func doneButton(_ sender: Any) {
        self.performSegue(withIdentifier: "done", sender: self)
    }
}
like image 654
Kinja Avatar asked Feb 12 '18 02:02

Kinja


People also ask

What is avplayerviewcontroller in iOS?

Besides AVPlayer, apple has also provided the support for a full screen controller for media playback. AVPlayerViewController — An object that displays the video content from a player object along with system-supplied playback controls. It is provided by AVKit framework. Line 1 — create an AVPlayerViewController instance.

How to show playback status on screen in avplayer?

For example, we could use a loader to show the playback status on screen. AVPlayer’s timeControlStatus can be used to track the video playback status. timeControlStatus — A status that indicates whether playback is currently in progress, paused indefinitely, or suspended while waiting for appropriate network conditions.

What is an avplayer and how to use it?

You can use an AVPlayer to play local and remote file-based media, such as QuickTime movies and MP3 audio files, as well as audiovisual media served using HTTP Live Streaming. Line 1 — AVAsset object is created using the video URL.

How to detect when avplayer video ends playing in Swift?

How to use Swift to detect when AVPlayer video ends playing? To detect the end of a video in swift we’ll need to create a video player, then use notifications to detect when the video stops playing. We’ll do this with help of an example in swift.


1 Answers

In viewWillDisapper() or button action for segue do this :

NotificationCenter.default.removeObserver(self)

Also move this from viewDidLoad() to some function like :

 var player: AVPlayer?

 func audioPlayer(){
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        let path                         = Bundle.main.path(forResource: "Innie-Kiss", ofType:"mp4")
        player                           = AVPlayer(url: URL(fileURLWithPath: path!))
        let resetPlayer                  = {
            self.player?.seek(to: kCMTimeZero)
            self.player?.play()
        }
        playerObserver                   = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil) { notification in resetPlayer() }
        let controller                   = AVPlayerViewController()
        controller.player                = player
        controller.showsPlaybackControls = false
        self.addChildViewController(controller)
        let screenSize                   = UIScreen.main.bounds.size
        let videoFrame                   = CGRect(x: 0, y: 130, width: screenSize.width, height: (screenSize.height - 130) / 2)
        controller.view.frame            = videoFrame
        self.view.addSubview(controller.view)
        player?.play()
    } catch {
    }
}

and make player object a global variable. var player = AVPlayer? and in viewWillDisappear make it nil.

So your viewWillDisappear should look like this :

override func viewWillDisappear(_ animated: Bool) {
     NotificationCenter.default.removeObserver(self)
    if player != nil{
        player?.replaceCurrentItem(with: nil)
        player = nil
    }
}
like image 149
Sharad Chauhan Avatar answered Oct 17 '22 15:10

Sharad Chauhan