AVPlayer 是 Apple 的媒体播放器框架,属于 AVFoundation 的一部分,为 iOS、macOS、tvOS 和 visionOS 提供音频和视频播放功能。AVPlayer 支持广泛的格式——从本地 MP4 文件到自适应 HLS 流——通过统一的 API,在 Apple Silicon 芯片上实现硬件加速解码。根据 Apple WWDC (2024) 的数据,AVPlayer 被用于 90% 处理媒体的 iOS 应用程序,包括 Apple TV、Music 和 Photos。
要点
AVPlayer — 是 AVFoundation 框架的核心组件,负责在所有 Apple 平台上播放多媒体内容。于 iOS 4.0(2010)中引入,取代了过时的 MPMoviePlayerController,AVPlayer 提供对播放的低级控制,可精细调整解码参数、音视频同步,以及与 AirPlay 和画中画等系统服务的集成。
与第三方播放器不同,AVPlayer 在 Apple Silicon 芯片上享有硬件加速的优势。视频解码通过 VideoToolbox 使用 M 系列专用媒体引擎(Media Engine)进行,以最低功耗实现 8K HDR 播放。对于 HEVC(H.265)和 ProRes,解码在芯片的专用模块上进行,不增加 CPU 负载。
AVPlayer 与 Apple 生态系统紧密集成:支持 Handoff 在设备间传输播放、AirPlay 2 流式传输到 Apple TV、带动态头部跟踪的空间音频,以及通过 MPNowPlayingInfoCenter 与系统控制元素同步。这些集成使 AVPlayer 成为 Apple 平台上所有处理媒体的应用程序的事实标准。
AVFoundation 框架提供三层播放层次结构:AVAsset(关于内容的元数据和信息)、AVPlayerItem(特定内容实例的状态和管理)和 AVPlayer(播放管理)。这种架构允许分离元数据加载、播放准备和播放过程本身,这对于具有多种比特率变体的 HLS 流尤其重要。
AVAsset 表示媒体内容模型——文件或流。AVAsset 本身不可播放;它包含轨道(AVAssetTrack)、元数据(commonMetadata)、时长信息和其他特征。从 AVAsset 创建 AVPlayerItem,然后可以将其传递给 AVPlayer 进行播放。
AVPlayer 提供一套功能,涵盖大多数播放场景——从简单的文件播放到带 DRM 的复杂直播。让我们通过应用示例来了解关键功能。
| 功能 | 描述 | 平台 |
|---|---|---|
| 本地文件 | MP4、MOV、M4V、AVI、MKV(通过扩展) | iOS、macOS、tvOS |
| HLS | 带自适应 ABR 的 HTTP Live Streaming | 所有 Apple 平台 |
| FairPlay DRM | 带流许可证的受保护 HLS 内容 | iOS、tvOS、macOS |
| 画中画 | 在其他应用程序上方的浮动视频窗口 | iPad、iPhone(iOS 14+)、Mac |
| AirPlay 2 | 无线传输到 Apple TV 和扬声器 | 所有平台 |
| 空间音频 | Dolby Atmos 和动态跟踪 | iOS 15+、macOS 13+ |
| HDR | Dolby Vision、HDR10、HLG(需要显示器支持) | iOS 11+、macOS 10.13+ |
AVPlayer 原生支持 HLS,无需安装额外库。播放 HLS 流时,AVPlayer 使用内置的、针对 Apple 平台优化的 ABR 算法自动管理自适应比特率切换。该算法不仅考虑网络带宽,还考虑设备的热状态——过热时,AVPlayer 可能会降低比特率以减轻处理器负载。
对于带有 FairPlay Streaming 的 HLS 流,AVPlayer 通过 AVContentKeySession 委托自动处理许可证的获取和更新。开发人员必须实现 AVContentKeySessionDelegate 协议,当需要获取或更新解密密钥时,播放器会调用该协议。这是在 Apple 平台上保护 HLS 内容的唯一方式,因为 Widevine 在 iOS 上不受支持。
PiP — 允许用户在应用间切换时在浮动窗口中继续观看视频的模式。在 iPad 和 iPhone(iOS 14+)上,AVPlayer 与 AVPictureInPictureController 集成以启用此模式。在 macOS 15+ 上,PiP 也可用,但通过系统菜单或播放器窗口中的按钮激活。
在 iOS 应用程序中集成 AVPlayer 可以通过两种方式完成:通过高级别 AVPlayerViewController(用于典型场景)或直接通过 AVPlayer + AVPlayerLayer(用于完全自定义界面)。让我们用 Swift 来探讨这两种方法。
AVPlayerViewController — 一个现成的 UI 组件,提供内置控制元素:播放/暂停、快退、音量、AirPlay、画中画和全屏模式。最小集成只需要几行代码:创建 AVPlayer 实例,将其传递给 AVPlayerViewController,并在屏幕上显示控制器。
import AVKit
let url = URL(string: "https://example.com/video.mp4")!
let asset = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
let controller = AVPlayerViewController()
controller.player = player
controller.allowsPictureInPicturePlayback = true
present(controller, animated: true) {
player.play()
}
对于具有自定义 UI 的应用程序,使用 AVPlayerLayer —— 一个 Core Animation 层,可在任何 UIView 内渲染视频。这种方法可以完全控制界面:您可以在视频上添加自己的控制元素、动画和额外图层。
class VideoPlayerView: UIView {
var player: AVPlayer? {
get { (layer as! AVPlayerLayer).player }
set { (layer as! AVPlayerLayer).player = newValue }
}
override class var layerClass: AnyClass {
AVPlayerLayer.self
}
}
// 使用:
let playerView = VideoPlayerView(frame: view.bounds)
playerView.player = AVPlayer(url: url)
view.addSubview(playerView)
正确管理播放器的生命周期对应用程序的稳定性至关重要。AVPlayer 应在屏幕出现时创建,在关闭时释放。当应用程序进入后台时,建议暂停播放以节省资源,并避免在没有明确需要的情况下因后台播放而受到 App Review 处罚。
AVPlayerLayer — 是一个 Core Animation 层,继承自 CALayer,负责在屏幕上渲染视频。与 UIView 不同,AVPlayerLayer 通过 Metal 或 OpenGL 直接与 GPU 协作,确保最小的帧输出延迟。了解 AVPlayerLayer 的工作原理对于实现自定义播放界面是必要的。
videoGravity 属性决定视频如何适应图层边界。AVLayerVideoGravity.resizeAspect(保持宽高比,带黑边)—— AVPlayerViewController 的默认值。resizeAspectFill(填充整个屏幕并裁剪)用于全屏模式。resize(扭曲宽高比以适应图层大小)很少使用,主要用于分析应用程序。
AVPlayerLayer 实时渲染视频,但所有播放器操作(开始、暂停、跳转)必须在主线程上执行。需要观察的关键值——timeControlStatus、rate、status 和 error——通过 KVO(键值观察)或 iOS 16 中引入的、支持 Swift Concurrency 的 AVPlayer 方法的现代 async/await API 进行跟踪。
let player = AVPlayer(url: url)
let statusObservation = player.observe(
\.status,
options: [.new, .initial]
) { player, _ in
switch player.status {
case .readyToPlay:
player.play()
case .failed:
handleError(player.error)
default:
break
}
}
AVPlayer 支持 VTT、CEA-608 和 ITT(iTunes Timed Text)格式的内置字幕。音频轨道和字幕的选择通过 AVMediaSelectionGroup 和 AVMediaSelectionOption 进行。用户字幕设置(字体、大小、颜色)从系统辅助功能设置中读取,如果代码中未明确指定,则自动应用于 AVPlayerLayer。
对于生产应用,AVPlayer 的基本集成通常需要额外的配置:缓存 HLS 片段、处理 FairPlay DRM、与“Now Playing”系统集成以及实现自定义比特率选择算法。
AVAssetResourceLoader —— 是拦截 HLS 片段加载和实现缓存的唯一方式。AVAssetResourceLoaderDelegate 委托接收加载密钥和片段的请求,允许本地保存并在重复请求时从缓存返回。这对于在不稳定网络条件下运行的应用程序尤其有用。
let asset = AVURLAsset(url: hlsURL)
asset.resourceLoader.setDelegate(
resourceLoaderDelegate,
queue: DispatchQueue(label: "com.app.resourceloader")
)
let playerItem = AVPlayerItem(asset: asset)
FairPlay Streaming(FPS)—— Apple 保护 HLS 内容的标准。集成 FPS 需要实现 AVContentKeySessionDelegate 协议,该协议处理获取解密密钥的请求。过程包括:从播放器获取 SPC(服务器播放上下文)、发送到许可证服务器、接收 CKC(内容密钥上下文)并将其传递回 AVContentKeySession。
class DRMDelegate: NSObject, AVContentKeySessionDelegate {
func contentKeySession(
_ session: AVContentKeySession,
didProvide keyRequest: AVContentKeyRequest
) {
// 1. 从 keyRequest 获取 SPC
// 2. 将 SPC 发送到许可证服务器
// 3. 获取 CKC 并传递给 keyRequest.processContentKeyResponse
}
}
要在锁定屏幕、控制中心和 Apple Watch 上显示当前播放信息,使用 MediaPlayer.framework 中的 MPNowPlayingInfoCenter。AVPlayer 不会自动更新 Now Playing——开发人员必须在播放状态更改时手动设置元数据(标题、艺术家、封面、进度)。进度更新使用定期计时器或 observe(\.timeControlStatus)。
远程命令中心 —— 另一个系统服务,允许从锁定屏幕、AirPods 和 CarPlay 控制播放。MPRemoteCommandCenter 为播放、暂停、下一曲、上一曲、更改播放位置和快进/快退命令注册处理程序。AVPlayer 不会自动处理这些命令——开发人员必须将它们与 player.play()、player.pause() 和 player.seek() 调用关联起来。
常见问题
AVPlayer —— 通用音频和视频播放器,支持流媒体、HLS、DRM 以及与系统控制元素同步。AVAudioPlayer —— 简化的音频播放器,用于播放本地音频文件,不支持流媒体和硬件视频加速。视频和 HLS 使用 AVPlayer,简单音频使用 AVAudioPlayer。
不支持,AVPlayer 不支持直接加载 YouTube 内容,因为 YouTube 使用基于 DASH 和专有格式的自有播放器。要将 YouTube 集成到 iOS 应用程序中,请通过 WKWebView 使用 YouTube IFrame Player API 或官方库 youtube-ios-player-helper。
对于后台音频,在 Xcode 项目的 Background Modes 中添加 Audio, AirPlay and Picture in Picture。将 AVAudioSession 配置为 .playback 类别:try AVAudioSession.sharedInstance().setCategory(.playback)。AVPlayer 将在后台继续播放,锁定屏幕和控制中心将通过 MPNowPlayingInfoCenter 显示控制元素。
这些服务使用 DRM 保护和自有播放器解决方案。AVPlayer 只能通过直接链接到媒体文件或 HLS 播放列表来播放内容。来自 YouTube 和类似平台的视频被包装在与 AVPlayer 不兼容的 iframe 或 JavaScript 播放器中。请使用它们的官方 SDK 或 WebView 进行显示。
对于低延迟 HLS,将 AVPlayerItem 配置为 preferredForwardBufferDuration = 2.0(秒),并在落后于直播边界时自动管理暂停:使用 player.currentItem?.configuredTimeOffsetFromLive 和 player.currentItem?.canPlayReverse。Apple 建议在服务器和客户端正确配置的情况下使用延迟 2-4 秒的 LL-HLS。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。