iOS音视频播放-AVPlayer简单使用
按公司需求需要对音频文件进行后台播放,借此机会对音频播放做了个总结.主要针对 AVPlayer 进行详细说明.
iOS 各播放器比较
名称 | 使用环境 | 优点 | 确点 |
---|---|---|---|
System Sound Services | AVFoundation | C语言的底层写法,节省内存 | 支持的格式有限,音量无法通过音量键控制,而且播放方式单一。 |
AVAudioPlayer | AVFoundation | 抒写效率更高,基本上支持所有的音频格式,对播放的控制,如循环播放,声音大小,暂停等比较方便。 | 对内存的消耗会多些。不支持流式,即无法播放在线音乐。 |
AVPlayer | AVFoundation | 可以播放音视频,可播放在线音乐,使用灵活 | |
MPMoviePlayerController | MediaPlayer | 简单易用 | 不可定制 |
AVPlayerViewController | AVKit | 简单易用 | 不可定制 |
IJKPlayer | IJKMediaFramework | 定制度高,支持流媒体播放 | 使用稍复杂 |
AVPlayer 使用
简介
AVPlayer 是iOS上常用的视频播放器组件,支持常见的音视频格式,支持流播放,可以播放在线音乐.
支持视频格式: WMV,AVI,MKV,RMVB,RM,XVID,MP4,3GP,MPG等。
支持音频格式:MP3,WMA,RM,ACC,OGG,APE,FLAC,FLV等。
相关类
- AVPlayer:播放器,控制播放器的播放,暂停,播放速度.
- AVURLAsset : AVAsset 的一个子类,使用 URL 进行实例化,实例化对象包换 URL 对应视频资源的所有信息.
- AVPlayerItem:管理资源对象,提供播放数据源.
- AVPlayerLayer:负责显示视频,如果没有添加该类,只有声音没有画面.
简单使用
使用 url 创建 AVPlayer
let player = AVPlayer(url: URL(string: "http://www.xxxx.mp3"))
使用 AVPlayerItem 创建 AVPlayer
if let url = URL(string: "http://www.***.mp3") {let asset = AVAsset(url: url)guard asset.isPlayable else{// 检测文件是否可播放return}let playItem = AVPlayerItem(asset: asset)let player = AVPlayer(playerItem: playItem)player.play()
}
AVPlayer 控制播放
player.play() // 播放
player.pause() //暂停
player.rate = 1.0 // 播放速度
通过通知监听播放状态变化
//播放完成
AVPlayerItemDidPlayToEndTimeNotification
//播放失败
AVPlayerItemFailedToPlayToEndTimeNotification
//异常中断
AVPlayerItemPlaybackStalledNotification// eg: 播放结束通知
NotificationCenter.default.addObserver(self, selector: #selector(finish(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
监听播放进度
// 添加周期时间观察者 一秒执行一次 block
let timeObserver = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 1), queue: DispatchQueue.main, using: { [weak self] (cmTime) inif let totalTime = self?.currentPlayItem?.duration {self?.delegate?.player(self!, currentTime: cmTime.seconds, totalTime: totalTime.seconds)}
})
// 不要忘记移除
player.removeTimeObserver(observer)
AVPlayerItem 创建
// 使用 AVAsset 创建
if let url = URL(string: "http://www.***.mp3") {let asset = AVAsset(url: url)guard asset.isPlayable else{// 检测文件是否可播放return}let playItem = AVPlayerItem(asset: asset)
}// 使用 URL 创建
if let url = URL(string: "http://www.***.mp3") {let playItem = AVPlayerItem(url: url)
}
监听 AVPlayerItem 状态和缓存进度
// 监听 playerItem 状态变化
playItem.addObserver(self, forKeyPath: "status", options: .new, context: nil)
// 监听缓存时间
playItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)// 移除监听
currentPlayItem?.removeObserver(self, forKeyPath: "status")
currentPlayItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {if object is AVPlayerItem {if keyPath == "status" {if let playerItem = object as? AVPlayerItem {switch playerItem.status {case .readyToPlay:// 准备播放case .failed:// 加载失败 default:// 未知状态}}}if keyPath == "loadedTimeRanges" {if let playerItem = object as? AVPlayerItem {if let timeRange = playerItem.loadedTimeRanges.first as? CMTimeRange {let cache = timeRange.start.seconds + timeRange.duration.seconds // 缓存总时长}}}}
音频后台播放
开启所需后台模式
选中Targets–>Capabilities–>BackgroundModes–>ON,
并勾选Audio and AirPlay选项,如下图:
或者 plist 文件添加如下字段:
利用 AVAudioSession 申请后台播放权限
let session = AVAudioSession.sharedInstance()
do {try session.setActive(true)try session.setCategory(AVAudioSessionCategoryPlayback)
} catch {print(error)
}
在播放控制界面接受远程控制(Remote Control)
开启远程控制
// 声明接收Remote Control事件
UIApplication.shared.beginReceivingRemoteControlEvents()
设置 Remote Control 响应
// 响应 Remote Control事件
MPRemoteCommandCenter.shared().playCommand.addTarget(self, action: #selector(play))
MPRemoteCommandCenter.shared().nextTrackCommand.addTarget(self, action: #selector(next))
MPRemoteCommandCenter.shared().pauseCommand.addTarget(self, action: #selector(pause))
MPRemoteCommandCenter.shared().previousTrackCommand.addTarget(self, action: #selector(previous))
移除 Remote Control 响应
// 在关闭播放页面时记得移除
MPRemoteCommandCenter.shared().playCommand.removeTarget(self, action: #selector(play))
MPRemoteCommandCenter.shared().nextTrackCommand.removeTarget(self, action: #selector(next))
MPRemoteCommandCenter.shared().pauseCommand.removeTarget(self, action: #selector(pause))
MPRemoteCommandCenter.shared().previousTrackCommand.removeTarget(self, action: #selector(previous))
// 停止响应 Remote Control
UIApplication.shared.endReceivingRemoteControlEvents()
通过重写父类方法响应外部事件
开启接受远程控制
使当前页面成为第一响应者
重写 remoteControlReceivedWithEvent 方法. UIEvent Type 取值:
- UIEventSubtypeRemoteControlTogglePlayPause // 暂停
- UIEventSubtypeRemoteControlPreviousTrack // 上一首
- UIEventSubtypeRemoteControlNextTrack // 下一首
- UIEventSubtypeRemoteControlPlay // 播放
- UIEventSubtypeRemoteControlPause // 暂停
关闭接受远程控制
锁屏页面显示播放信息(Now Playing Center)
使用 MPNowPlayingInfoCenter 设置锁屏页面音乐信息.
func setLockScreenPlayingInfo(_ info: YTTMediaInfo) {// Now Playing Center可以在锁屏界面展示音乐的信息,也达到增强用户体验的作用。// https://www.jianshu.com/p/458b67f84f27var infoDic: [String : Any] = [:]infoDic[MPMediaItemPropertyTitle] = info.title // 歌曲名infoDic[MPMediaItemPropertyArtist] = info.singer // 歌手if let img = info.image {infoDic[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(image: img) // 专辑图片}infoDic[MPMediaItemPropertyPlaybackDuration] = info.totalTime // 歌曲总时长infoDic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = info.currentTime // 当前播放时间infoDic[MPNowPlayingInfoPropertyPlaybackRate] = 1.0 // 播放速度MPNowPlayingInfoCenter.default().nowPlayingInfo = infoDic
}
注意: MPNowPlayingInfoPropertyElapsedPlaybackTime 设置的并不是时时的,他是根据你设置的值进行计时的,如果想要在锁屏页面得到准确的时间,请及时刷新 MPNowPlayingInfoPropertyElapsedPlaybackTime 的值.当暂停时要暂停播放时间,只需将 MPNowPlayingInfoPropertyPlaybackRate 设置为 0.播放时设置回 1.
补充说明
iOS 对后台管理十分严格,任何 app 都有大约3分钟或者10分钟的后台执行时间.3分钟或者10分钟后, app 就会被强制挂起.使用 AVAudioSession 申请后台权限时,可以保证播放本地音乐能在后台长久播放,当播放网络音乐时就会出现不能播放情况,针对这情况使用了 beginBackgroundTask 设置后台任务 ID,通过这种方式我们大约可以获得额外的 10 分钟来执行后台任务.为了能无限后台播放网络音乐添加计时器,当即将挂起时再次申请后台任务 ID.
func applicationDidEnterBackground(_ application: UIApplication) {// 这样做,可以在按home键进入后台后 ,播放一段时间,几分钟吧。但是不能持续播放网络歌曲,若需要持续播放网络歌曲,还需要申请后台任务idbgTask = application.beginBackgroundTask(expirationHandler: nil)timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}@objc func timerAction() {timerCount = timerCount + 1if timerCount < 500 {return}timerCount = 0let newTask = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)if bgTask != UIBackgroundTaskInvalid && newTask != UIBackgroundTaskInvalid {UIApplication.shared.endBackgroundTask(bgTask)bgTask = newTask}}
遇到的坑
关于 rate 倍数播放
对于 AVPlayer 的暂停和播放是通过 rate 的值来判断的,但 rate 为 1 时.播放状态,但其为 0 时为暂停.每次调用 play() 方法时,rate 的值都将会置为 1,所以当调用 play 方法时,需要重新设置 rate 的值.
关于AVPlayerItem 切换
在 iOS9 以上系统测试时AVPlayerItem切换正常,但当在 iOS8 系统下,切换了AVPlayerItem 发现无法进行播放,针对这进行百度得到解决方式,iOS8 对于replaceCurrentItem方法支持不是很好,需要每次重新创建 AVPlayer.
其他
- AVPlayer那些坑
- 项目参考地址
iOS音视频播放-AVPlayer简单使用相关推荐
- iOS音视频播放指南(二)
1. 让你的App支持画中画 画中画指可以让视频在小窗中播放,可以一边看视频一边刷知乎 你可以使用AVPlayerViewController或者AVPictureInPictureControlle ...
- iOS音视频播放指南(一)
1. 简介 苹果目前提供两个框架用来处理音视频播放 1.AVFoundation AVFoundation用于播放.处理音视频.可以通过结构图看到AVFoundation位于UIKit之下,很好理解A ...
- ios nslinkattributename 自定义url_iOS音视频播放指南(二)
没看第一篇的小伙伴可以先看第一篇 wlzz:iOS音视频播放指南(一)zhuanlan.zhihu.com 本章主要内容 画中画支持 后台音频播放,锁屏界面显示,远程音频控制 在耳机插拔.接听电话等 ...
- 6、Qt Project之音视频播放
音视频播放 这里简单的制作了一个音乐播放器,播放器的界面设计如下所示: Step1:这里是界面对应的HTML文件: <?xml version="1.0" encoding ...
- 【iOS】视频播放之AVPlayer
[iOS]视频播放之AVPlayer iOS平台使用播放视频,可用的选项一般有这四个,他们各自的作用和功能如下: 使用环境 优点 缺点 AVPlayerViewController AVKit 简单易 ...
- iOS 视频播放 - AVPlayer
iOS实现视频播放,原生代码播放视频更多的使用AVPlayer和AVPlayerViewController进行播放. 其中, AVPlayer不能单独进行播放,仅使用AVPLayer的话,还需要将其 ...
- IOS音视频(一)AVFoundation核心类
IOS音视频(一)AVFoundation核心类 1. AVFoundation框架架构简介 1.1 AVFoundation框架 1.2 AVFoundation 之 Assets 1.3 AVFo ...
- IOS音视频(三)AVFoundation 播放和录音
IOS音视频(三)AVFoundation 播放和录音 1. 音频理论知识 1.1 声音的物理性质 1.2 数字音频 1.2.1 采样.量化和编码 1.2.2 音频编码 1.3 音频编解码 2. 播放 ...
- 入门启发:音视频的简单理解
算机技术领域中,『音视频技术』应该说算是较复杂的小门类.较复杂的东西有个简单的入门指引,或者有前辈带路是很重要的. 前阵子,因为项目中急需音视频技术,虽然网上资料看似很丰富,但对初学者来说,很多资料都 ...
最新文章
- Android adb你真的会用吗?
- eoLinker-API_Shop_验证码识别与生成类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等...
- 安卓系统换成linux系统软件,将旧安卓手机打造成“简易linux”机器,并部署AdGuardHome...
- Kubernetes 是如何调度的?
- 消息中间件学习总结(11)——Kafka与RocketMQ的Topic数量对单机性能的影响比较分析
- 基于TCP/UDP的socket编程
- wine装通达信_linux下安装虚拟机,完美在linux系统下运行通达信软件
- joc杂志影响因子2019_化学sci期刊影响因子排名_国际化学期刊2018最新影响因子_分析测试学报影响因子...
- 利用公共手机获取短信验证码
- div半透明背景,文字不透明
- 【武汉加油!中国加油!】挑战七天 实现机器视觉检测有没有戴口罩系统——第四五六七天
- DellR720安装系统不能正常进入系统
- 面对新的挑战,成为更好的自己--进击的技术er
- SCS【13】单细胞转录组之识别细胞对“基因集”的响应 (AUCell)
- android 编译libjpeg-turbo
- 【机器学习】为什么机器学习难于应用
- 拓扑容差如何修改_如何在CAD中通过设置容差参数对多段线进行自动修复重构
- html本地化软件,如何为本地化做准备 (HTML)
- android ndk x86 arm,NDK r21编译FFmpeg 4.2.2(x86、x86_64、armv7、armv8)
- AP_应付税务预扣税Withholding Tax中付款时产生预扣税(案例)