如何在Swift中使用AVPlayerViewController (AVKit)播放视频

189

如何使用 AV Kit Player View Controller 在 Swift 中播放视频?

override func viewDidLoad() {
        super.viewDidLoad()
        let videoURLWithPath = "http://****/5.m3u8"
        let videoURL = NSURL(string: videoURLWithPath)
        playerViewController = AVPlayerViewController()

        dispatch_async(dispatch_get_main_queue()) {
            self.playerViewController?.player = AVPlayer.playerWithURL(videoURL) as AVPlayer
        }
    }

要使用AVPlayer(没有控件),请参见此答案 - Suragch
15个回答

1

使用来自Github链接的ASVideoPlayer库创建自定义视频播放器:https://github.com/Asbat/ASVideoPlayer

// --------------------------------------------------------
// MARK:- variables
// --------------------------------------------------------

var videoPlayer = ASVideoPlayerController()
var videoData : [VideoModel] = []
var allVideoData : [AllVideoModel] = []
var cellHeights = [IndexPath: CGFloat]()
let loadingCellTableViewCellCellIdentifier = "LoadingCellTableViewCell"
var pauseIndexPath : Int = 0
var pageNumber = 1
var index = 0
var id = ""
var titleVideo = ""
var isUpdate = false
var myVideo : [MyVideo] = []
var imgs = [UIImage]()
var activityViewController : UIActivityViewController!

private var activityIndicator = NVActivityIndicatorView(frame: CGRect(x: 5, y: 5, width: 5, height: 5), type: .circleStrokeSpin, color: .systemBlue, padding: 5)
private let refreshControl = UIRefreshControl()


// --------------------------------------------------------
// MARK:- Outlets
// --------------------------------------------------------
@IBOutlet private var tableVideo: UITableView!
@IBOutlet private var _btnBack: UIButton!
@IBOutlet var _btnide: UIButton!

// ---------------------------------------------------------
// MARK:- Lifecycle
// ---------------------------------------------------------

override func viewDidLoad() {
    super.viewDidLoad()
    
    self._btnide.isHidden = true
    tableVideo.rowHeight = UITableView.automaticDimension
    tableVideo.separatorStyle = .none
    tableVideo.delegate = self
    tableVideo.dataSource = self
    tableVideo.register(UINib(nibName: "VideoPlayerTableCell", bundle: nil), forCellReuseIdentifier: "VideoPlayerTableCell")
    let cellNib = UINib(nibName:loadingCellTableViewCellCellIdentifier, bundle: nil)
    tableVideo.register(cellNib, forCellReuseIdentifier: loadingCellTableViewCellCellIdentifier)
    navigationController?.navigationBar.isHidden = true
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    ASVideoPlayerController.sharedVideoPlayer.pausePlayeVideosFor(tableView: tableVideo)
    tableVideo.scrollToRow(at: IndexPath(row: index, section: 0), at: .none, animated: true)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    tableVideo.scrollToRow(at: IndexPath(row: pauseIndexPath, section: 0), at: .none, animated: true)
    puasVideoWhenPushVC(index: pauseIndexPath)
    NotificationCenter.default.removeObserver(self)
    if tableVideo.isHidden == true {
    }
}

@IBAction func _onTapBackBtnAction(_ sender: UIButton) {
    tableVideo.scrollToRow(at: IndexPath(row: pauseIndexPath, section: 0), at: .none, animated: true)
    self.puasVideoWhenPushVC(index: pauseIndexPath)
    navigationController?.popViewController(animated: true)
    navigationController?.navigationBar.isHidden = false
}

// ---------------------------------------------------------------------
// MARK:- TableView Delegate & DataSource
// ---------------------------------------------------------------------

  extension VideoPlayerVC : 
  UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate {

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if isUpdate{
        return videoData.count
    }else{
        return allVideoData.count
    }
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if tableView == tableVideo {
        return view.bounds.height
    }else {
        return UITableView.automaticDimension
    }
}


func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if tableView == tableVideo {
        if let videoCell = cell as? ASAutoPlayVideoLayerContainer, let _ = videoCell.videoURL {
            ASVideoPlayerController.sharedVideoPlayer.removeLayerFor(cell: videoCell)
        }
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableVideo.dequeueReusableCell(withIdentifier: "VideoPlayerTableCell", for: indexPath) as! VideoPlayerTableCell
    if isUpdate{
        self.id = videoData[indexPath.row].id ?? ""
        cell.configureCell(videoUrl: videoData[indexPath.row].videoLink )
    }else{
        self.id = allVideoData[indexPath.row].id ?? ""
        cell.configureCell(videoUrl: allVideoData[indexPath.row].videoLink)
    }
    cell.btnPlayPause.isSelected = false
    cell.btnPlayPause.tag = indexPath.row
    cell.btnPlayPause.addTarget(self, action: #selector(didTapPlayPauseButton(_:)), for: .touchUpInside)
    cell.btnPlayPause.setImage(UIImage(named: ""), for: .normal)
    cell.btnPlayPause.setImage(UIImage(named: "btn_play_video"), for: .selected)
    
    cell.btnUseNow.tag = indexPath.row
    cell.btnUseNow.addTarget(self, action: #selector(btnUseNowTapped(sender:)), for: .touchUpInside)
    
    cell.btnShare.tag = indexPath.row
    cell.btnShare.addTarget(self, action: #selector(btnShareTapped(sender:)), for: .touchUpInside)
    
    cell.btnSave.tag = indexPath.row
    cell.btnSave.addTarget(self, action: #selector(btnSaveTapped(sender:)), for: .touchUpInside)
    
    pauseIndexPath = indexPath.row
    return cell
}

@objc func btnUseNowTapped(sender: UIButton){
    
    self._btnide.isHidden = false
    self.pausePlayeVideos()
    let editVC = EditVideoVC()
    var fileName : String = kEmptyString
    
    if self.isUpdate{
        editVC.videoString = self.videoData[sender.tag].videoLink ?? kEmptyString
        editVC.id = self.videoData[sender.tag].id ?? kEmptyString
        editVC.titleVideo = self.videoData[sender.tag].title ?? kEmptyString
        fileName = self.videoData[sender.tag].videoZip ?? kEmptyString
        
        guard !FileManager.isExist(id: self.videoData[sender.tag].id ?? kEmptyString) else{
            print("File Downloaded")
            self.puasVideoWhenPushVC(index: sender.tag)
            self.navigationController?.pushViewController(editVC, animated: true)
            return }
        
        FileManager.download(id: self.videoData[sender.tag].id ?? kEmptyString, url: fileName) { (url) in
            guard url != nil else {
                print("not download")
                return
            }
            self.puasVideoWhenPushVC(index: sender.tag)
            self.navigationController?.pushViewController(editVC, animated: true)
        }
    }
    else{
        editVC.videoString = self.allVideoData[sender.tag].videoLink ?? kEmptyString
        editVC.id = self.allVideoData[sender.tag].id ?? kEmptyString
        editVC.titleVideo = self.allVideoData[sender.tag].title ?? kEmptyString
        fileName = self.allVideoData[sender.tag].videoZip ?? kEmptyString
        
        guard !FileManager.isExist(id: self.allVideoData[sender.tag].id ?? kEmptyString) else{
            print("File Downloaded")
            self.puasVideoWhenPushVC(index: sender.tag)
            self.navigationController?.pushViewController(editVC, animated: true)
            return }
        
        FileManager.download(id: self.allVideoData[sender.tag].id ?? kEmptyString, url: fileName) { (url) in
            guard url != nil else {
                print("not download")
                return
            }
            self.puasVideoWhenPushVC(index: sender.tag)
            self.navigationController?.pushViewController(editVC, animated: true)
        }
    }
}

@objc func btnShareTapped(sender: UIButton){
    
    if self.isUpdate{
        let video = ["\(String(describing: self.videoData[sender.tag].videoLink))"]
        self.activityViewController = UIActivityViewController(activityItems: video, applicationActivities: nil)
        self.activityViewController.setValue("Video Share", forKey: "subject")
        
        self.activityViewController.popoverPresentationController?.sourceView = self.view
        self.activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToTwitter, UIActivity.ActivityType.addToReadingList, UIActivity.ActivityType.assignToContact,UIActivity.ActivityType.copyToPasteboard,UIActivity.ActivityType.mail,UIActivity.ActivityType.markupAsPDF,UIActivity.ActivityType.message,UIActivity.ActivityType.postToFacebook,UIActivity.ActivityType.postToFlickr,UIActivity.ActivityType.postToTencentWeibo,UIActivity.ActivityType.postToVimeo,UIActivity.ActivityType.postToWeibo,UIActivity.ActivityType.saveToCameraRoll]
        self.present(self.activityViewController, animated: true, completion: nil)
    }
    else{
        let categoryVideo = ["\(String(describing: self.allVideoData[sender.tag].videoLink))"]
        self.activityViewController = UIActivityViewController(activityItems: categoryVideo, applicationActivities: nil)
        self.activityViewController.setValue("Video Share", forKey: "subject")
        
        self.activityViewController.popoverPresentationController?.sourceView = self.view
        self.activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToTwitter]
        self.present(self.activityViewController, animated: true, completion: nil)
    }
}

@objc func btnSaveTapped(sender: UIButton){
   
    if self.isUpdate{
        self.downloadVideos(video: self.videoData[sender.tag].videoLink ?? kEmptyString)
    }else{
        self.downloadVideos(video: self.allVideoData[sender.tag].videoLink ?? kEmptyString)
    }
}


private func downloadVideos(video : String){
    Alamofire.request(video).downloadProgress(closure : { (progress) in
    }).responseData{ (response) in
        ///# Create folder in documetn directory #///

        if let data = response.result.value{
            let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("Videos")
            if !FileManager.default.fileExists(atPath: path) {
                try! FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
            }
            let fileURL = URL(fileURLWithPath:path).appendingPathComponent("\(self.id)/\(self.titleVideo)/output.mp4")
            print(fileURL)
            do{
                try data.write(to: fileURL, options: .atomic)
            }catch{
                print("could not download")
            }
            print(fileURL)
        }
    }
}


// ----------------------------------------------------------------------
// MARK:- Scrollview Method
// ----------------------------------------------------------------------

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    if scrollView == tableVideo {
        pauseIndexPath = Int(scrollView.contentOffset.y / scrollView.frame.size.height)
        pausePlayeVideos()
    }
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if scrollView == tableVideo {
        if !decelerate {
            pausePlayeVideos()
        }
    }
}

// ----------------------------------------------------------------------
// MARK:- Function Pause & Play Button
// ----------------------------------------------------------------------

func puasVideoWhenPushVC (index : NSInteger) {
    if isUpdate{
        guard let cell = tableVideo.cellForRow(at: IndexPath(row: index, section: 0)) as? VideoPlayerTableCell else { return }
        ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: videoData[index].videoLink ?? "")
    }
    else{
        guard let cell = tableVideo.cellForRow(at: IndexPath(row: index, section: 0)) as? VideoPlayerTableCell else { return }
        ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: allVideoData[index].videoLink ?? "")
    }
}

@objc func pausePlayeVideos(){
    ASVideoPlayerController.sharedVideoPlayer.pausePlayeVideosFor(tableView: tableVideo)
}

@objc func appEnteredFromBackground() {
    ASVideoPlayerController.sharedVideoPlayer.pausePlayeVideosFor(tableView: tableVideo, appEnteredFromBackground: true)
}

@objc func didTapPlayPauseButton(_ sender: UIButton) {
    
    guard let cell = tableVideo.cellForRow(at: IndexPath(row: sender.tag, section: 0)) as? VideoPlayerTableCell else { return }
    if sender.isSelected {
        if isUpdate{
            ASVideoPlayerController.sharedVideoPlayer.playVideo(withLayer: cell.videoLayer, url: videoData[sender.tag].videoLink ?? "")
        }else{
            ASVideoPlayerController.sharedVideoPlayer.playVideo(withLayer: cell.videoLayer, url: allVideoData[sender.tag].videoLink ?? "")
        }
    } else {
        if isUpdate{
            ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: videoData[sender.tag].videoLink ?? "")
        }else{
            ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: allVideoData[sender.tag].videoLink ?? "")
        }
    }
    sender.isSelected = !sender.isSelected
}

1

Swift 5.0

从@ingconti的回答中改进。这对我有用。

 if let url = URL(string: "urUrlString"){
            let player = AVPlayer(url: url)
            let avController = AVPlayerViewController()
            avController.player = player
            // your desired frame
            avController.view.frame = self.view.frame
            self.view.addSubview(avController.view)
            self.addChild(avController)
            player.play()
        }

1
let videoUrl = //URL: Your Video URL

//Create player first using your URL
let yourplayer = AVPlayer(url: videoUrl)

//Create player controller and set it’s player
let playerController = AVPlayerViewController()
playerController.player = yourplayer


//Final step To present controller  with player in your view controller
present(playerController, animated: true, completion: {
   playerController.player!.play()
})

0

Swift 5

  @IBAction func buttonPressed(_ sender: Any) {
    let videoURL = course.introductionVideoURL
    let player = AVPlayer(url: videoURL)
    let playerViewController = AVPlayerViewController()
    playerViewController.player = player

    present(playerViewController, animated: true, completion: {

        playerViewController.player!.play()
    })

// 这里的课程包括一个模型文件,在其中我已经给出了URL,因此我正在使用课程函数从模型中调用该函数。

// 同样,introductionVideoUrl是我在模型中声明的URL。

 var introductionVideoURL: URL

另外,您也可以使用以下代码而不是从模型中调用函数

替换此代码

  let videoURL = course.introductionVideoURL

使用

  guard let videoURL = URL(string: "https://something.mp4) else {
        return

0
如果你想使用AVPlayer播放视频并进行一些UI定制,最好还是涉及storyboard...就像在视频播放时占据整个屏幕(类似于Snapchat)...在视频准备好播放之前使用缩略图...并且可以轻松添加拖动手势来关闭...或者当用户按住时停止视频播放...
import UIKit
import AVKit
import AVFoundation

class CustomVideoPlayer: BaseViewController {
    
    @IBOutlet weak var videoThumbNail: UIImageView! //to show thumbnail image until the video is ready to play 
    @IBOutlet weak private var videoView: UIView! //uiview thats gonna play video 
    
    private var observer: NSKeyValueObservation?
    
    var thumbNailURL = ""
    var videoURL = ""
    
    // MARK: - Properties
    private var player: AVPlayer!
    private var playerLayer: AVPlayerLayer!
    private var isVideoPlaying = false
    private var isPlayerViewHide = true
    private var puseTime: CMTime = .zero
    private var timer: Timer?
    
    //to remove on drop guesture
    var panGestureRecognizer: UIPanGestureRecognizer?
    var originalPosition: CGPoint?
    var currentPositionTouched: CGPoint?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupThumbnail()
        setupPlayer()
    }
    
    
    override func viewDidAppear(_ animated: Bool) {
        //video again play when app comes from background
        let nc = NotificationCenter.default
        nc.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
        nc.addObserver(self, selector: #selector(appMovedToForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
        
        //remove VC to drag
        panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureAction(_:)))
        view.addGestureRecognizer(panGestureRecognizer!)
        
    }
    
    //drag down gesture to dismiss video viewcontroller
    @objc func panGestureAction(_ panGesture: UIPanGestureRecognizer) {
        let translation = panGesture.translation(in: view)
        
        if panGesture.state == .began {
          originalPosition = view.center
          currentPositionTouched = panGesture.location(in: view)
        } else if panGesture.state == .changed {
            view.frame.origin = CGPoint(
              x: translation.x,
              y: translation.y
            )
        } else if panGesture.state == .ended {
          let velocity = panGesture.velocity(in: view)

          if velocity.y >= 1500 {
            UIView.animate(withDuration: 0.2
              , animations: {
                self.view.frame.origin = CGPoint(
                  x: self.view.frame.origin.x,
                  y: self.view.frame.size.height
                )
            }, completion: { [weak self] (isCompleted) in
                if isCompleted {
                    self?.dismiss(animated: false, completion: nil)
                    self?.player.replaceCurrentItem(with: nil)
                }
            })
          } else {
            UIView.animate(withDuration: 0.2, animations: {
              self.view.center = self.originalPosition!
            })
          }
            
        }
      }
    
    
    @objc func appMovedToBackground() {
        print("video player is in background")
    }



   //again play video if user comming from background 
    @objc func appMovedToForeground() {
        print("video player is in forground")
        self.player?.play()
    }
    
    
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        playerLayer.frame = videoView.bounds
    }
    
    //set thumbnail 
    private func setupThumbnail(){
        showProgressIndicator(view: self.view)
        videoThumbNail.contentMode = .scaleAspectFill
        videoThumbNail.setImage(WithUrlString: thumbNailURL)
        
    }
    
    
    private func setupPlayer() {
        
        guard let videoURL = URL(string: videoURL) else {
            return
        }
        player = AVPlayer(url: videoURL)
        
        let asset = AVAsset(url: videoURL)
        
        let assetKeys = [
            "playable",
            "hasProtectedContent"
        ]
        
        // Create a new AVPlayerItem with the asset and an
        // array of asset keys to be automatically loaded
        let playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: assetKeys)
        
        // Register as an observer of the player item's status property
        self.observer = playerItem.observe(\.status, options:  [.new, .old], changeHandler: { (playerItem, change) in
            if playerItem.status == .readyToPlay {
                //Do your work here
                hideProgressIndicator(view: self.view)
                self.videoThumbNail.isHidden = true
                self.player?.play()
                print("ready")
            }else if playerItem.status == .failed{
                print("failed")
            }else{
                print("unknown")
            }
        })
        
        // Associate the player item with the player
        player = AVPlayer(playerItem: playerItem)
        
        playerLayer = AVPlayerLayer(player: player)
        playerLayer.videoGravity = .resizeAspectFill
        videoView.layer.addSublayer(playerLayer)
        
        //add observer when complete
        NotificationCenter.default
            .addObserver(self,
                         selector: #selector(playerDidFinishPlaying),
                         name: .AVPlayerItemDidPlayToEndTime,
                         object: player?.currentItem
            )

    }
    
    //dismiss Viewcontioller when video is complete 
    @objc func playerDidFinishPlaying(note: NSNotification) {
        print("Video Finished")
        self.dismiss(animated: true)
    }
    
    
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接