EmptyWalker

黑夜给了我黑色的眼睛,我却用它寻找光明

欢迎来到空行者小站


「译」使用 ARVideoKit 录制 ARKit 视频 & GIFs 动画

本文是翻译于AppCoda社区,如有版权问题,请告知,会配合处理

作者:Ahmed Fathi Bekhit - 原文地址 - 原文日期:2017-11-29

最近,移动增强现实已经成为一种趋势,它已经应用在很多应用程序中,为与人分享提供了更丰富的交互,有趣的体验。于是,主流的增强现实框架,比如 ARKit ,可以让开发者很简单地在他们的 apps 中实现复杂的计算机视觉功能,使 AR 在移动设备上成为了现实 😉 。

然而, ARKit和类似的框架,并没有简化使用增强现实组件录制视频的过程,尽管用户热衷于在使用增强现实时分享他们的有趣体验(参考面部过滤和像 AR 热狗这样的趋势),这导致了开发者去使用替代解决方案,比如 录屏或截图

在本教程中,我们将演示不使用录屏或截图如何去录制包含增强现实组件的视频GIFs。为了实现这个,我们使用一个特别构建的框架去简化渲染和录制 ARKit 视频的过程,这个框架叫做 ARVideoKit 。这个框架是使用 Apple 的 ARKitAVFoundationMetalCoreMedia 构建的,用于减掉使用相机流渲染一个 ARSCNViewARSKView 内容过程中复杂的部分。

我们开始!

开始,我们首先打开仓库的 release 页面,下载最近发布的 ARVideoKit ,然后下载 Framework.zip 文件。

然后我们将在 Xcode 里创建一个新的 ARKit 项目。对于本教程,我们创建一个 ARKit + SpriteKit 项目。

当项目创建好之后, Xcode 将会自动生成一份 SpriteKit 的示例代码给我们使用。尽管,这样对演示很有用,但我们将会对它进行一点修改,添加我们自己的用户界面,视频录制器, GIF 制作器,然后显示更多不同的 emojis 😇 !

添加框架

我们将从把 ARVideoKit 添加到项目中开始!为了正确地添加框架,需要做以下几步:

  1. 在你的项目文件夹中创建一个 Frameworks 文件夹。

  1. 把下载的 ARVideoKit.framework 拷贝到 Frameworks 文件夹中

  1. 把 ARVideoKit.framework 拖入项目 target 的 Embedded Binaries ,确保 「Copy items if needed」勾选上了。

现在,让我们在 application delegate 中配置框架,通过以下步骤:

  1. 通过添加下面的语句在 AppDelegate.swift 中导入 ARVideoKit
import ARVideoKit
  1. AppDelegate.swift 类中添加下面的方法,允许在不同的方向录制视频 & GIFs 。
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return ViewAR.orientation
}

你的 AppDelegate 文件看起来应该像这样:

import UIKit
import ARVideoKit
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
 
    var window: UIWindow?
 
 
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }
 
    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }
 
    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }
 
    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }
 
    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }
 
    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
 
    
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return ViewAR.orientation
    }
 
}

添加 UI

我们将以编程的形式构建 UI ,而不是使用 Interface Builder 。为了保持简单,我们将创建 3 个简单的按钮:录制/停止、暂停/继续、和捕获 GIFs 。

为了完成这些,在 ViewController 类中声明以下属性:

// Recorder UIButton. 这个按钮将会开始和停止视频的录制。
var recorderButton:UIButton = {
    let btn = UIButton(type: .system)
    btn.setTitle("Record", for: .normal)
    btn.setTitleColor(.black, for: .normal)
    btn.backgroundColor = .white
    btn.frame = CGRect(x: 0, y: 0, width: 110, height: 60)
    btn.center = CGPoint(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height*0.90)
    btn.layer.cornerRadius = btn.bounds.height/2
    btn.tag = 0
    return btn
}()
 
// Pause UIButton. 这个按钮将会暂停一个视频的录制。
var pauseButton:UIButton = {
    let btn = UIButton(type: .system)
    btn.setTitle("Pause", for: .normal)
    btn.setTitleColor(.black, for: .normal)
    btn.backgroundColor = .white
    btn.frame = CGRect(x: 0, y: 0, width: 60, height: 60)
    btn.center = CGPoint(x: UIScreen.main.bounds.width*0.15, y: UIScreen.main.bounds.height*0.90)
    btn.layer.cornerRadius = btn.bounds.height/2
    btn.alpha = 0.3
    btn.isEnabled = false
    return btn
}()
 
// GIF UIButton. 这个按钮将会捕获 GIF 图片。
var gifButton:UIButton = {
    let btn = UIButton(type: .system)
    btn.setTitle("GIF", for: .normal)
    btn.setTitleColor(.black, for: .normal)
    btn.backgroundColor = .white
    btn.frame = CGRect(x: 0, y: 0, width: 60, height: 60)
    btn.center = CGPoint(x: UIScreen.main.bounds.width*0.85, y: UIScreen.main.bounds.height*0.90)
    btn.layer.cornerRadius = btn.bounds.height/2
    return btn
}()

接下来,添加按钮作为 View Controller 的子视图。在 viewDidLoad() 方法中插入下面几行代码:

self.view.addSubview(recorderButton)
self.view.addSubview(pauseButton)
self.view.addSubview(gifButton)

为了处理按钮的行为,我们会创建 3 行为方法:

// 录制和停止方法
@objc func recorderAction(sender:UIButton) {
        
}
// 暂停和继续方法
@objc func pauseAction(sender:UIButton) {
    
}
// 捕获 GIF 方法
@objc func gifAction(sender:UIButton) {
 
}

现在,回到 viewDidLoad() ,添加按钮的 targets ,并把他们和上面创建的方法连接起来:

recorderButton.addTarget(self, action: #selector(recorderAction(sender:)), for: .touchUpInside)
pauseButton.addTarget(self, action: #selector(pauseAction(sender:)), for: .touchUpInside)
gifButton.addTarget(self, action: #selector(gifAction(sender:)), for: .touchUpInside)

在我们开始下一部分之前,让我们运行这个应用看看到目前为止我们已经构建的效果。如果你跟着我做的没有出错地话,你将会有一个简单的在屏幕上有三个按钮的 ARKit app 。记住你必须在真实设备上测试 app 而不是在模拟器上。

实现 ARVideoKit 框架

现在,是时候实现录制功能了!我们将会在 ViewController.swift 中实现 ARVideoKit 框架。每个第一步都是导入框架:

import ARVideoKit

接下来,创建一个 RecordAR 类型的变量。 RecordAR 是 ARView 的一个子类,使用设备相机流渲染一个 ARSCNView 或 ARSKView 的内容,去生成一个视频,图片, live 图片 或者 GIF 。

var  recorder: RecordAR?

viewDidLoad() 方法中,用 ARSKView 初始化 RecordAR ,并指定支持的方向:

// 用 SpriteKit 场景初始化
recorder = RecordAR(ARSpriteKit: sceneView)
 
// 指定支持的方向
recorder?.inputViewOrientations = [.portrait, .landscapeLeft, .landscapeRight]

为了准备录制,在 viewWillAppear(_ animated: Bool) 方法中插入以下语句:

recorder ?.prepare(configuration)

最后,当视图消失的时候,为了让录制器「休息」。在 viewWillDisappear(_ animated: Bool) 方法中插入下面一行代码:

recorder?.rest()

实现 录制/停止 和 暂停/继续 函数

现在, RecordAR 变量已经准备好了,让我们转到实现录制和停止的功能上。

对于录制行为方法,把方法更新成下面这样:

@objc func recorderAction(sender:UIButton) {
    
    if recorder?.status == .readyToRecord {
        // 开始录制
        recorder?.record()
        
        // 修改按钮标题
        sender.setTitle("Stop", for: .normal)
        sender.setTitleColor(.red, for: .normal)
        
        // 暂停按钮可用
        pauseButton.alpha = 1
        pauseButton.isEnabled = true
        
        // 是 GIF 按钮不可用
        gifButton.alpha = 0.3
        gifButton.isEnabled = false
    }else if recorder?.status == .recording || recorder?.status == .paused {
        // 停止录制并从相机卷中导出视频
        recorder?.stopAndExport()
        
        // 改变按钮标题
        sender.setTitle("Record", for: .normal)
        sender.setTitleColor(.black, for: .normal)
        
        // 使 GIF 按钮可用
        gifButton.alpha = 1
        gifButton.isEnabled = true
        
        // 使暂停按钮不可用
        pauseButton.alpha = 0.3
        pauseButton.isEnabled = false
    }
}

在上面这段代码中,我们正在检查视频录制器的状态如果是准备录制,应用程序就会开始录制 ARKit 视频。否则,如果录制器当前的状态是录制中已暂停,应用程序就会停止视频录制器,并把全部渲染后的视频导入到相册中。

接下来,我们将会在 pauseAction(sender:UIButton) 方法中实现暂停/继续功能,更新 pauseAction 方法,像下面这样:

@objc func pauseAction(sender:UIButton) {
    if recorder?.status == .recording {
        // 暂停录制
        recorder?.pause()
        
        // 改变按钮标题
        sender.setTitle("Resume", for: .normal)
        sender.setTitleColor(.blue, for: .normal)
    } else if recorder?.status == .paused {
        // 继续录制
        recorder?.record()
        
        // 改变按钮标题
        sender.setTitle("Pause", for: .normal)
        sender.setTitleColor(.black, for: .normal)
    }
}

上面这段代码很简单。我们首先检查录制器当前是否处于录制中状态,如果是,当用户点击暂停按钮时应用程序就会暂停视频录制。否则,就重新开始录制。

现在,我们来测试一下!在你的 iOS 设备运行应用程序之前,我们需要确保已经在 app 的 Info.plist 文件中添加了 cameramicrophonephoto library 的使用描述。

为了完成这个,把下面的代码添加到 plist 源码中:

<key>NSCameraUsageDescription</key>
<string>AR Camera</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Export AR Media</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Export AR Media</string>
<key>NSMicrophoneUsageDescription</key>
<string>Audiovisual Recording</string>

或者,你可以选择 Property Editor 添加这些属性:

现在让我们来运行它!📲🎊 点击录制按钮,开始录制你的 AR 视频。

示例视频 YouToBe

捕获 GIFs

最后,让我们实现 GIFs 函数,以便你可以捕获动画的 GIFs 。更新 gifAction 方法,像这样:

@objc func gifAction(sender:UIButton) {
        self.gifButton.isEnabled = false
        self.gifButton.alpha = 0.3
        self.recorderButton.isEnabled = false
        self.recorderButton.alpha = 0.3
 
        recorder?.gif(forDuration: 1.5, export: true) { _, _, _ , exported in
            if exported {
                DispatchQueue.main.sync {
                    self.gifButton.isEnabled = true
                    self.gifButton.alpha = 1.0
                    self.recorderButton.isEnabled = true
                    self.recorderButton.alpha = 1.0
                }
            }
        }
    }

修改 SpriteKit 内容

在这最后的一部分,我们将会修改 SpriteKit 的内容去在 AR 世界中展示一些不同的 emojis 🤗🤓🧐🔥 。

首先我们创建一个变量,可以从一个 emojis 的数组中返回一个随机的 emoji 。通过使用基于 C 语言的函数 arc4random_uniform() ,我们可以检索到一个在 0 到数组个数之间的随机数。

为了完成这个,我们在 ViewController 类中创建以下变量作为全局变量(在 gifButton 之后替换它):

var randoMoji: String {
    let emojis = ["👾", "🤓", "🔥", "😜", "😇", "🤣", "🤗", "🧐", "🛰", "🚀"]
    return emojis[Int(arc4random_uniform(UInt32(emojis.count)))]
}

接下来把 view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? 方法编辑成这样:

func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
    // 为添加到视图会话的锚点创建和添加一个配置
    let labelNode = SKLabelNode(text: randoMoji)
    labelNode.horizontalAlignmentMode = .center
    labelNode.verticalAlignmentMode = .center
    return labelNode;
}

我们只是使用了新创建的 randoMoji 替换了 SKLabelNode 的静态文本。

就这样!玩的开心

你现在可以在你的设备中运行你的应用程序,然后使用它去录制 ARKit 视频和GIFs!想要下载完整的项目,你可以在 GitHub 中下载

你认为这篇教程怎么样?请在下面给我留言并分享你的想法。

最近的文章

iOS 开发学习的国外网站

本文主要记录笔者正在和将要学习的一个国外网站和个人博客,会在阅读后进行一些简短的描述,当然都是基于笔者自身的角度去体验感受的。 顺序是随机,按着笔者的了解程度来的。 AppCoda 这是一位 Hong Kong 的朋友创建的,主要是介绍新的 API 和结构。很多新的框架学习可以参考本站,并且都属于入门级的,如果你对自己的英文不太自信,那就从这里开始吧,因为笔者就是这么做的。笔者翻译了很多篇该站的文章用于学习和提示英语阅读能力。 Medium 有很多短文咨询,可以...…

继续阅读
更早的文章

「译」在 iOS 中集成 Google ML Kit 进行人脸检测、人脸识别等等

本文是翻译于AppCoda社区,如有版权问题,请告知,会配合处理 原文地址 原文时间:2018-06-15就像 Apple 为她的开发者社区做了很多事情一样,另一家不遗余力的为她的开发者创造出色工具和服务的公司就是 Google 。最近几年, Google 已经发布和改进了它的多个服务,以便给 iOS 和 Android 开发者更多的功能,比如 Google Cloud 、Firebase 、 TensorFlow 等等。今年,在 Google I/O 2018 上, Google...…

继续阅读