iOS音视频播放指南(二)

article/2025/10/2 14:41:32

1. 让你的App支持画中画


画中画指可以让视频在小窗中播放,可以一边看视频一边刷知乎

你可以使用AVPlayerViewController或者AVPictureInPictureController来实现画中画播放。 其中AVPictureInPictureController支持你自定义一些播放控件

在支持画中画播放之前,确保你按照iOS音视频播放指南(一) 第三部分(3.音频设置 )完成相应的设置

  1. 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)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓


http://chatgpt.dhexx.cn/article/AcLQuMpo.shtml

相关文章

iOS音视频播放指南(一)

1. 简介 苹果目前提供两个框架用来处理音视频播放 1.AVFoundation AVFoundation用于播放、处理音视频。可以通过结构图看到AVFoundation位于UIKit之下,很好理解AVFoundation并不提供用户界面,你可以自己自己构建用户界面来控制媒体的播放处理等功能。 但是苹果更推荐使用AVKit来…

iOS视频播放的基本方法

本文总结了iOS中最常见的视频播放方法,不同的方法都各具特点,我希望能够总结它们的不同,方便在开发中选择合适的技术方案。 Apple为我们提供了多种方法来实现视频播放,包括MPMoviePlayerController,MPMoviePlayerView…

【计算机系统1】4 Nim游戏

目录 目的与要求 内容与方法 步骤与过程 程序总体设计 核心数据结构及算法流程 核心代码 调试过程 界面展示子程序DISPLAY(嵌套:球数展示子程序PUTBALL) 游戏子程序GAME(嵌套:单人每轮子程序PLAY) 结论或体…

java nim游戏_LeetCode 292. Nim游戏

题目描述: 你和你的朋友,两个人一起玩 Nim游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。 你们是聪明人,每一步都是最优解。 编写一个函数,来判断你…

Nim游戏、3的幂、4的幂

🍅 Java学习路线:Java学习路线 🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者💪 🍅 百日刷题计划:第 12 / 100 天。 🍅 扫描主页左侧二维码&a…

【数论】博弈论 —— nim游戏

知识点 一 . nim游戏的数学定义 Nim游戏是博弈论中最经典的模型,它又有着十分简单的规则和无比优美的结论 。 Nim游戏是组合游戏(Combinatorial Games)的一种,准确来说,属于“Impartial Combinatorial Games”(以下简称ICG&#…

【模板题】几种常见的Nim游戏(博弈论)

一、AcWing 891. Nim游戏 【题目描述】 给定 n n n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。 问如果两人都采用最优…

Kafka 为什么能那么快 | Kafka高效读写数据的原因

点击上方“服务端思维”,选择“设为星标” 回复”669“获取独家整理的精选资料集 回复”加群“加入全国服务端高端社群「后端圈」 无论 kafka 作为 MQ 也好,作为存储层也罢,无非就是两个功能(好简单的样子)&#xff0c…

【人人都懂密码学】一篇最易懂的Java密码学入门教程

密码与我们的生活息息相关,远到国家机密,近到个人账户,我们每天都在跟密码打交道: 那么,密码从何而来?生活中常见的加密是怎么实现的?怎么保证个人信息安全?本文将从这几方面进行浅谈…

Kafka必须掌握的核心技术--为什么吞吐量大、速度快?

点击上方“服务端思维”,选择“设为星标” 回复”669“获取独家整理的精选资料集 回复”加群“加入全国服务端高端社群「后端圈」 Kafka是大数据领域无处不在的消息中间件,目前广泛使用在企业内部的实时数据管道,并帮助企业构建自己的流计算应…

哪些软件问题也可导致硬盘录像机死机

硬盘录像机死机除了一些硬件上的问题之外,也有不少是由软件引起的。如: 1、病毒感染 病毒是计算机操作的大患,几乎人人恶之。病毒可以使计算机工作效率急剧下降,造成频繁死机、数据丢失、系统崩溃,甚至损坏主板、硬盘、…

导致硬盘录像机卡死的十大原因分析

硬盘录像机卡死除了一些技术上的问题之外,也有不少是由软件引起的。如: 1、病毒感染 病毒是硬盘录像机操作的大患,几乎人人恶之。病毒可以使硬盘录像机工作效率急剧下降,造成频繁死机、数据丢失、系统崩溃,甚至损坏主板…

谈项目管理和软件测试过程

谈项目管理和软件测试过程(一) 1. 软件测试在公司的组织保障是基础 1.1 研发部组织结构介绍 以华友公司研发部的组织结构为例,测试部门属于研发部副总裁直接管理,见如下结构图 公司研发部的组织结构图 …

NoSQL初探之人人都爱Redis:(1)Redis简介与简单安装

一、NoSQL的风生水起 1.1 后Web2.0时代的发展要求 随着互联网Web2.0网站的兴起,传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类型的Web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题: (1…

软件公司面试总结

文章目录 面试1面试2面试3面试4面试5面试6 面试1 1、你先做个简单的自我介绍吧 我叫张三,2015年在重庆邮电大学毕业。我读的专业是电子信息。工作已经快5年了。 我上家公司的主营业务是在柬埔寨做移动支付钱包。 最近做的一个项目是聚合支付的项目,主要…

腾讯的硬盘里,有互联网的昨天今天和明天

作者:史中 来源:浅黑科技(qianheikeji) 2018年1月1日,太阳照常升起。 世界上所有的时钟合谋,把最后一个90后推过了18岁的门槛。对于这些年轻的面孔来说,自由的风终于如期而至,只是其…

机械硬盘与SSD固态硬盘性能的深度

从7200转硬盘升级到10000转的迅猛龙,那叫量变。从10000转的迅猛龙升级到SSD,这个叫质变。2者的差距是有些地方相当大,而有些却很接近,主要是难比较。经常听到有人说:我买2个黑盘组RAID 0,传输率也有接近250…

sudo rm-rf引发的惨案——Linux硬盘的分区和挂载

前言 前不久,刚使用组里的一台服务器,这台服务器平时用的人不多, 没有严格的管理机制,大家都使用同一个用户名进行远程连接,人人都有sudo权限。我因为对Linux不是非常熟悉,使用管理员权限下执行了一个删除…

DVR-硬盘录像机

硬盘录像机(Digital Video Recorder,简称DVR),即数字视频录像机,相对于传统的模拟视频录像机,采用硬盘录像,故常常被称为硬盘录像机,也被称为DVR。 它是一套进行图像存储处理的计算…

[转]80后研制出世界最快硬盘:传输速度每秒1.5GB

传输速度每秒1.5GB,仅需3秒就能传输一张DVD光盘的数据,是普通硬盘速度的15倍。一秒钟可以访问31万次,而普通硬盘仅可以访问16次。这些数据,描绘着一款固态硬盘的卓越性能。研发出这款世界传输速度最快、性能最好的固态硬盘的&…