Adicionar vídeo espacial ao seu app

O SDK Jetpack XR oferece suporte à reprodução de vídeo lado a lado estereoscópico em superfícies planas. Com o vídeo estereoscópico, cada frame consiste em uma imagem do olho esquerdo e uma do olho direito para dar aos espectadores uma sensação de profundidade.

É possível renderizar vídeos 2D não estereoscópicos em apps Android XR com as APIs de mídia padrão usadas para desenvolvimento do Android em outros formatos.

Reproduzir vídeos lado a lado usando o SDK Jetpack XR

No vídeo lado a lado, cada frame estereoscópico é apresentado como duas imagens organizadas horizontalmente uma ao lado da outra. Os frames de vídeo de cima e de baixo são organizados verticalmente, um ao lado do outro.

O vídeo lado a lado não é um codec, mas uma maneira de organizar frames estereoscópicos, o que significa que ele pode ser codificado em qualquer um dos codecs compatíveis com o Android.

Jetpack SceneCore

É possível carregar vídeos lado a lado usando o Exoplayer da Media3 e renderizá-los usando o novo SurfaceEntity. Para criar um SurfaceEntity, chame SurfaceEntity.create, conforme mostrado no exemplo abaixo.

val stereoSurfaceEntity = SurfaceEntity.create(
    xrSession,
    SurfaceEntity.StereoMode.SIDE_BY_SIDE,
    Pose(Vector3(0.0f, 0.0f, -1.5f)),
    SurfaceEntity.CanvasShape.Quad(1.0f, 1.0f)
)
val videoUri = Uri.Builder()
    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
    .path("sbs_video.mp4")
    .build()
val mediaItem = MediaItem.fromUri(videoUri)

val exoPlayer = ExoPlayer.Builder(this).build()
exoPlayer.setVideoSurface(stereoSurfaceEntity.getSurface())
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.play()

Jetpack Compose para XR

Alpha04 e mais recentes

A partir da versão 1.0.0-alpha04, o Jetpack Compose para XR oferece outra maneira de carregar e renderizar vídeos lado a lado. Use SpatialExternalSurface, um combinável de subespaço que cria e gerencia o Surface em que o app pode desenhar conteúdo, como uma imagem ou vídeo. Para mais detalhes sobre SpatialExternalSurface, consulte o guia Desenvolver interface com o Compose para XR.

Este exemplo demonstra como carregar vídeos lado a lado usando o Media3 Exoplayer e o SpatialExternalSurface.

@Composable
fun SpatialExternalSurfaceContent() {
    val context = LocalContext.current
    Subspace {
        SpatialExternalSurface(
            modifier = SubspaceModifier
                .width(1200.dp) // Default width is 400.dp if no width modifier is specified
                .height(676.dp), // Default height is 400.dp if no height modifier is specified
            // Use StereoMode.Mono, StereoMode.SideBySide, or StereoMode.TopBottom, depending
            // upon which type of content you are rendering: monoscopic content, side-by-side stereo
            // content, or top-bottom stereo content
            stereoMode = StereoMode.SideBySide,
        ) {
            val exoPlayer = remember { ExoPlayer.Builder(context).build() }
            val videoUri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                // Represents a side-by-side stereo video, where each frame contains a pair of
                // video frames arranged side-by-side. The frame on the left represents the left
                // eye view, and the frame on the right represents the right eye view.
                .path("sbs_video.mp4")
                .build()
            val mediaItem = MediaItem.fromUri(videoUri)

            // onSurfaceCreated is invoked only one time, when the Surface is created
            onSurfaceCreated { surface ->
                exoPlayer.setVideoSurface(surface)
                exoPlayer.setMediaItem(mediaItem)
                exoPlayer.prepare()
                exoPlayer.play()
            }
            // onSurfaceDestroyed is invoked when the SpatialExternalSurface composable and its
            // associated Surface are destroyed
            onSurfaceDestroyed { exoPlayer.release() }
        }
    }
}

Reproduzir vídeos de 180 e 360 graus usando o SDK do Jetpack XR

O SurfaceEntity oferece suporte à reprodução de vídeos em 180° em superfícies hemisféricas e em 360° em superfícies esféricas. Se os vídeos forem estereoscópicos, os arquivos precisam estar em um formato lado a lado.

O código a seguir mostra como configurar SurfaceEntity para reprodução em um hemisfério de 180° e uma esfera de 360°. Ao usar essas formas de tela, posicione a superfície usando a pose da cabeça do usuário para oferecer uma experiência imersiva.

.

// Set up the surface for playing a 180° video on a hemisphere.
val hemisphereStereoSurfaceEntity =
    SurfaceEntity.create(
        xrSession,
        SurfaceEntity.StereoMode.SIDE_BY_SIDE,
        xrSession.scene.spatialUser.head?.transformPoseTo(
            Pose.Identity,
            xrSession.scene.activitySpace
        )!!,
        SurfaceEntity.CanvasShape.Vr180Hemisphere(1.0f),
    )
// ... and use the surface for playing the media.

// Set up the surface for playing a 360° video on a sphere.
val sphereStereoSurfaceEntity =
    SurfaceEntity.create(
        xrSession,
        SurfaceEntity.StereoMode.TOP_BOTTOM,
        xrSession.scene.spatialUser.head?.transformPoseTo(
            Pose.Identity,
            xrSession.scene.activitySpace
        )!!,
        SurfaceEntity.CanvasShape.Vr360Sphere(1.0f),
    )
// ... and use the surface for playing the media.