Superficies externas espaciales

Dispositivos de realidad extendida correspondientes
Esta guía te ayuda a crear experiencias para estos tipos de dispositivos de realidad extendida.
Visores de realidad extendida
Lentes de realidad extendida con cable

Un SpatialExternalSurface es un elemento componible de subespacio que crea y administra el Surface en el que tu app puede dibujar contenido, como una imagen o un video. SpatialExternalSurface admite contenido estereoscópico o monoscópico.

Agrega una superficie para el contenido de imagen o video

En este ejemplo, se muestra cómo cargar un video estereoscópico en paralelo con Media3 Exoplayer y SpatialExternalSurface:

@OptIn(ExperimentalComposeApi::class)
@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() }
        }
    }
}

Puntos clave sobre el código

  • Establece StereoMode como Mono, SideBySide o TopBottom según el tipo de contenido que renderices:
    • Mono: La imagen o el fotograma consta de una sola imagen idéntica que se muestra en ambos ojos.
    • SideBySide: La imagen o el fotograma contiene un par de imágenes o fotogramas dispuestos uno al lado del otro, en los que la imagen o el fotograma de la izquierda representa la vista del ojo izquierdo, y la imagen o el fotograma de la derecha representa la vista del ojo derecho.
    • TopBottom: La imagen o el fotograma contiene un par de imágenes o fotogramas de video apilados verticalmente, en los que la imagen o el fotograma de la parte superior representan la vista del ojo izquierdo, y la imagen o el fotograma de la parte inferior representan la vista del ojo derecho.
  • SpatialExternalSurface solo admite superficies rectangulares.
  • Este Surface no captura eventos de entrada.
  • No es posible sincronizar los cambios de StereoMode con la renderización de la aplicación ni la decodificación de video.
  • Este elemento componible no se puede renderizar delante de otros paneles, por lo que no debes usar un MovePolicy si hay otros paneles en el diseño.

Agrega una plataforma para el contenido de video protegido por DRM

SpatialExternalSurface también admite la reproducción de transmisiones de video por Internet protegidas por DRM. Para habilitar esto, debes crear una superficie segura que se renderice en búferes gráficos protegidos. Esto evita que el contenido se grabe en pantalla o que los componentes del sistema no seguros accedan a él.

Para crear una superficie segura, establece el parámetro SpatialExternalSurfaceProtection en SpatialExternalSurfaceProtection.Protected en el elemento componible SpatialExternalSurface. Además, debes configurar Media3 ExoPlayer con la información de DRM adecuada para controlar la adquisición de licencias desde un servidor de licencias.

En el siguiente ejemplo, se muestra cómo configurar SpatialExternalSurface y ExoPlayer para reproducir una transmisión de video por Internet protegida por DRM:

@OptIn(ExperimentalComposeApi::class)
@Composable
fun DrmSpatialVideoPlayer() {
    val context = LocalContext.current
    Subspace {
        SpatialExternalSurface(
            modifier = SubspaceModifier
                .width(1200.dp)
                .height(676.dp),
            stereoMode = StereoMode.SideBySide,
            surfaceProtection = SpatialExternalSurfaceProtection.Protected
        ) {
            val exoPlayer = remember { ExoPlayer.Builder(context).build() }

            // Define the URI for your DRM-protected content and license server.
            val videoUri = "https://your-content-provider.com/video.mpd"
            val drmLicenseUrl = "https://your-license-server.com/license"

            // Build a MediaItem with the necessary DRM configuration.
            val mediaItem = MediaItem.Builder()
                .setUri(videoUri)
                .setDrmConfiguration(
                    MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
                        .setLicenseUri(drmLicenseUrl)
                        .build()
                )
                .build()

            onSurfaceCreated { surface ->
                // The created surface is secure and can be used by the player.
                exoPlayer.setVideoSurface(surface)
                exoPlayer.setMediaItem(mediaItem)
                exoPlayer.prepare()
                exoPlayer.play()
            }

            onSurfaceDestroyed { exoPlayer.release() }
        }
    }
}

Puntos clave sobre el código

  • Superficie protegida: Configurar surfaceProtection = SpatialExternalSurfaceProtection.Protected en SpatialExternalSurface es esencial para que el Surface subyacente esté respaldado por búferes seguros adecuados para el contenido de DRM.
  • Configuración de DRM: Debes configurar el MediaItem con el esquema de DRM (por ejemplo, C.WIDEVINE_UUID) y el URI de tu servidor de licencias. ExoPlayer usa esta información para administrar la sesión de DRM.
  • Contenido seguro: Cuando se renderiza en una plataforma protegida, el contenido de video se decodifica y se muestra en una ruta de acceso segura, lo que ayuda a cumplir con los requisitos de licencias de contenido. Esto también evita que el contenido aparezca en las capturas de pantalla.