四.AV Foundation 视频播放 - 进度同步

引言

现在播放器已经拥有了核心的播放功能,包括基本的播放和暂停控制功能,以及通过拖拽进度条实现快进功能。然而,我们注意到在视频播放的过程中,播放进度并没有显示出来,当前时间也没有发生任何变化。这显然不能令用户满意。下面我们就来实现播放进度的同步功能,使用户更加方便地掌控视频的播放,提升使用体验。

实现方案

AVPlayer提供了两种基于时间的监听方法,让应用程序可以对时间变化进行精准的监听。

定期监听

利用AVPlayer提供的addPeriodicTimeObserver(forInterval:, queue:, using:)方法可以实现以一定时间间隔获得通知。该方法有如下三个参数:

interval:用于注定通知周期的CMTime。

queue:通知发送的顺序调度队列。大多数时候我们会指定在主队列。

block:在指定的时间间隔中会在指定的队列上调用的block,这个block会回传一个CMTime表示播放器的当前时间。

边界时间监听

还有一种更具针对性的方法来监听时间,我们可以得到播放器时间轴中多个边界点的遍历结果。比如我们可定义25%,50%的边界标记,来判断用户播放进度。这个功能需要用到addBoundaryTimeObserver(forTimes:, queue: , using: )方法,该方法参数如下:

times:CMTime值组成一个NSArray数组定义了需要通知的边界点。

queue:与定期监听类似,为方法提供一个用来发送通知的顺序调度队列。

block:每当正常播放中跨越一个边界点时就会在队列中调用这个回调块。但该块不提供遍历的CMTime值,所以我们需要为此执行一些额外计算进行确定。

我们就采用定期监听的方案,将时间间隔设置为0.5来监听播放器的进度。然后通过代理将进度来同步到播放页面的PHControlView。

/// 监听播放进度func addPlayerItemTimeObserver() {guard let player = player else { return }let interval = CMTimeMakeWithSeconds(0.5, preferredTimescale: Int32(NSEC_PER_SEC))let queue = DispatchQueue.maintimeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: queue, using: {[weak self] time inguard let self = self else { return }guard let playerItem = self.playerItem else { return }guard let delegate = self.delegate else { return }let currentTime = CMTimeGetSeconds(time)let duration = CMTimeGetSeconds(playerItem.duration)delegate.setCuttentTime(time: currentTime, duration: duration)})}

代理方法在PHControlView的实现,来同步进度条的进度,以及播放时间信息。

//MARK: PHControlDelegate/// 设置时间func setCuttentTime(time: TimeInterval, duration: TimeInterval) {currentTimeLabel.text = timeString(from: time)totalTimeLabel.text = timeString(from: duration)sliderView.minimumValue = 0.0sliderView.maximumValue = Float(duration)sliderView.value = Float(time)}

在监听到播放资源准备完成开始播放的时候调用监听播放进度的方法。

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.durationself.delegate?.playstart()self.delegate?.setCuttentTime(time: 0.0, duration: CMTimeGetSeconds(duration))addPlayerItemTimeObserver()}} else {super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)}}

现在在运行代码,我们就能发现播放进度的同步功能就已经完成了。

结语

同步播放进度的整体代码并不复杂,值得注意的是我们不能使用KVO来监听播放器的播放时间,因为这些信息需要非常高的精确度,比键值监听要求要高。更不能开始定时器自己来处理播放进度的时间,会产生很大的误差。
现在播放器已经与大多数视频播放器一样,具备了所有的播放器功能。但视频的标题,视频的字幕还没有显示出来,下一篇我们来处理这两组元数据,将标题和字幕显示到播放器中。

项目地址:PHPlayer: 视频播放器
 

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

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

相关文章

《PCI Express体系结构导读》随记 —— 第II篇 第13章 PCI总线与虚拟化技术(6)

接前一篇文章:《PCI Express体系结构导读》随记 —— 第II篇 第13章 PCI总线与虚拟化技术(5) 13.2 ATS(Address Translation Services) 单纯使用IOMMU并不能充分发挥处理器系统的效率,从图13-2中可以发现&…

Java基于微信小程序的医院挂号小程序,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

ERP系统扫盲:B端系统的集大成,其他系统都是弟弟。

B端管理系统扫盲的最后一篇,留给ERP吧。ERP可说是B端管理系统的集大成者,貌似什么功能都可以纳入ERP中,也貌似其他B端管理系统也就是ERP的一个分支而已。 一、ERP定义 ERP(Enterprise Resource Planning)是企业资源计…

第13章 网络 Page738~741 13.8.3 TCP/UDP简述

libcurl是C语言写成的网络编程工具库,asio是C写的网络编程的基础类型库 libcurl只用于客户端,asio既可以写客户端,也可以写服务端 libcurl实现了HTTP\FTP等应用层协议,但asio却只实现了传输层TCP/UDP等协议。 在学习http时介绍…

深入探讨Lambda表达式转换为委托类型的编译过程

了解了,如果要深入探讨Lambda表达式转换为委托类型的编译过程,我们需要关注C#编译器如何处理这个转换。这个过程涉及到编译时的类型推断、匿名方法的创建,以及生成对应的委托实例。我们来更详细地分析这个过程: 编译阶段 1. 解…

猫头虎分享:一文带你搞懂什么是SaaS、PaaS、LaaS、CaaS、FaaS、MBaaS

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …

NodeLocal DNS介绍及部署应用

1 NodeLocal DNS是什么? NodeLocal DNSCache 通过在集群节点上运行一个 DaemonSet 来提高 clusterDNS 性能和可靠性。处于 ClusterFirst 的 DNS 模式下的 Pod 可以连接到 kube-dns 的 serviceIP 进行 DNS 查询。通过 kube-proxy 组件添加的 iptables 规则将其转换为…

463. Island Perimeter(岛屿的周长)

问题描述 给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] 1 表示陆地, grid[i][j] 0 表示水域。 网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有…

肆拾玖坊泰斗酒,春节佳节送礼首选

眼看着童年春节就要到来了,作为一家人难得团团圆圆的日子,除了和家人一同吃团圆饭看春晚以外,很多人还会在正月里开始走亲访友,这时候也是礼尚往来的好时机,选择一瓶上好的美酒,带着和家人美好的祝福,去拜访难得一见的亲朋好友,共度佳节,这样才有着浓浓的年味。 很多人不知道肆…

Unity类银河恶魔城学习记录7-6 P72 Bouncy sword源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Sword_Skill_Controller.cs using System.Collections; using System.Colle…

[AIGC] 利用 chatgpt 深入理解 Java 虚拟机(JVM)

Java 虚拟机(JVM)是 Java 编程语言的核心运行环境,它负责解释和执行 Java 字节码。它是 Java 程序能够跨平台运行的关键,因为不同的操作系统和硬件平台都有自己的指令集和体系结构,而 JVM 则提供了一个统一的运行环境&…

梵宁教育:虚假宣传不实控诉,真相公布于众

近期,网络上出现了一些关于梵宁教育虚假宣传的言论,给梵宁教育及广大消费者带来了困扰和误解。作为负责任的教育机构,梵宁教育有必要站出来澄清这些不实言论,还原事实真相。 一、梵宁教育的基本情况 梵宁教育是一家致力于为学生…