一.显示章节标记
章节标记可以使用户快速的浏览你的内容,在tvOS和macOs中,如果你播放的资源文件包含章节标记,那么 AVPlayerViewController会自动显示,你也可以通过读取元数据中的章节信息来自定义章节选择界面。可以通过chapterMetadataGroupsBestMatchingPreferredLanguages:或者
chapterMetadataGroupsWithTitleLocale:containingItemsWithCommonKeys:来读取章节信息。
let asset = AVAsset(url: <# Asset URL #>)
let chapterLocalesKey = "availableChapterLocales"
asset.loadValuesAsynchronously(forKeys: [chapterLocalesKey]) {
var error: NSError?
let status = asset.statusOfValue(forKey: chapterLocalesKey, error: &error)
if status == .loaded {
let languages = Locale.preferredLanguages
let chapterMetadata = asset.chapterMetadataGroups(bestMatchingPreferredLanguages: languages)
// Process chapter metadata
}
else {
// Handle other status cases
}
}
这个两个方法,返回一个包含AVTimedMetadataGroup对象的数组,每一个对象代表了一个章节信息,包括CMTImerRange(定义时间范围),一个包含AVMetadataItem对象的数组,AVMetadataItem含有章节的标题,缩略图。下面代码展示了如何将AVTimedMetadataGroup对象中提取数据放入到一个Chapter的自定义数据模型中。
func convertTimedMetadataGroupsToChapters(groups: [AVTimedMetadataGroup]) -> [Chapter] {
return groups.map { group -> Chapter in
// Retrieve AVMetadataCommonIdentifierTitle metadata items
let titleItems =
AVMetadataItem.metadataItems(from: group.items,
filteredByIdentifier: AVMetadataCommonIdentifierTitle)
// Retrieve AVMetadataCommonIdentifierTitle metadata items
let artworkItems =
AVMetadataItem.metadataItems(from: group.items,
filteredByIdentifier: AVMetadataCommonIdentifierArtwork)
var title = "Default Title"
var image = UIImage(named: "placeholder")!
if let titleValue = titleItems.first?.stringValue {
title = titleValue
}
if let imgData = artworkItems.first?.dataValue, imageValue = UIImage(data: imgData) {
image = imageValue
}
return Chapter(time: group.timeRange.start, title: title, image: image)
}
}
二、选择媒体选项
AVKit和AVFoundation提供了呈现字幕和隐藏式字幕以及选择其他音频和视频轨道的功能。如果您正在构建自己的自定义播放器或想要提供自己的媒体选择界面,则可以使用AVFoundation AVMediaSelectionGroup
和AVMediaSelectionOption
类提供的功能。
AVMediaSelectionOption封装了资源元数据里提供的可供选择的,音频,视频,文字。媒体选项用来实现选择可替换相机的角度,选择本地化语言,显示字幕或隐藏式字幕。可以通过availableMediaCharacteristicsWithMediaSelectionOptions来获得播放资源支持哪些选项。
for characteristic in asset.availableMediaCharacteristicsWithMediaSelectionOptions {
print("\(characteristic)")
// Retrieve the AVMediaSelectionGroup for the specified characteristic.
if let group = asset.mediaSelectionGroup(forMediaCharacteristic: characteristic) {
// Print its options.
for option in group.options {
print(" Option: \(option.displayName)")
}
}
}
会输出类似于以下格式的数据
[AVMediaCharacteristicAudible]
Option: English
Option: Spanish
[AVMediaCharacteristicLegible]
Option: English
Option: German
Option: Spanish
Option: French
选择媒体选项:
if let group = asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristicLegible) {
let locale = Locale(identifier: "es-ES")
let options =
AVMediaSelectionGroup.mediaSelectionOptions(from: group.options, with: locale)
if let option = options.first {
// Select Spanish-language subtitle option
playerItem.select(option, in: group)
}
}
iOS7开始,AVPlayer自动根据系统偏好设置来选择媒体选项,通过将player的appliesMediaSelectionCriteriaAutomatically来禁用这个功能。
三、在后台播放音频
通常情况下设置AVAudioSession的category就可以满足在播放音频文件时,可以实现后台播放,但是在播放视频文件时,如果App进入后台,而仍然想播放音频,需要在进入后台时与AVPlayer实例解除关联,在进入前台时,重新关联。
func applicationDidEnterBackground(_ application: UIApplication) {
// Disconnect the AVPlayer from the presentation when entering background
// If presenting video with AVPlayerViewController
playerViewController.player = nil
// If presenting video with AVPlayerLayer
playerLayer.player = nil
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Reconnect the AVPlayer to the presentation when returning to foreground
// If presenting video with AVPlayerViewController
playerViewController.player = player
// If presenting video with AVPlayerLayer
playerLayer.player = player
}
如果您的应用在后台播放音频,则应支持在控制中心和iOS锁定屏幕中远程控制播放。除了控制播放外,您还应该在这些界面中提供有关当前播放内容的有用信息。要实现此功能,请使用MediaPlayer框架MPRemoteCommandCenter
和MPNowPlayingInfoCenter
类。
func setupRemoteTransportControls() {
// Get the shared MPRemoteCommandCenter
let commandCenter = MPRemoteCommandCenter.shared()
// Add handler for Play Command
commandCenter.playCommand.addTarget { [unowned self] event in
if self.player.rate == 0.0 {
self.player.play()
return .success
}
return .commandFailed
}
// Add handler for Pause Command
commandCenter.pauseCommand.addTarget { [unowned self] event in
if self.player.rate == 1.0 {
self.player.pause()
return .success
}
return .commandFailed
}
}
设置完远程控制之后,需要向用户提供正在播放的媒体信息。
func setupNowPlaying() {
// Define Now Playing Info
var nowPlayingInfo = [String : Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = "My Movie"
if let image = UIImage(named: "lockscreen") {
nowPlayingInfo[MPMediaItemPropertyArtwork] =
MPMediaItemArtwork(boundsSize: image.size) { size in
return image
}
}
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playerItem.currentTime().seconds
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = playerItem.asset.duration.seconds
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.rate
// Set the metadata
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}