五.AV Foundation 视频播放 - 标题和字幕

引言

本篇博客主要介绍使用AV Foundation加载视频资源的时候,如何获取视频标题,获取字幕并让其显示到播放界面。

设置标题

资源标题的元数据内容,我们需要从资源的commonMetadata中获取,在加载AVPlayerItem的时候我们已经指定了需要加载commonMetadata数据,所以这里不需要做任何改动,可以在AVPlayerItem的status变为.readyToPlay的时候直接读取标题内容。

添加方法

首先我们需要在PHControlDelegate中添加两个代理方法,分别对应设置视频标题和设置设置字幕标题,并在PHControlView中实现。

protocol PHControlDelegate:NSObjectProtocol {var delegate:PHPlayerDelegate? { get set }/// 开始播放func playstart()/// 设置当前时间////// - Parameters:///   - time: 当前时间///   - duration: 总时间func setCuttentTime(time:TimeInterval,duration:TimeInterval)/// 设置视频标题////// - Parameters:///   - title: 标题func setTitle(title:String)/// 设置字幕标题////// - Parameters:///   - titles: 字幕标题数组func setSubtitle(titles:[String])/// 播放完成func playbackComplete()
}

设置标题代理方法的实现。

// 设置标题func setTitle(title: String) {titleLabel.text = title}



加载commonMetadata数据

首先来看一下创建AVPlayerItem的时候加载commonMetadata的实现。

/// 准备播放private func prepareToPlay() {let keys = ["tracks","duration","commonMetadata"]guard let asset = asset else { return }playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: keys)guard let playerItem = playerItem else { return }player = AVPlayer(playerItem: playerItem)guard let player = player else { return }playerView = PHPlayerView(player: player)self.delegate = playerView?.controlViewself.delegate?.delegate = selfplayerItem.addObserver(self, forKeyPath: status_keypath, context: &playerItemContext)}

获取标题数据

在视频准备好播放后,从commonMetadata中获取我们需要的视频标题数据。

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {if context == &playerItemContext {guard let playerItem = playerItem else { return }guard let player = player else { return }if playerItem.status == .readyToPlay{playerItem.removeObserver(self, forKeyPath: status_keypath)player.play()let duration = playerItem.duration// 同步页面开始播放self.delegate?.playstart()// 同步时间self.delegate?.setCuttentTime(time: 0.0, duration: CMTimeGetSeconds(duration))// 设置标题let assetTitle = assertTitle()self.delegate?.setTitle(title: assetTitle)// 监听播放进度addPlayerItemTimeObserver()}} else {super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)}}

获取标题数据。

/// 获取func assertTitle() -> String {var title = ""guard let asset = asset else { return title }let status = asset.status(of: .commonMetadata)if case .loaded(let metatadaItems) = status {let titleItem = metatadaItems.firstlet itemStatus = titleItem?.status(of: .value)if case .loaded(let value) = itemStatus {if let itemTitle = value as? String {title = itemTitle}}}return title}

再次运行播放器会发现播放器的左上角已经显示出了视频的标题。

设置字幕

AV Foundation为显示字幕提供了非常可靠的方法,AVPlayerLayer会自动渲染这些元数据到页面上,并且还可以手动选择需要显示那种字幕。要完成这个功能需要用到AVMediaSelectionGrop和AVMediaSelectionOption这两个类。
 

AVMediaSelectionOption标识AVAsset中的备用媒体呈现方式。比如备用音频、视频或者文本轨道。想要确定存在哪些备用轨道要用到一个名为availableMediaCharacteristicsWithMediaSelectionOptions属性。它会返回一个包含字符串的数组,这些字符串用于表示保存在资源中可用选项的媒体特征,包含AVMediaCharacteristicVisual(视频),AVMediaCharacteristicAudible(音频)、AVMediaCharacteristicLegible(字幕或隐藏式字幕)。

请求可用媒体特性数据后,调用AVAsset的mediaSelectionGroupForMediaCharacteristic:方法,(iOS16后推荐使用loadMediaSelectionGroup(for mediaCharacteristic: AVMediaCharacteristic) 方法),为其传递要检索的选项的特定媒体特征。这个方法会返回一个AVMediaSelectionGroup,它作为一个或多个互斥的AVMediaSelectionOption实例的容器。

加载availableMediaCharacteristicsWithMediaSelectionOptions数据

下面就在视频准备开始播放的时候进行字幕数据的加载,在这之前呢和加载其它元数据一样需要在创建AVPlayerItem的时候指定所需加载的元数据。

 /// 准备播放private func prepareToPlay() {let keys = ["tracks","duration","commonMetadata","availableMediaCharacteristicsWithMediaSelectionOptions"]guard let asset = asset else { return }playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: keys)guard let playerItem = playerItem else { return }player = AVPlayer(playerItem: playerItem)guard let player = player else { return }playerView = PHPlayerView(player: player)self.delegate = playerView?.controlViewself.delegate?.delegate = selfplayerItem.addObserver(self, forKeyPath: status_keypath, context: &playerItemContext)}

获取字幕数据

在监听到视频状态转换为.readyToPlay时开始调用方法处理字幕数据。

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {if context == &playerItemContext {guard let playerItem = playerItem else { return }guard let player = player else { return }if playerItem.status == .readyToPlay{playerItem.removeObserver(self, forKeyPath: status_keypath)player.play()let duration = playerItem.duration// 同步页面开始播放self.delegate?.playstart()// 同步时间self.delegate?.setCuttentTime(time: 0.0, duration: CMTimeGetSeconds(duration))// 设置标题let assetTitle = assertTitle()self.delegate?.setTitle(title: assetTitle)// 设置字幕let subtitles = loadMediaOptions()self.delegate?.setSubtitle(titles: subtitles)// 监听播放进度addPlayerItemTimeObserver()}} else {super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)}}

加载字幕方法实现。

/// 加载字幕func loadMediaOptions() -> [String] {var subtitles = [String]()guard let asset = asset else { return subtitles }let mc = AVMediaCharacteristic.legibleasset.loadMediaSelectionGroup(for: mc) {[weak self] selectionGroup, error inguard let self = self, let selectionGroup = selectionGroup else { return }// 获取字幕选项for option in selectionGroup.options {let displayName = option.displayNamesubtitles.append(displayName)}}return  subtitles}

字幕选择页面实现

获取到字幕数据后,我们借助delegate将其专递到了PHControlView中供使用,目前在控制页面还没有选择字幕的按钮,先来把它添加到播放器的右上角,并实现点击事件。

实现代理方法

// 设置字幕标题func setSubtitle(titles: [String]) {subtitles = titles}

实现点击事件。

// 显示字幕列表@objc func subtitleOnclick() {guard let subtitles = subtitles else { return }guard let delegate = delegate else { return }let alertViewController = UIAlertController(title: "选择字幕", message: nil, preferredStyle: .actionSheet)for subtitle in subtitles {let action = UIAlertAction(title: subtitle, style: .default) { action indelegate.selectedSubtitle(subtitle: subtitle)}alertViewController.addAction(action)}let cancel = UIAlertAction(title: "取消字幕", style: .cancel)alertViewController.addAction(cancel)self.window?.rootViewController?.present(alertViewController, animated: true)}

显示字幕

在播放控制器内,接收选择的字幕信息开始设置字幕。

/// 指定字幕////// - Parameters:///   - subtitle: 字幕名称func selectedSubtitle(subtitle: String) {guard let asset = asset else { return }guard let playerItem = playerItem else { return }let mc = AVMediaCharacteristic.legibleasset.loadMediaSelectionGroup(for: mc) {[weak self] selectionGroup, error inguard let self = self, let selectionGroup = selectionGroup else { return }var selected = false// 获取字幕选项for option in selectionGroup.options {if option.displayName == subtitle {playerItem.select(option, in: selectionGroup)selected = truebreak}}if selected == false {playerItem.select(nil, in: selectionGroup)}}}

结语

显示标题和字幕的功能就完成了,主要就是读取AVAsset资源中的元数据并同步到视频播放的过程中,播放器的整体用户体验有了进一步的提升。到目前为止我们在处理的都是播放过程中是逻辑,但关于视频播放结束的处理也同样重要,下一篇博客就专门来介绍关于视频资源播放结束逻辑的实现。

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/491864.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker安装mongodb

1.使用docker安装mongo 1.1下载MongoDB镜像 docker pull mongo:4.4 1.2运行MongoDB容器 docker run -itd --name mongo -v /docker_volume/mongodb/data:/data/db -p 27017:27017 mongo:4.4 --auth 2.创建用户 2.1 登录mongo容器,并进入到【admin】数据库 dock…

kafka生产者

1.原理 2.普通异步发送 引入pom&#xff1a; <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>3.0.0</version></dependency><dependency><g…

【wails】(6):使用wails做桌面应用开发,使用gin+go-chatglm.cpp进行本地模型运行,在windows上运行成功

1&#xff0c;整体架构说明 主要使用&#xff0c;参考的开源项目是&#xff1a; https://github.com/wailsapp/wails 前端项目&#xff1a; https://github.com/Chanzhaoyu/chatgpt-web 运行模型&#xff1a; https://github.com/Weaxs/go-chatglm.cpp 参考代码&#xff1a; h…

Python算法题集_实现 Trie [前缀树]

Python算法题集_实现 Trie [前缀树] 题208&#xff1a;实现 Trie (前缀树)1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【定义数据类默认字典】2) 改进版一【初始化字典无额外类】3) 改进版二【字典保存结尾信息无额外类】 4. 最优算法5. 相关…

JAVA集合进阶(Set、Map集合)

一、Set系列集合 1.1 认识Set集合的特点 Set集合是属于Collection体系下的另一个分支&#xff0c;它的特点如下图所示 下面我们用代码简单演示一下&#xff0c;每一种Set集合的特点。 //Set<Integer> set new HashSet<>(); //无序、无索引、不重复 //Set<…

Vulnhub靶机:Hacker_Kid

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;Hacker_Kid&#xff08;10.0.2.42&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://download.vulnhub.com/hac…

信息抽取(UIE):使用自然语言处理技术提升证券投资决策效率

一、引言 在当今快速变化的证券市场中&#xff0c;信息的价值不言而喻。作为一名资深项目经理&#xff0c;我曾领导一个关键项目&#xff0c;旨在通过先进的信息抽取技术&#xff0c;从海量的文本数据中提取关键事件&#xff0c;如企业并购、新产品发布以及政策环境的变动。这些…

【openGL教程08】基于C++的着色器(02)

LearnOpenGL - Shaders 一、说明 着色器是openGL渲染的重要内容&#xff0c;客户如果想自我实现渲染灵活性&#xff0c;可以用着色器进行编程&#xff0c;这种程序小脚本被传送到GPU的显卡内部&#xff0c;起到动态灵活的着色作用。 二、着色器简述 正如“Hello Triangle”一章…

常用实验室器皿耐硝酸盐酸进口PFA材质容量瓶螺纹盖密封效果好

PFA容量瓶规格参考&#xff1a;10ml、25ml、50ml、100ml、250ml、500ml、1000ml。 别名可溶性聚四氟乙烯容量瓶、特氟龙容量瓶。常用于ICP-MS、ICP-OES等痕量分析以及同位素分析等实验&#xff0c;也可在地质、电子化学品、半导体分析测试、疾控中心、制药厂、环境检测中心等机…

Linux之JAVA环境配置jdkTomcatMySQL

目录 一. 安装jdk 1.1 查询是否有jdk 1.2 解压 1.3 配置环境变量 二. 安装Tomcat&#xff08;开机自启动&#xff09; 2.1 解压 2.2 启动tomcat 2.3 防火墙设置 2.4 创建启动脚本&#xff08;设置自启动&#xff0c;服务器开启即启动&#xff09; 三. MySQL安装&#xff08;…

力扣思路题:丑数

此题的思路非常奇妙&#xff0c;可以借鉴一下 bool isUgly(int num){if(num0)return false;while(num%20)num/2;while(num%30)num/3;while(num%50)num/5;return num1; }

α-酮戊二酸钙(CaAKG)应用领域广泛 食品级CaAKG市场需求旺盛

α-酮戊二酸钙&#xff08;CaAKG&#xff09;应用领域广泛 食品级CaAKG市场需求旺盛 α-酮戊二酸钙&#xff08;CaAKG&#xff09;是α-酮戊二酸&#xff08;AKG&#xff09;的钙盐&#xff0c;外观呈白色结晶粉末。   α-酮戊二酸是三羧酸能量代谢&#xff08;TCA&#xff0…