在 iOS 系统上使用声网 UIKit 进行 AR 推流

有了声网 UIKit 程序包,(ios视频直播)推流直播 AR 会话就会变得非常简单。下面我会教大家怎么通过简单几步将一个 AR 场景推流到声网。


前期准备

  • 一个声网开发者帐户(详细步骤可参考这篇文章)。
  • Xcode 12.0或更高版本
  • 配置了 iOS 13.0或更高版本的 iOS 设备(因为要使用SF Symbols)
  • 对 iOS 开发有基础的了解


设置

首先,我们在 Xcode 中创建一个单视图的 iOS 新项目,然后把声网 UIKit 程序包添加进去。

我们可以按照这个步骤添加程序包:打开并选择File > Swift Packages > Add Package Dependency,然后把这个链接粘贴到 Swift 包中:

GitHub GitHub - AgoraIO-Community/iOS-UIKit: Swift package and CocoaPod to simply... Swift package and CocoaPod to simply integrate Agora Video Calling or Live Video Streaming to your iOS or macOS app with just a few lines of code. - GitHub - AgoraIO-Community/iOS-UIKit: Swift pack...

这个程序包的最新版本(2021年11月23日)是4.0.0-preview.8。这里我们使用的版本是 SDK 4.x preview,同时示例库里还有一个配置好声网 video SDK 3.x 的这个例子的可用版本。

我们还需要添加 ARVideoKit,这是一个 Swift 包,它可以帮我们从 SceneKit 视图中捕捉音频和视频。

GitHub GitHub - AFathi/ARVideoKit: Capture & record ARKit videos 📹, photos 🌄,... Capture & record ARKit videos 📹, photos 🌄, Live Photos 🎇, and GIFs 🎆. - GitHub - AFathi/ARVideoKit: Capture & record ARKit videos 📹, photos 🌄, Live Photos 🎇, and GIFs 🎆.

如果你想了解更多信息,可以在这里找到所有示例项目:

获得更多信息

这些程序包都安装完成后,接下来就要添加摄像头和麦克风访问权限啦。如果不知道怎么添加,可以点击下面的链接查看 Apple 的文档哦:

Apple文档

搭建 UI

我们只需要在 App 上添加两个视图:

  • Augmented Reality SceneKit 视图(ARSCNView
  • 设置为 .collection 样式的 Agora UIKit 视图

我们示例的是一个常见的 SceneKit 视图,只需要先创建一个填充屏幕的 ARSCNView,然后在摄像头前( [0, 0, -3] 位置)放置一个立方体。


SceneKit

我们可以像下面这样设置 SceneKit 视图:

// Initialise and frame SceneKit view
self.sceneView = ARSCNView()
self.view.addSubview(sceneView)
self.view.sendSubviewToBack(sceneView)
sceneView.translatesAutoresizingMaskIntoConstraints = false
sceneView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
sceneView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
sceneView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
sceneView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true

// Add cube to SceneKit
let node = SCNNode(
  geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0.3)
)
node.position.z = -3
sceneView.scene.rootNode.addChildNode(node)

以上所有代码段都来自 ViewController 类的函数。


接下来,我们在 ARVideoKit 中搭建 AR Recorder。因为这个类包裹了 ARSCNView,所以它可以抓取适合的镜头以及 SceneKit 帧并把它们合并起来。

// setup ARViewRecorder
self.arvkRenderer = RecordAR(ARSceneKit: self.sceneView)
self.arvkRenderer?.renderAR = self // Set the renderer's delegate
// Configure the renderer to always render the scene
self.arvkRenderer?.onlyRenderWhileRecording = false
// Configure ARKit content mode. Default is .auto
self.arvkRenderer?.contentMode = .aspectFill
// Set the UIViewController orientations
self.arvkRenderer?.inputViewOrientations = [.portrait]
self.arvkRenderer?.enableAudio = false

在上面的示例里,我们把 renderAR 委托设置成 self,但这里的 self 指的是 ViewController实例。


我们要把 RenderARDelegate 协议添加到 ViewController 中,还要添加给我们提供视频帧的委托方法:

extension ViewController: RenderARDelegate {
  // MARK: ARVideoKit Renderer
  open func frame(
    didRender buffer: CVPixelBuffer, with time: CMTime,
    using rawBuffer: CVPixelBuffer
  ) {
    // Create AgoraVideoFrame, and push to Agora engine.
    // This part will be filled in later.
  }
}


ARKit 会话的最后一步是配置和启动 AR 会话。我一般会把这一步放进 viewDidAppear 函数。因为我们只想要一个基础的 AR 会话,所以使用 ARWorldTrackingConfiguration 这个基础配置就完全 OK :

open func setARConfiguration() {
  let configuration = ARWorldTrackingConfiguration()
  // run the config to start the ARSession
  self.arvkRenderer?.prepare(configuration)
}

一般来说我们会调用 self.sceneView.session.run(configuration) 来启动会话。但因为我们把它包裹在一个 RecordAR 对象中,所以可以直接在 arvkRenderer 对象上调用这个函数。


声网 UIKit

现在我们要使用UIKit 加入声网视频频道。记得告诉引擎我们会使用外部摄像头,要不然 UIKit 会打开默认的内置摄像头。

我们要在 AgoraSettings 中对已调用的 externalVideoSettings 接口进行设置。这个属性不但能告诉引擎我们要使用外部视频源,还能告诉引擎外部视频源的一些细节,包括视频源是否是纹理视频数据以及它是否被编码。

这里我们使用的是纹理视频数据,而且源码没有被编码。我们不想要翻转摄像头的标识,所以要像下面这样创建设置属性:

var agSettings = AgoraSettings()
agSettings.externalVideoSettings = AgoraSettings.ExternalVideoSettings(
  enabled: true, texture: true, encoded: false
)
agSettings.enabledButtons = [.cameraButton, .micButton]


然后创建一个 AgoraVideoViewer 的实例,并按照上面说的以及前面提到的 .collection 样式设置。

let agoraView = AgoraVideoViewer(
  connectionData: AgoraConnectionData(
    appId: <#Agora App ID#>,
    appToken: <#Agora Token or nil#>
  ),
  style: .collection,
  agoraSettings: agSettings
)


接下来用 AgoraVideoViewer 填充视图并加入频道,同时在 ViewController 中保持对 agoraView 的引用。

agoraView.fills(view: self.view)
agoraView.join(channel: "test", as: .broadcaster)
self.agoraView = agoraView

推送帧给声网

此时AR 场景在背景里正确渲染。任何人如果使用摄像头加入同一个频道,都会显示在视图上方。因为我们的设备没有推送任何内容,所以加入的摄像头画面不会传到远程用户端。

回到之前提到的视频帧委托方法,我们需要创建一个 AgoraVideoFrame 对象,为视频帧配置格式、像素缓冲和时间戳。

extension ViewController: RenderARDelegate {
  // MARK: ARVideoKit Renderer
  open func frame(
    didRender buffer: CVPixelBuffer, with time: CMTime,
    using rawBuffer: CVPixelBuffer
  ) {
    // Create a new AgoraVideoFrame
    let videoFrame = AgoraVideoFrame()
    videoFrame.format = 12 // format 12 means iOS texture (CVPixelBufferRef)
    videoFrame.textureBuf = buffer // set the texture buffer to our CVPixelBuffer
    videoFrame.time = time // assign the timestamp
    // Push the AgoraVideoFrame to the Agora engine
    self.agoraView?.agkit.pushExternalVideoFrame(videoFrame)
  }
}


然后,通过 AgoraVideoViewer 类抓取 AgoraRtcEngineKit 实例,把视频帧推送过去。


音频

如果你想在 SceneKit 中推流音频,还需要额外进行一些设置:


总结

你可以用这个新的视频流 App 在 iOS 系统上使用 SceneKit 推流 AR 场景,还可以在任何一个配置了兼容声网 SDK 的设备上观看这个场景。


测试

用下面的 UIKit 3.x 或 4.x SDK 试用这个实例。

测试

因为 ARVideoKit 有一些与设备方向相关的 bug,所以这次的实例我推荐只在(ios视频直播)设备直立(竖屏)时尝试。


其他资源


原文作者:Max Cobb
原文链接:https://www.agora.io/en/blog/augmented-reality-streaming-with-agora-uikit-on-ios/
推荐阅读
相关专栏
SDK 教程
167 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和声网 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。