【iOS 开发】同步快速判断视频是否可以播放

2019-04-11 17:10:50 浏览数 (1)

背景

拿到一个视频的 url 地址(无论是远程还是本地),有时候在播放之前需要检测该视频是否可以播放(本地可能是文件损坏,远端地址情况更复杂),下面介绍两种适用不同情况的方法来实现。

常用的异步方法

代码语言:javascript复制
import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    var avplayer: AVPlayer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let url = URL(string: "http://gslb.miaopai.com/stream/24fONfescp-SRz61DjJz62WO1LLIwjIQXHthNg__.mp4")!
        
        avplayer = AVPlayer(url: url)
        avplayer.addObserver(self, forKeyPath: "status", options: .new, context: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if (avplayer == object as? AVPlayer) && (keyPath == "status") {
            print((avplayer.status == .readyToPlay) ? "readyToPlay" : "fail")
        }
    }

}

如代码所示,我们可以使用 AVPlayer (MPMoviePlayerController 在 iOS 9 被 deprecated) 尝试解析 url,进行视频播放。然后可以通过 KVO 在它的 status 属性变为 “readyToPlay” 的时候,进行播放等操作。在这里这个 status 只能异步获取,如果你直接在初始化 AVPlayer 之后就同步获取这个值,这个值会是 “unknown”。

如果你在这里需要直接使用这个 AVPlayer 进行视频播放,那么推荐使用这个 KVO 方法。否则会有这样几个缺点:

  • avplayer 用于判断视频可播放性,本应该是局部变量,现在因为 KVO 它的 scope 被扩大了
  • KVO 方法在代码可读性上不如同步的直接判断
  • 控制台会默认打印下面这些东西:
代码语言:javascript复制
2017-09-05 14:43:36.983707 0800 VideoPlayable[40473:10508878] [aqme] 254: AQDefaultDevice (1): skipping input stream 0 0 0x0
2017-09-05 14:43:38.992581 0800 VideoPlayable[40473:10508878] [aqme] 254: AQDefaultDevice (173): skipping input stream 0 0 0x0
2017-09-05 14:43:41.000864 0800 VideoPlayable[40473:10508878] [aqme] 254: AQDefaultDevice (173): skipping input stream 0 0 0x0

同步判断方法

代码语言:javascript复制
import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let url = URL(string: "http://gslb.miaopai.com/stream/24fONfescp-SRz61DjJz62WO1LLIwjIQXHthNg__.mp4")!
        let avasset = AVAsset(url: url)
        print(avasset.isPlayable)
    }
}

经过一番折腾,发现直接通过 url 新建出 AVAsset,即可通过 isPlayable 属性判断视频是否可以正常播放。如果仅仅是想要判断视频可播放性,而不需要使用 AVPlayer,建议使用这种方法,可以将 AVAsset 的创建逻辑加入到你的自定义播放器的 init 方法中。

我尝试在 iPhone 6s 上使用本地的一个约 800k 的 mp4 视频进行粗略测试,发现新建 AVAsset 耗时约 0.02s,新建 AVPlayer 异步返回耗时约 0.05s,这种同步方法大概快了一倍。

0 人点赞