欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > (五)深入了解AVFoundation-播放:多音轨、字幕、倍速播放与横竖屏切换

(五)深入了解AVFoundation-播放:多音轨、字幕、倍速播放与横竖屏切换

2025/4/18 13:11:41 来源:https://blog.csdn.net/weixin_39339407/article/details/147074660  浏览:    关键词:(五)深入了解AVFoundation-播放:多音轨、字幕、倍速播放与横竖屏切换

引言

在之前的博客中,我们已经实现了一个相对完整的播放器,具备了基本功能,如播放、暂停、播放进度显示和拖拽快进等。这为我们提供了一个坚实的基础。接下来,我们将进一步扩展播放器的功能,使其更具灵活性和实用性:

  • 支持多音轨播放:允许用户根据需要选择不同语言的音轨
  • 添加和切换字幕:为视频提供多语言字幕支持
  • 倍速播放:提供快进、慢放等不同的播放速度选项
  • 横竖屏切换:根据设备方向变化自动调整播放器布局,提升用户体验

通过这些进阶功能,我们的播放器将变得更加智能,能够适应更多的使用场景。

协议

我们需要定义个新的协议用来定义资源轨道处理相关的方法,包括音频轨道数据,字幕轨道数据。

import Foundation
import AVFoundationprotocol PHTrackProtocol: NSObjectProtocol {/// 更换音频轨道(Switch)/// - Parameter audioSelectionOption: 音频信息/// - Parameter group: 音频组func switchAudioSelectionOption(audioSelectionOption: AVMediaSelectionOption,group: AVMediaSelectionGroup)/// 更换字幕可以为空奥/// - Parameter subtitleSelectionOption: 字幕信息/// - Parameter group: 字幕组func switchSubtitleSelectionOption(subtitleSelectionOption: AVMediaSelectionOption?,group: AVMediaSelectionGroup)}

多音轨的的处理

视频资源本身可以包含多个音轨,音轨会嵌入到视频文件中,例如使用MP4、MKV或其它多音轨支持的格式。当我们使用AVPlayer 播放这些视频时,播放器会自动识别并提供所有可用的音轨。

获取音轨信息

我们可以通过AVAsset 获取视频中的所有音轨信息。

    /// 获取资源的所有音轨func loadAudioSelectionOptions() {guard let asset = asset else {print("PHPlayerTrackManager : Asset is nil")return}guard let group = asset.mediaSelectionGroup(forMediaCharacteristic: .audible) else {print("PHPlayerTrackManager : Group is nil")return}let options = group.optionsfor option in options {print("音轨语言:\(option.locale?.languageCode)")}audioSelectionOptions = options ?? []self.group = group}

这段代码会返回所有的音轨信息,这个音频组 (audioGroup) 中包含了所有可用的音轨选项,每一个选项是一个 AVMediaSelectionOption,代表一种语言或音轨编码方式。

切换音轨

当用户选择了不同的音轨时,我们需要更新 AVPlayerItem 的音轨设置。

播放控制器 PHPlayerController 需要遵循 PHTrackProtocol 协议,当用户切换不同的音频轨道时,在switchAudioSelectionOption(audioSelectionOption:group:) 方法内实现切换的操作。

extension PHPlayerController:PHTrackProtocol {//MARK: 资源轨道相关协议/// 更换音频轨道(Switch)/// - Parameter audioSelectionOption: 音频信息/// - Parameter group: 音频组func switchAudioSelectionOption(audioSelectionOption: AVMediaSelectionOption,group: AVMediaSelectionGroup) {print("PHPlayerController: switchAudioSelectionOption")// 选择音轨playerItem.select(audioSelectionOption, in: group)}
}

添加和切换字幕

在上一节中我们提到,AVPlayer 对于多语言音轨的支持,是通过 AVAsset 中的 mediaSelectionGroup(forMediaCharacteristic:) 方法来实现的。实际上,字幕轨道的处理方式也是一样的。

获取字幕

如果一个视频包含字幕轨道,我们可以使用同样的方式来获取字幕选择组:

    /// 加载字幕选择组func loadSubtitleSelectionOptions() {guard let asset = asset else {print("PHPlayerTrackManager : Asset is nil")return}guard let group = asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else {print("PHPlayerTrackManager : Group is nil")return}let options = group.optionsfor option in options {print("字幕语言:\(option.locale?.languageCode)")}}

在 AVFoundation 中,legible 特指“可阅读”的轨道,通常用于字幕(Subtitles)或隐藏式字幕(Closed Captions)。接下来,我们就基于这个方式,来介绍如何实现字幕的显示与切换。

展示与切换字幕

当我们获取到字幕信息之后,可以构建一个选项列表,将所有可用的字幕展示给用户。

  • option.displayName:用于展示给用户(例如“English”)
  • option.locale?.languageCode:语言代码(例如 "en"、"zh")

当用户选择了字幕之后,仍然是通过 AVPlayerItem 进行设置。

    /// 更换字幕可以为空奥/// - Parameter subtitleSelectionOption: 字幕信息/// - Parameter group: 字幕组func switchSubtitleSelectionOption(subtitleSelectionOption: AVMediaSelectionOption?,group: AVMediaSelectionGroup) {print("PHPlayerController: switchSubtitleSelectionOption")// 选择字幕playerItem.select(subtitleSelectionOption, in: group)}

倍速播放

除了音轨和字幕之外,播放器的播放速度控制也是一个比较常见的需求,尤其在教学视频或长内容消费场景中,支持 加快或减慢播放速度,能大幅提升用户体验。

在 AVPlayer 中,实现倍速播放非常简单,只需设置 rate 属性即可:

player.rate = 1.5 // 播放速度设置为 1.5 倍

协议方法

在 PHControlProtocol 协议中我们再增加一个关于设置倍速协议方法,用作在控制视图内直接设置视频播放器的播放倍速。

protocol PHControlProtocol:NSObjectProtocol {.../// 设置倍速/// - Parameter rate: 倍速func setRate(rate: Float)}

UI

控制播放的速度,显然我们需要在 PHPlayerControlView 添加新的UI组件来实现这一功能。我们直接使用按钮,点击后显示播放的速度列表来供给用户选择。

    /// 倍速按钮let speedButton = UIButton(type: .custom)// 倍速按钮self.addSubview(speedButton)speedButton.setTitleColor(.white, for: .normal)speedButton.titleLabel?.font = UIFont.systemFont(ofSize: 14)speedButton.setTitle("1x", for: .normal)

列表的具体代码如下:

class PHPlayerRateListView: UIView {/// 选项数据let rateOptions: [Float] = [0.5, 1.0, 1.5, 2.0]/// 选中倍速private var selectedRate: Float = 1.0/// 选中倍速回调var rateSelected: ((Float) -> Void)?override init(frame: CGRect) {super.init(frame: frame)addRateItems()}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func addRateItems() {for i in 0..<rateOptions.count {let rate = rateOptions[i]let button = UIButton(type: .custom)button.setTitle("\(rate)x", for: .normal)button.tag = 100 + ibutton.addTarget(self, action: #selector(rateButtonTapped(_:)), for: .touchUpInside)self.addSubview(button)button.snp.makeConstraints { make inmake.top.equalToSuperview().offset(Double(i) * 40.0)make.leading.trailing.equalToSuperview()make.height.equalTo(40.0)if i == rateOptions.count - 1 {make.bottom.equalToSuperview()}}}}/// 选项按钮点击事件/// - Parameter sender: 按钮@objc private func rateButtonTapped(_ sender: UIButton) {let rate = rateOptions[sender.tag - 100]selectedRate = raterateSelected?(rate)}}
  1. 默认速度有四个常用选项0.5、1.0、1.5、2.0。
  2. 根据选项来创建选项按钮。
  3. 当用户选择对应的速度时,通过闭包回调出去。

当用户点击倍速按钮时,开始创建并添加倍速的选项视图,具体代码如下:

    /// 倍速按钮点击事件@objc private func speedButtonTapped() {guard let controlSuperView = self.superview else { return }// 创建倍速选项视图let rateListView = PHPlayerRateListView()rateListView.layer.masksToBounds = truerateListView.layer.cornerRadius = 8.0rateListView.backgroundColor = .black.withAlphaComponent(0.5)controlSuperView.addSubview(rateListView)rateListView.snp.makeConstraints { make inmake.centerX.equalTo(speedButton)make.bottom.equalTo(speedButton.snp.centerY)make.width.equalTo(60.0)}rateListView.rateSelected = { [weak self] rate inguard let self = self else { return }// 设置倍速self.delegate?.setRate(rate: rate)// 设置倍速按钮标题self.speedButton.setTitle("\(rate)x", for: .normal)// 移除倍速选项视图rateListView.removeFromSuperview()}}
  1. 我们选择将列表视图添加在 PHPlayerOverlayView 上面。
  2. 当用户修改播放速度时,首先通过delegate修改播放器的rate属性。
  3. 然后同步倍速按钮显示状态,同时移除当前列表。

横竖屏切换(手动控制)

在视频播放的场景中,**全屏播放(横屏)**常常带来更沉浸的观看体验。而竖屏状态下则方便浏览其他界面信息。

UI

既然是对播放器的控制,那么横竖屏切换按钮就很自然的需要在 PHPlayerControlView 的视图中来添加,除了按钮之外我们还需要定义一个属性,来记录屏幕的横竖屏状态。

    /// 横竖屏切换按钮let rotateButton = UIButton(type: .custom)/// 是否是横屏private(set) var isLandscape: Bool = false// 横竖屏切换按钮self.addSubview(rotateButton)rotateButton.setImage(UIImage(named: "ph_player_rotate"), for: .normal)

实现切换

当切换按钮时,我们并不需要任何回调,直接获取 windowScene 执行切换的方法。

    /// 横竖屏切换按钮点击事件@objc private func rotateButtonTapped() {// 横竖屏切换switchOrientation(to: isLandscape ? .portrait : .landscapeRight)}// 控制方向private  func switchOrientation(to orientation: UIInterfaceOrientation) {if let windowScene = self.window?.windowScene {let geometryPreferences = UIWindowScene.GeometryPreferences.iOS(interfaceOrientations: orientation == .landscapeRight ? .landscapeRight : .portrait)isLandscape = !isLandscapewindowScene.requestGeometryUpdate(geometryPreferences) {[weak self] error inguard let self = self else { return }// 处理错误self.isLandscape = !self.isLandscapeprint("切换方向失败: \(error.localizedDescription)")}}}

但这里面会有两个细节需要注意:

  • 当我们创建 PHPlayerOverlayView 和  PHPlayerView 两个视图并添加到视图控制器时没有使用约束布局,因此需要在 viewDidLayoutSubviews() 方法中 重新设置frame。
    override func viewDidLayoutSubviews() {super.viewDidLayoutSubviews()// 设置播放器视图playerView.frame = self.view.bounds// 设置覆盖视图overlayView.frame = self.view.bounds}
  • 当我们横屏播放时,那么可以忽略底部的安全距离,因此需要调整 PHPlayerControlView 的约束。
    override func layoutSubviews() {super.layoutSubviews()// 如果是横屏controlView.snp.updateConstraints { make inmake.height.equalTo(125.0 + (controlView.isLandscape ? 0.0 : MW_BOTTOM_SAFE_HEIGHT))}}

结语

通过本篇博客,我们详细介绍了如何在 iOS 中扩展 AVPlayer 的功能,包括:

  1. • 多音轨切换,让用户能够自由选择不同的音频语言轨道;
  2. • 字幕管理,通过 AVPlayerItemLegibleOutput 实现动态字幕展示及切换;
  3. • 倍速播放,支持快进、慢放等播放速度的调整;
  4. • 横竖屏切换,通过自定义按钮实现视频播放器的方向控制。

这些功能的实现让我们的播放器更加智能和灵活,也提高了用户的观看体验。通过这些扩展,你可以构建出一个功能完备的本地视频播放器,满足更复杂的播放需求。

接下来,你可以根据需要进一步优化界面的响应能力、网络资源的支持,或是考虑实现更丰富的视频控制功能,如画中画、缩放、分屏等。未来还可以结合 iOS 的新特性,探索更多可能性,提升播放器的体验。

希望这篇博客对你有所帮助,也欢迎你在评论区分享自己的想法和问题!

感谢阅读,我们下次再见!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词