AR+ 實時音視頻通話,虛擬與現實無縫結合

AR+ 实时音视频通话,虚拟与现实无缝结合

今年中旬 Google 在萬眾期待下推出了 ARCore(https://developers.google.com/ar/),能將現實與數碼完美無縫地融合在一起,豐富我們的現實世界。通過它開發者可以更加快速方便地在 Android 平臺開發 AR 應用,憑藉 AR 技術大量產品能找到新穎的應用場景,甚至開闢出新的一條產品線。

目前市場上已經有不少基於 AR 技術的產品,例如宜家家居的 IKEA Place 應用提供了新型的在線選購家俬方式,用戶只需要將手機攝像頭擺向想要放置傢俱的角落,接著選取你想要的傢俱,通過簡單的拖拉以及旋轉即可完成佈局,查看這件傢俱是否符合你的心意。

下圖為使用 IKEA Place 的示意圖,看起來這張椅子還挺適合的 :)

AR+ 实时音视频通话,虚拟与现实无缝结合

那麼假如 AR 與其他技術進行結合,是否會有更激動人心的應用場景呢?

七牛實時音視頻雲 (以下簡稱七牛 RTN)基於已被廣泛標準化的 WebRTC 技術棧,有全平臺的兼容性,支持各大瀏覽器如 Chrome、Safari、Firefox 以及各端 Android、iOS、Windows 等。強大的七牛實時音視頻流媒體網絡在全球有 180 多個數據中心,具有強大的鏈路加速功能,豐富的節點保證了無論客戶分佈在全球的什麼地區都可以獲得加速。平均 200ms 的超低延時,為諸多對實時性有苛刻要求的客戶場景提供最根本支持,如一對一語聊、聊天室、視頻會議、在線教育等對交互性有強需求的場景均十分適合使用七牛 RTN。

在本篇中,我們會結合 Google 官方的示例 helloarjava(https://github.com/google-ar/arcore-android-sdk)將 AR 技術融入到實時音視頻通話,其中會應用到 1.1.0+ 版本七牛 RTN SDK 的新功能 「外部音視頻數據導入」。

以下為效果動圖:

AR+ 实时音视频通话,虚拟与现实无缝结合

集成七牛 RTN SDK 到 AR Demo

在真正開始編碼前,我們需要先將相應的項目和環境搭建完成

下載 七牛 RTN SDK 到當前目錄 QNRTC-Android

git clone [email protected]:pili-engineering/QNRTC-Android.git

下載 ARCore 到當前目錄 arcore-android-sdk

git clone [email protected]:google-ar/arcore-android-sdk.git

拷貝相應七牛 RTN SDK 文件到 helloarjava 工程中

  1. 將文件 QNRTC-Android/releases/qndroid-rtc-1.2.0.jar 拷貝到 arcore-android-sdk/samples/hello_ar_java/app/libs/ 中(libs 目錄需要自行創建)


  2. 將 QNRTC-Android/releases/ 下的 armeabi、armeabi-v7a、arm64-v8a、x86 等 4 個文件夾拷貝到 arcore-android-sdk/samples/hello_ar_java/app/src/main/jniLibs 文件夾中(jniLibs 目錄需要自行創建)


  3. 使用 AndroidStudio 打開 arcore-android-sdk/samples/hello_ar_java 工程,修改其中幾項配置:


  • 為了讓工程引用上面兩步中添加的庫,打開 app/build.gradle 文件,在 中增加行 implementation fileTree(include: ['*.jar'], dir: 'libs')

  • 為了能進行實時通話,需要設置程序使用網絡的權限,打開 AndroidManifest.xml 文件,在 manifest 標籤中增加以下使用權限聲明:

    (1)

    (2)

核心類介紹

在實際編碼與代碼分析前,我們先簡單概述介紹其中會涉及到的核心類

QNRTCManager:七牛 RTN SDK 核心類,提供低延時實時音視頻通話能力

Session:ARCore 核心類,管理 AR 系統狀態包括攝像頭 Camera 採集、點網監測、平面檢測等能力

GLSurfaceView & Renderer:Android 系統提供的視圖類與渲染類,分別提供負責畫面顯示與渲染

BackgroundRenderer & ObjectRenderer & PlaneRenderer & PointCloudRenderer: Demo 中提供的渲染類,分別負責以下部分的渲染:

  • 背景圖渲染(攝像頭預覽原始圖)

  • 物體及其陰影渲染(Android 模型及其陰影)

  • 平面渲染(AR 系統檢測到的平面)

  • 點雲渲染(AR 系統檢測到的點雲)

建立基本的實時音視頻通話環境

首先需要實現實時音視頻的房間事件監聽器 QNRoomEventListener,其需要實現的方法很多,以下只展現這次簡單示例需要用到的方法,完整的接口說明在這裡(https://developer.qiniu.com/rtn/sdk/4387/qnroomeventlistener)

public class HelloArActivity extends AppCompatActivity implements GLSurfaceView.Renderer, QNRoomEventListener {
private boolean mPublished = false; // 標識本地是否發佈成功

...

@Override
public void onJoinedRoom {
mRTCManager.publish; // 加入房間成功後,嘗試發佈
}

@Override
public void onLocalPublished {
mPublished = true; // 發佈成功後,標識為 true
}

...
}

在 onCreate 方法尾部初始化實時音視頻通話環境並加入指定房間,其中關於 Room Token 獲取的方式可以參考這裡(https://developer.qiniu.com/rtn/sdk/4538/server-api-reference#5)

protected void onCreate(Bundle savedInstanceState) {
...
QNRTCSetting setting = new QNRTCSetting;
setting.setExternalVideoInputEnabled(true); // 開啟外部視頻導入功能

mRTCManager.setRoomEventListener(this); // 設置房間事件監聽器
mRTCManager.initialize(this, setting); // 七牛 RTN SDK 初始化

mRTCManager.joinRoom(###Your Room Token###); // 通過 Room Token 加入指定房間
}

建立基本的 AR 環境

利用 GLSurfaceView & Renderer

為繪製 AR 畫面做好準備

在 Activity 類聲明中實現 GLSurfaceView.Renderer 接口,在本 Demo 中如下,隨即需要我們實現 3 個相應的方法,意義分別在註釋中被描述:

public class HelloArActivity extends AppCompatActivity implements GLSurfaceView.Renderer, QNRoomEventListener {
/**
* 顯示 Surface 創建完成時回調
**/
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}

...

/**
* 顯示 Surface 尺寸大小改變時回調
**/
public void onSurfaceChanged(GL10 gl, int width, int height) {
}

...

/**
* 顯示 Surface 創建完成時回調
**/
public void onDrawFrame(GL10 gl) {
}
}

在實現了 Renderer 渲染類後,我們需要提供用作顯示的 Surface,以便讓 Renderer 在其上進行渲染顯示,GLSurfaceView 就有這種能力。

以下示例代碼,從佈局 xml 文件中解析出 GLSurfaceView 並設置 Renderer

surfaceView = findViewById(R.id.surfaceview); // 從佈局 xml 中解析 GLSurfaceView
...
surfaceView.setRenderer(this); // 設置 Renderer

創建 Session

Session 是 AR 系統的主入口類,在任何 AR 操作前必須先初始化並啟動

protected void onResume {
session = new Session(/* context= */ this); // AR 系統初始化
...
session.resume; // 開始 AR 會話,嘗試開啟攝像頭,如攝像頭被佔用,會拋出 CameraNotAvailableException 異常
}

使用 OpenGL Shader 在顯示 Surface 上

繪製 AR 增強畫面

在 AR 會話開始後,攝像頭的每一幀數據都能提供以下信息

  • 原始攝像頭預覽數據

  • 檢測到的平面數組

  • 檢測到的點雲數組

  • 平面觸摸事件

我們可以在 onDrawFrame 方法中利用以上的事件進行相應的處理,例如遇到平面觸摸事件,則在相應的位置放上一個 Android 模型,並且同時繪製出檢測到的平面以及點雲。

// 繪製背景
private final BackgroundRenderer backgroundRenderer = new BackgroundRenderer;
// 繪製物體
private final ObjectRenderer virtualObject = new ObjectRenderer;
// 繪製物體陰影
private final ObjectRenderer virtualObjectShadow = new ObjectRenderer;
// 繪製平面
private final PlaneRenderer planeRenderer = new PlaneRenderer;
// 繪製雲點
private final PointCloudRenderer pointCloudRenderer = new PointCloudRenderer;

public void onDrawFrame(GL10 gl) {
frame = session.update; // 獲取攝像頭原始數據幀(阻塞方法)

// Handle one tap per frame.
handleTap(frame, camera); // 檢測是否有平面點擊事件,如有則在相應位置放置 Android 模型

...
// Draw background.
backgroundRenderer.draw(frame); // 將攝像頭預覽數據作為背景圖繪製

...
// Visualize tracked points.
PointCloud pointCloud = frame.acquirePointCloud;
pointCloudRenderer.update(pointCloud);
pointCloudRenderer.draw(viewmtx, projmtx); // 繪製點雲

...
// Visualize planes.
planeRenderer.drawPlanes(session.getAllTrackables(Plane.class), camera.getDisplayOrientedPose, projmtx); // 繪製平面

...
// Update and draw the model and its shadow.
virtualObject.updateModelMatrix(anchorMatrix, scaleFactor);
virtualObjectShadow.updateModelMatrix(anchorMatrix, scaleFactor);
virtualObject.draw(viewmtx, projmtx, colorCorrectionRgba, coloredAnchor.color); // 繪製 Android 模型
virtualObjectShadow.draw(viewmtx, projmtx, colorCorrectionRgba, coloredAnchor.color); // 繪製 Android 模型的陰影
}

將 AR 增強畫面發佈到實時音視頻雲

在分別實現了基本的實時音視頻通話AR 增強畫面後,現在只需要將它們進行最後的結合。

因為 Session 啟動後會佔用設備攝像頭,因此七牛 RTN SDK 無法進行採集,這時候我們需要使用最新版本提供的功能「外部音視頻數據導入」。

在發佈流前,我們需要獲取到 AR 增強畫面的 NV21 格式數據,因為當前七牛 RTN Android SDK 的「外部視頻數據導入」功能只支持 NV21 格式的數據。

以下示例代碼在 onDrawFrame 方法中的尾部添加,將 GLSurfaceView 的 Surface 內容數據讀取出來,進行必要的格式轉換,接著發佈出去:

public void onDrawFrame(GL10 gl) {
...

if (mPublished) { // 只在七牛 RTN 發佈流成功後才導入 AR 數據
// 將 AR 增強畫面 的數據從 GPU 中讀取出來
GLES20.glReadPixels(0, 0, mSurfaceWidth, mSurfaceHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mBufferRGBA);

// RGBA 轉為 NV21(篇幅原因,不在此展開算法)
mBufferNV21 = RGBAToNV21(mBufferRGBA, mSurfaceWidth, mSurfaceHeight);

// 通過 "外部視頻數據導入" 功能將 NV21 數據形式的 AR 增強畫面 發佈出去
mRTCManager.inputVideoFrame(mBufferNV21, mSurfaceWidth, mSurfaceHeight, 0, frame.getTimestamp);
}
}

總結:

使用 1.1.0+ 版本七牛 RTN SDK 提供的 “外部音視頻數據導入” 功能,可以輕鬆地把 AR 和直播場景結合起來。以上程序基於七牛 RTN SDK 以及相應的 RTN 網絡運行,最大可以支持 20 人同時視頻連麥。可以預見,AR 技術會為實時音視頻通話帶來全新的體驗。

AR+ 实时音视频通话,虚拟与现实无缝结合

免費時長額度贈送活動

七牛實時音視頻雲從 10 月 30 日 起,實行每月免費時長額度贈送活動。純音頻、標清、高清、超清 4 檔位分別贈送5000 分鐘,如果完全使用,折算總消費金額共 770 元。


分享到:


相關文章: