Async Reprojection Video es una capa (denominada external surface) que una aplicación puede usar para alimentar frames de video directamente en el sistema de reproyección asíncrona. Las principales ventajas de usar la API son:
Sin la API, el video se muestrea una vez para convertirlo en el búfer de color de la aplicación, luego se vuelve a muestrear el búfer de color para realizar la corrección de la distorsión. Esto introduce artefactos de doble muestreo. La superficie externa pasa el video directamente al compositor EDS, por lo que solo se muestrea una vez, lo que mejora la calidad visual del video.
Al usar la API de superficie externa, la velocidad de frames de video está desacoplada de la velocidad de frames de la aplicación. La aplicación puede tomar 1 segundo para renderizar un nuevo frame y el único resultado es que el usuario verá barras negras cuando mueve su cabeza, el video seguirá reproduciéndose normalmente. Esto debería reducir significativamente los fotogramas de video caídos y mantener la sincronización AV
La aplicación puede marcar que quiere reproducir video DRM, y la API creará una ruta protegida que muestra videos protegidos y mantiene la velocidad de fotogramas de Reproyección Asíncrona.
Cuando se usa la reproyección de Video Async, la cámara debe comenzar en el origen (0,0,0). Pueden ocurrir errores si la posición de la cámara no está ajustada a 0,0,0.
No hay una interfaz de C # públicamente accesible para la reproyección Async. La API pública es solo Java.
Async Video Reprojection forma parte de la configuración del dispositivo Daydream VR.
Haga clic en la flecha gris junto a Daydream y luego marque la casilla Enable Video Surface para habilitar el uso de la función Async Video Reprojection
Seleccione la opción Use Protected Memory solo si necesita protección de memoria para todo su contenido, ya que esto significa que está habilitado durante toda la vida de la aplicación.
Para aprovechar la API de Google VR, deberá extender la UnityPlayerActivity. Para obtener más información, consulte la documentación sobre Ampliación de la actividad de jugador de Unity.
Los plugins de Java no pueden acceder directamente a los Objetos en su escena, por lo que deberá proporcionar una API simple a su código C # que le permitirá pasar una transformación al lado de Java e indicarle a su código Java cuándo iniciar el procesamiento.
__Nota: __ Este código no está completo. No contiene implementación de un reproductor de video, ya que es un detalle de implementación específico del cliente. Tampoco tiene controles de reproducción, que deberían implementarse como objetos en la escena y las acciones en esos objetos necesitarían llamar a Java.
Para obtener información sobre el uso de Java en Unity y la extensión de UnityPlayerActivity, consulte la documentación sobre Desarrollo de Android en Unity.
Para obtener información sobre el sistema de reproyección de Google Video Async, consulte la documentación de la Red de Desarrolladores de Android en Video Viewports.
package com.unity3d.samplevideoplayer;
import com.unity3d.player.GoogleVrVideo;
import com.unity3d.player.GoogleVrApi;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
public class GoogleAVRPlayer implements GoogleVrVideo.GoogleVrVideoCallbacks {
private static final String TAG = GoogleAVRPlayer.class.getSimpleName();
private MyOwnVideoPlayer videoPlayer;
private boolean canPlayVideo = false;
private boolean isSceneLoaded = false;
// API you present to your C# code to handle initialization of your
// video system.
public void initVideoPlayer(UnityPlayerActivity activity) {
// Initialize Video player and any other support you need…
// Register this instance as the Google Vr Video Listener to get
// lifetime and control callbacks.
GoogleVrVideo gvrv = GoogleVrApi.getGoogleVrVideo();
if (gvrv != null) gvrv.registerGoogleVrVideoListener(this);
}
// API you present to your C# code to start your video system
// playing a video.
public void play()
{
if (canPlayVideo && videoPlayer != null && videoPlayer.isPaused())
videoPlayer.play();
}
// API you present to your C# code to stop your video system
// playing a video
public void pause()
{
if (canPlayVideo && videoPlayer != null && !videoPlayer.isPaused())
videoPlayer.pause();
}
// Google Vr Video Listener
@Override
public void onSurfaceAvailable(Surface surface) {
// Google Vr has a surface available for you to render into.
// Use this surface with your video player as needed.
if (videoPlayer != null){
videoPlayer.setSurface(surface);
canPlayVideo = true;
if (isSceneLoaded)
{
videoPlayer.play();
}
}
}
@Override
public void onSurfaceUnavailable() {
// The Google Vr Video Surface is going away. You need to remove
// it from anything you have holding it and stop your video player.
if (videoPlayer != null){
videoPlayer.pause();
canPlayVideo = false;
}
}
@Override
public void onFrameAvailable() {
// Handle Google Vr frame available callback
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public class GoogleVRVideo : MonoBehaviour {
private AndroidJavaObject googleAvrPlayer = null;
private AndroidJavaObject googleVrVideo = null;
void Awake()
{
if (googleAvrPlayer == null)
{
googleAvrPlayer = new AndroidJavaObject("com.unity3d.samplevideoplayer.GoogleAVRPlayer");
}
AndroidJavaObject googleVrApi = new AndroidJavaClass("com.unity3d.player.GoogleVrApi");
if (googleVrApi != null) googleVrVideo = googleVrApi.CallStatic<AndroidJavaObject>("getGoogleVrVideo");
}
void Start()
{
if (googleVrVideo != null)
{
// We need to tell Google VR the location of the video suface in\n
// world space. Since there isn't a way to get at that info from
// Java, we can do it here and then pass the calculated matrix
// down to the api we expose on our UnityPlayerActivity subclass.
Matrix4x4 wm = transform.localToWorldMatrix;
wm = Camera.main.transform.parent.worldToLocalMatrix * wm;
wm = wm * Matrix4x4.Scale(new Vector3(0.5f, 0.5f, 1));
// Convert 4x4 Row Ordered matrix into a 16 element column ordered
// flat array. The transposition is to make sure that the matrix is
// in the order that Google uses and the we flatten it to make passing
// over the JNI boundary easier. The complication being that you have to
// then convert it back to an 4x4 matrix on the Java side.
float[] matrix = new float[16];
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
matrix[i * 4 + j] = wm[j,i];
}
}
googleVrVideo.Call("setVideoLocationTransform", matrix);
}
if (googleAvrPlayer != null)
{
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
googleAvrPlayer.Call("initVideoPlayer", jo);
googleAvrPlayer.Call("play");
}
}
}