iOS音视频播放指南(二)
1. 让你的App支持画中画
画中画指可以让视频在小窗中播放,可以一边看视频一边刷知乎
你可以使用AVPlayerViewController或者AVPictureInPictureController来实现画中画播放。 其中AVPictureInPictureController支持你自定义一些播放控件
在支持画中画播放之前,确保你按照iOS音视频播放指南(一) 第三部分(3.音频设置 )完成相应的设置。
AVPlayerViewController
支持画中画播放最简单的方式就是使用 AVPlayerViewController 。如果你的设备支持画中画播放,使用AVPlayerViewController点击按钮就能看到效果。支持画中画播放的设备在视频播放的时候直接返回桌面,视频也会以画中画形式继续播放。
如果你返回桌面的时候视频不会以画中画形式继续播放,检测一下设置-通用-画中画。查看是否开启
但是当你想还原画中画视频的时候,AVKit在默认情况下会停止视频的播放(系统不知道如何处理你App的用户界面),我们需要自己实现代理来完成视频的恢复。
letcontroller=AVPlayerViewController()
controller.delegate=self
extensionViewController:AVPlayerViewControllerDelegate{
//在这里处理App的恢复逻辑
funcplayerViewController(_playerViewController:AVPlayerViewController,restoreUserInterfaceForPictureInPictureStopWithCompletionHandlercompletionHandler:@escaping(Bool)->Void){
//重新present playerViewController
present(playerViewController,animated:true){
//通知系统我们已经完成了视频的界面恢复
completionHandler(true)
}
}
}
\2. 使用AVPictureInPictureController
当你自定义的播放器需要支持画中画的时候,你需要用到AVPictureInPictureController ,它管理着AVPlayerLayer。
funcsetupPictureInPicture(){
// 判断设备是否支持画中画
ifAVPictureInPictureController.isPictureInPictureSupported(){
//创建AVPlayerLayer
playerLayer=AVPlayerLayer(player:AVPlayer(url:url))
playerLayer.frame=CGRect(x:100,y:100,width:100,height:100)
view.layer.addSublayer(playerLayer)
playerLayer.player?.play()
// 创建AVPictureInPictureController
pictureInPictureController=AVPictureInPictureController(playerLayer:playerLayer)
pictureInPictureController.delegate=self
}else{
// 不支持画中画
startButton.isEnabled=false
stopButton.isEnabled=false
}
}
@objcfunctogglePictureInPictureMode(_sender:UIButton){
ifpictureInPictureController.isPictureInPictureActive{
//停止
pictureInPictureController.stopPictureInPicture()
}else{
//开始
pictureInPictureController.startPictureInPicture()
}
}
funcpictureInPictureController(_pictureInPictureController:AVPictureInPictureController,restoreUserInterfaceForPictureInPictureStopWithCompletionHandlercompletionHandler:@escaping(Bool)->Void){
//在这里进行用户视频播放界面的恢复逻辑
print("restore")
completionHandler(true)
}
funcpictureInPictureControllerWillStartPictureInPicture(_pictureInPictureController:AVPictureInPictureController){
//在界面上显示placeholder,隐藏播放控件等操作
print("will start")
}
funcpictureInPictureControllerWillStopPictureInPicture(_pictureInPictureController:AVPictureInPictureController){
//在界面上隐藏placeholder,恢复播放控件等操作
print("will stop")
}
其中AVPictureInPictureController 创建使用到了AVPlayerLayer,但是实际播放的时候PIP不使用AVPlayerLayer进行显示。当PIP开始使用的时候,系统会自动停止向AVPlayerLayer输出视频帧。
你一定要让用户通过操作(点击按钮等)来开始画中画显示。 不能直接在代码中直接startPictureInPicture ,这样的话你的APP上架审核会被拒绝。
2. 音频控制
后台播放请参考iOS音视频播放指南(一)第三部分(3.音频设置 )
当你完成后台播放设置以后,如果你播放的是音频文件,你退到后台的时候系统会自动继续播放。但是当你播放的是视频文件,默认情况下进入后台系统会自动停止播放。 如果你想在退到后台继续播放声音,需要在进入后台时断开AVPlayer的连接,进入前台重新连接。
funcsceneWillEnterForeground(_scene:UIScene){
guardletvc=(scene.delegateas?SceneDelegate)?.window?.rootViewControlleras?ViewControllerelse{
return
}
ifletplayerLayer=vc.playerLayer,letplayer=vc.player{
// 进入前台重新连接player
playerLayer.player=player
}
}
funcsceneDidEnterBackground(_scene:UIScene){
guardletvc=(scene.delegateas?SceneDelegate)?.window?.rootViewControlleras?ViewControllerelse{
return
}
ifletplayerLayer=vc.playerLayer{
// 进入后台断开与player的连接
playerLayer.player=nil
}
}
如果你的App支持后台音频播放,你可能还需要支持远程控制(耳机控制等)以及在锁屏界面的控制。这里我们使用到MediaPlayer 框架中的MPRemoteCommandCenter和MPNowPlayingInfoCenter 这两个类。
MPRemoteCommandCenter用于处理远程控制
importMediaPlayer
funcsetupRemoteTransportControls(){
// 获取 MPRemoteCommandCenter
letcommandCenter=MPRemoteCommandCenter.shared()
// 播放控制
commandCenter.playCommand.addTarget{[unownedself]eventin
ifself.player.rate==0.0{
self.player.play()
return.success
}
return.commandFailed
}
// 停止控制
commandCenter.pauseCommand.addTarget{[unownedself]eventin
ifself.player.rate==1.0{
self.player.pause()
return.success
}
return.commandFailed
}
}
MPNowPlayingInfoCenter用于锁屏界面的显示。其中我们需要注意的是AVPlayerViewController会自动刷新锁屏界面显示内容,这里我们关闭自动刷新。
funcsetupNowPlaying(){
// 由我们自己控制锁屏界面的显示,如果设置为false可能会使耳机控制失效
playerViewController.updatesNowPlayingInfoCenter=false
// 设置显示内容
varnowPlayingInfo=[String:Any]()
nowPlayingInfo[MPMediaItemPropertyTitle]="My Movie"
ifletimage=UIImage(named:"lockscreen"){
nowPlayingInfo[MPMediaItemPropertyArtwork]=
MPMediaItemArtwork(boundsSize:image.size){sizein
returnimage
}
}
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime]=playerItem.currentTime().seconds
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration]=playerItem.asset.duration.seconds
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate]=player.rate
// 提交给MPNowPlayingInfoCenter
MPNowPlayingInfoCenter.default().nowPlayingInfo=nowPlayingInfo
}
我们可以在屏幕上看到我们提供显示的内容
3. 处理中断请求
当用户观看视频的时候,如果有电话打进来,系统会自动暂停视频播放。当通话结束的时候,系统会自动恢复播放。如果你自定义了播放界面,你可能需要在这种情况下更新界面,对AVPlayer的rate属性进行KVO可以很方便的处理业务逻辑。
此外,你也可以通过监听通知来处理业务逻辑
funcsetupInterruptionNotification(){
letnotificationCenter=NotificationCenter.default
notificationCenter.addObserver(self,
selector:#selector(handleInterruption),
name:AVAudioSession.interruptionNotification,
object:nil)
}
@objcfunchandleInterruption(notification:Notification){
guardletuserInfo=notification.userInfo,
lettypeValue=userInfo[AVAudioSessionInterruptionTypeKey]as?UInt,
lettype=AVAudioSession.InterruptionType(rawValue:typeValue)else{
return
}
iftype==.began{
// 中断请求触发,在这里处理你的业务逻辑
}
elseiftype==.ended{
ifletoptionsValue=userInfo[AVAudioSessionInterruptionOptionKey]as?UInt{
letoptions=AVAudioSession.InterruptionOptions(rawValue:optionsValue)
ifoptions.contains(.shouldResume){
// 系统会自动恢复播放 (通话结束)
}else{
// 系统不会自动恢复播放
}
}
}
}
AVAudioSession一个比较重要的功能是处理音频路由变化。 一般情况下,在用户插入耳机的时候,音频会继续播放,在用户拔出耳机的时候,音频停止播放,这一切都由系统为你自动完成。你可能需要在App中对这种情况进行一些业务处理。对AVPlayer的rate属性进行KVO或者使用AVAudioSession.routeChangeNotification进行监听
funcsetupRouteChangeNotification(){
letnotificationCenter=NotificationCenter.default
notificationCenter.addObserver(self,
selector:#selector(handleRouteChange),
name:AVAudioSession.routeChangeNotification,
object:nil)
}
@objcfunchandleRouteChange(notification:Notification){
guardletuserInfo=notification.userInfo,
letreasonValue=userInfo[AVAudioSessionRouteChangeReasonKey]as?UInt,
letreason=AVAudioSession.RouteChangeReason(rawValue:reasonValue)else{
return
}
switchreason{
case.newDeviceAvailable:
//耳机插入、蓝牙连接等情况
letsession=AVAudioSession.sharedInstance()
//获取当前路由信息
foroutputinsession.currentRoute.outputswhereoutput.portType==AVAudioSession.Port.headphones{
//耳机已连接
//headphonesConnected = true
break
}
case.oldDeviceUnavailable:
//耳机拔出、蓝牙断开等情况
//获取先前的路由信息
ifletpreviousRoute=
userInfo[AVAudioSessionRouteChangePreviousRouteKey]as?AVAudioSessionRouteDescription{
foroutputinpreviousRoute.outputswhereoutput.portType==AVAudioSession.Port.headphones{
//耳机已断开连接
//headphonesConnected = false
break
}
}
default:()
}
}
原文https://zhuanlan.zhihu.com/p/335956344
★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
iOS音视频播放指南(二)相关推荐
- iOS音视频播放指南(一)
1. 简介 苹果目前提供两个框架用来处理音视频播放 1.AVFoundation AVFoundation用于播放.处理音视频.可以通过结构图看到AVFoundation位于UIKit之下,很好理解A ...
- ios nslinkattributename 自定义url_iOS音视频播放指南(二)
没看第一篇的小伙伴可以先看第一篇 wlzz:iOS音视频播放指南(一)zhuanlan.zhihu.com 本章主要内容 画中画支持 后台音频播放,锁屏界面显示,远程音频控制 在耳机插拔.接听电话等 ...
- [ISUX译]iOS 9人机界面指南(二):设计策略
[ISUX译]iOS 9人机界面指南(二):设计策略 雪糕 2015.11.09 文章索引 2.1 设计原则(Design Principles) 2.1.1 美学完整性(Aesthetic Inte ...
- iOS音视频播放-AVPlayer简单使用
按公司需求需要对音频文件进行后台播放,借此机会对音频播放做了个总结.主要针对 AVPlayer 进行详细说明. iOS 各播放器比较 名称 使用环境 优点 确点 System Sound Servic ...
- IOS音视频(三)AVFoundation 播放和录音
IOS音视频(三)AVFoundation 播放和录音 1. 音频理论知识 1.1 声音的物理性质 1.2 数字音频 1.2.1 采样.量化和编码 1.2.2 音频编码 1.3 音频编解码 2. 播放 ...
- iOS音视频开发七:视频采集
将通过拆解采集 → 编码 → 封装 → 解封装 → 解码 → 渲染流程并实现 Demo 来向大家介绍如何在 iOS/Android 平台上手音视频开发. 这里是第七篇:iOS 视频采集 Demo.这个 ...
- iOS音视频开发八:视频编码,H.264 和 H.265 都支持
我们将通过拆解采集 → 编码 → 封装 → 解封装 → 解码 → 渲染流程并实现 Demo 来向大家介绍如何在 iOS/Android 平台上手音视频开发. 这里是第八篇:iOS 视频编码 Demo. ...
- QT视频播放器(windows qt、linux qt 音视频播放器)
想要更多项目私wo!!! 一.项目简介 这是基于Qt的QMediaPlayer实现的音视频播放器,实现了播放器的常用功能,例如根据播放列表选择播放的音视频,拖动滑块控制音视频播放. 二. ...
- 李洪强iOS之集成极光推送二iOS 证书 设置指南
李洪强iOS之集成极光推送二iOS 证书 设置指南 创建应用程序ID 登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 在 iOS Provisioning ...
最新文章
- Equinix公司在巴西圣保罗开通了一个数据中心
- JAVA入门级教学之(构造方法)
- 前端windows下常用的CMD 命令归纳
- Java Object 类 深入分析
- SPSS分析技术:多元方差分析
- java 取pdf 文本域_使用PDFBox获取文本行的位置
- 程序员怒了!你敢削减专利奖金,我敢拒绝提交代码!
- 报表下拉框多选查询及一般在sql中添加查询条件
- 转:iPhone官换机和新机的区别
- asp.net 性能优化细节
- 模块电源(一):DC-DCLDO
- 换头软件测试,抖音女大十八变换脸测试
- python爬取饿了么评论_爬虫实例:饿了么爬虫
- java sqlite sqlite_busy_sqlite3 busy timeout
- Linux系统tar、rar、7z、zip压缩解压缩命令使用
- JVM性能调优1:JVM性能调优理论及实践(收集整理)
- Windows 2003 工作手册
- 反相器的Cadence仿真
- 第4关 注册配置中心实现
- 无线降噪蓝牙耳机对比:NANK南卡和苹果AirPods Pro哪个好用?