美文网首页iOS开发
Video Streaming 教程

Video Streaming 教程

作者: _浅墨_ | 来源:发表于2021-03-02 18:52 被阅读0次

本教程使用 AVKit 和 AVFoundation frameworks 制作一个 Video Streaming app。

AVKit 介绍

AVKit 位于 AVFoundation 顶部,它提供了用于与视频交互的所有必要 UI。

本 demo 的开始界面如下:

我们最后要达到的效果是,当用户点击 cell,将弹出 video player 并播放在线视频。

添加 Local Playback

可播放的视频,分为本地视频,以及存放在 server 端的视频。

接下来,我们一起开始编码实现起来。

首先,打开 VideoFeedViewController.swift,添加引用:

import AVKit

然后,在 tableView(_ tableView:didSelectRowAt:) 方法内,添加如下代码:

//1
let video = videos[indexPath.row]

//2
let videoURL = video.url
let player = AVPlayer(url: videoURL)
  1. 首先,获得 video model 对象。
  2. 所有 Video 对象都有 url 属性。我们使用 URL 创建一个 AVPlayer 对象。

AVPlayer 对象可以启动和停止视频,更改视频播放速率,以及调高或调低音量等。 我们可以将 AVPlayer 视为管理媒体资产(media asset)的控制器。

在该方法底部继续添加代码:

let playerViewController = AVPlayerViewController()
playerViewController.player = player

present(playerViewController, animated: true) {
  player.play()
}

AVPlayerViewController 是一个使用 player 对象的简洁的视图控制器。

当 presentation 动画结束后,我们可以通过调用 play() 方法来播放视频。效果如下:

AVPlayerViewController 有一组基本控件,包括一个播放器按钮,一个静音按钮以及一个向前和向后前进 15s 的快进按钮。

添加远程播放功能

打开 AppDelegate.swift,找到设置 feed.videos 那一行,替换为如下代码:

feed.videos = Video.allVideos()

进入 Video.swift 文件,查看 allVideos() 方法,我们可以看到,区别是它的 url 属性为网络链接,而不是文件路径。

在 allVideos() 内,替换如下代码

let videoURLString = 
  "https://wolverine.raywenderlich.com/content/ios/tutorials/video_streaming/foxVillage.mp4"

let videoURLString = 
  "https://wolverine.raywenderlich.com/content/ios/tutorials/video_streaming/foxVillage.m3u8"

Build and run

这两个的区别是,第二个 URL 是 HLS 实时流媒体(Livestream)类型。

HLS 实时流媒体通过将视频分成 10秒的块来工作,然后将它们一次提供给客户端。对比可知,该视频开始播放的速度比使用 MP4 格式播放快得多。

Adding a Looping Video Preview

看看右下角浮动的黑框播放器,现在我们需要添加手势事件,当单击的时候打开或者关闭声音,双击的时候使播放速度增加或者减少 2 倍。

AVFoundation 简介

我们需要熟悉几个类:

  1. AVPlayerLayer: 这个特殊的 CALayer 子类可以显示 AVPlayer 对象的播放。
  2. AVAsset: 媒体资产的静态表示。资产对象包含诸如持续时间和创建日期之类的信息。
  3. AVPlayerItem: AVAset 的动态副本,代表可播放视频的当前状态。
使用 AVPlayerLayer 写一个自定义 Video View

我们首先需要考虑的是 AVPlayerLayer,此 CALayer 子类与其他任何层一样:在屏幕上显示其 content 属性中的内容。

打开 VideoPlayerView.swift,添加以下属性,记得使用 AVPlayerLayer 而不是普通的 CALayer。

import AVFoundation

override class var layerClass: AnyClass {
  return AVPlayerLayer.self
}

override class var layerClass: AnyClass {
  return AVPlayerLayer.self
}

var playerLayer: AVPlayerLayer {
  return layer as! AVPlayerLayer
}

Build and run,可以看到

编写 Looping Video View

打开 VideoLooperView.swift,添加如下属性:

private let player = AVQueuePlayer()

此类允许我们提供将要播放对象的队列。

继续添加代码:

private func initializePlayer() {
  videoPlayerView.player = player
}

这里,我们将播放器传递到 videoPlayerView,以将其连接到 AVPlayerLayer。

现在是时候将视频片段列表添加到播放器,以便它开始播放了。

添加以下方法:

private func addAllVideosToPlayer() {
  for video in clips {
    //1
    let asset = AVURLAsset(url: video.url)
    let item = AVPlayerItem(asset: asset)

    //2
    player.insert(item, after: player.items().last)
  }
}

这里,我们在浏览所有剪辑:

  1. 由每个视频剪辑对象的 URL 创建一个 AVURLAsset。
  2. 然后,使用播放器可用来控制播放的 asset 创建一个 AVPlayerItem。
  3. 最后,使用 insert(_after:) 方法将每个项目添加到队列中。

现在,在 initializePlayer() 中调用该方法。

addAllVideosToPlayer()

player.volume = 0.0
player.play()

最后,在 init(clips:) 方法中添加调用:

initializePlayer()

Build and run:

美中不足的是,当最后一个短视频播放完毕,视频播放器会逐渐变黑。

添加循环播放

苹果编写了一个漂亮的新类,AVPlayerLooper。此类包含一个播放器项目,并负责循环播放该项目所需的所有逻辑。不幸的是,这里 AVPlayerLooper 对我们没有帮助。

我们想要的是能够循环播放所有视频,我们必须手动执行操作了。

我们需要做的是跟踪播放器及当前正在播放的 playing item。当播放到最后一个视频时,我们将所有剪辑(clips)再次添加到队列中。

我们可以使用 Key-Value Observing 跟踪 player’s information。

Key-Value Observing 是 Apple 提供的一种出色 API。此外,它还是一种实时观察和响应状态变化的有效方法。 如果你还不熟悉 KVO,这里可以快速了解下。其基本思想是,只要特定属性的值发生改变,就可以注册通知。

这里我们想知道 player 的 currentItem 何时更改。每次收到通知时,我们知道播放器已前进到下一个视频了。

代码走起来:

@objc private let player = AVQueuePlayer()

区别是我们添加了@objc 指令。这告诉 Swift,我们想将属性公开给 Objective-C 环境下的东西,例如 KVO。要在 Swift中 使用 KVO(比在Objective-C中更好),我们需要保留对观察者的引用。 在 player 之后添加以下属性:

private var token: NSKeyValueObservation?

回到 initializePlayer() 方法,添加如下代码:

token = player.observe(\.currentItem) { [weak self] player, _ in
  if player.items().count == 1 {
    self?.addAllVideosToPlayer()
  }
}

这里,我们注册一个 block,以在播放器的 currentItem 属性每次更改时运行。 当前视频更改后,需要检查播放器是否已移至最终视频。如果是最后一个,此时需要将所有视频片段(video clips)重新添加到队列中了。

Build and run,看看循环播放效果:

高效播放视频

需要注意的是,播放视频是一项资源密集型任务。实际上,即使我们开始观看全屏视频,右下角的播放器也将继续播放这些剪辑。

为了解决此问题,我们在 VideoLooperView.swift 的底部添加以下两个方法:

func pause() {
  player.pause()
}

func play() {
  player.play()
}

这里我们暴露了 play() 和 pause() 两个方法。

打开 VideoFeedViewController.swift 文件,找到 viewWillDisappear(_:) 方法,添加如下代码:

videoPreviewLooper.pause()

在 viewWillAppear(_:) 方法添加执行播放命令:

videoPreviewLooper.play()

Build and run,进入全屏播放时,右下角的 preview 将暂停播放。

使用 Player Controls 播放

接下来我们实现如下两个小功能:

  1. 单击视频,静音播放
  2. 双击视频,切换一倍速 1x和二倍速 2x

打开 VideoLooperView.swift,在 play and pause 方法下,添加代码:

@objc func wasTapped() {
  player.volume = player.volume == 1.0 ? 0.0 : 1.0
}

@objc func wasDoubleTapped() {
  player.rate = player.rate == 1.0 ? 2.0 : 1.0
}

然后添加手势事件:

相关文章

网友评论

    本文标题:Video Streaming 教程

    本文链接:https://www.haomeiwen.com/subject/ylbufltx.html