Ihrer App ein räumliches Video hinzufügen

XR‑Geräte, für die der Leitfaden gilt
Dieser Leitfaden hilft Ihnen dabei, Erlebnisse für die folgenden Arten von XR-Geräten zu entwickeln.
XR‑Headsets
XR‑Brillen mit Kabel

Das Jetpack XR SDK unterstützt die Wiedergabe von stereoskopischen Side-by-Side Videos auf flachen Oberflächen. Bei stereoskopischen Videos besteht jeder Frame aus einem Bild für das linke und einem Bild für das rechte Auge, um den Zuschauern ein Gefühl von Tiefe zu vermitteln. Dieses Phänomen wird auch als Stereopsis bezeichnet.

Sie können nicht stereoskopische 2D‑Videos in Android XR‑Apps mit den Standard Media APIs rendern, die für die Android-Entwicklung auf anderen Formfaktoren verwendet werden.

Side-by-Side-Videos mit Jetpack SceneCore abspielen

Bei Side-by-Side-Videos wird jeder stereoskopische Frame als zwei Bilder dargestellt, die horizontal nebeneinander angeordnet sind. Die Video-Frames für oben und unten sind vertikal nebeneinander angeordnet.

Side-by-Side-Videos sind kein Codec, sondern eine Möglichkeit, stereoskopische Frames zu organisieren. Sie können also mit jedem der von Android unterstützten Codecs codiert werden.

Sie können Side-by-Side-Videos mit Media3 ExoPlayer laden und dann mit der neuen SurfaceEntity rendern. Rufen Sie SurfaceEntity.create auf, um eine SurfaceEntity zu erstellen, wie im folgenden Beispiel gezeigt.

val stereoSurfaceEntity = SurfaceEntity.create(
    session = xrSession,
    stereoMode = SurfaceEntity.StereoMode.SIDE_BY_SIDE,
    pose = Pose(Vector3(0.0f, 0.0f, -1.5f)),
    shape = SurfaceEntity.Shape.Quad(FloatSize2d(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()

MV-HEVC-Videos mit Jetpack SceneCore abspielen

Der MV-HEVC-Codec-Standard ist für stereoskopische Videos optimiert und konzipiert. So kann Ihre App immersive Videos effizient und in hoher Qualität wiedergeben. MV-HEVC-Dateien haben einen primären Stream, in der Regel für das linke Auge, und einen Stereostream für das andere Auge.

Ähnlich wie bei Side-by-Side-Videos können Sie sie mit Media3 ExoPlayer laden und mit der SurfaceEntity rendern. Sie müssen angeben, ob Ihre MV-HEVC-Datei im Parameter stereoMode links oder rechts primär ist, wenn Sie SurfaceEntity.create aufrufen.

// Create the SurfaceEntity with the StereoMode corresponding to the MV-HEVC content
val stereoSurfaceEntity = SurfaceEntity.create(
    session = xrSession,
    stereoMode = SurfaceEntity.StereoMode.MULTIVIEW_LEFT_PRIMARY,
    pose = Pose(Vector3(0.0f, 0.0f, -1.5f)),
    shape = SurfaceEntity.Shape.Quad(FloatSize2d(1.0f, 1.0f))
)
val videoUri = Uri.Builder()
    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
    .path("mvhevc_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()

DRM-geschützte räumliche Videos mit Jetpack SceneCore abspielen

Das Jetpack XR SDK unterstützt die Wiedergabe verschlüsselter Videostreams mit dem integrierten DRM-Framework (Digital Rights Management) von Android. DRM schützt Ihre Inhalte durch sichere Verteilung und verhindert unbefugtes Kopieren oder Abspielen.

Dabei kontaktiert Ihre Mediaplayer-Anwendung einen Lizenzserver, um Entschlüsselungsschlüssel zu erhalten. Unter Android wird dieser Vorgang sicher verwaltet und die entschlüsselten Video-Frames werden in einem geschützten Grafikpuffer gerendert, auf den das System oder andere Anwendungen nicht zugreifen können. So wird die Bildschirmaufnahme verhindert.

So spielen Sie DRM-geschützte Videos mit Jetpack SceneCore ab:

  1. Konfigurieren Sie SurfaceEntity, um eine geschützte Oberfläche anzufordern.
  2. Konfigurieren Sie Media3 ExoPlayer mit den erforderlichen DRM-Informationen, um den Schlüsselaustausch zu verarbeiten.
  3. Legen Sie die Ausgabe des Players auf die SurfaceEntity Oberfläche fest.

Das folgende Beispiel zeigt, wie Sie ExoPlayer so konfigurieren, dass ein DRM-geschützter Stream wiedergegeben und auf einer SurfaceEntity gerendert wird:

// Create a SurfaceEntity with DRM content

// 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"

// Create the SurfaceEntity with the PROTECTED content security level.
val protectedSurfaceEntity = SurfaceEntity.create(
    session = xrSession,
    stereoMode = SurfaceEntity.StereoMode.SIDE_BY_SIDE,
    pose = Pose(Vector3(0.0f, 0.0f, -1.5f)),
    shape = SurfaceEntity.Shape.Quad(FloatSize2d(1.0f, 1.0f)),
    surfaceProtection = SurfaceEntity.SurfaceProtection.PROTECTED
)

// 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()

// Initialize ExoPlayer and set the protected surface.
val exoPlayer = ExoPlayer.Builder(this).build()
exoPlayer.setVideoSurface(protectedSurfaceEntity.getSurface())

// Set the media item and start playback.
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.play()

Eine detailliertere Übersicht über das Media DRM-Framework von Android finden Sie in der Media DRM-Dokumentation auf source.android.com.

180°- und 360°-Videos mit Jetpack SceneCore abspielen

SurfaceEntity unterstützt die Wiedergabe von 180°-Videos auf halbkugelförmigen Oberflächen und von 360°-Videos auf kugelförmigen Oberflächen. Der Parameter radius bezieht sich standardmäßig auf die radiale Größe der jeweiligen Oberflächen in Metern.

Der folgende Code zeigt, wie Sie SurfaceEntity für die Wiedergabe auf einer 180°-Halbkugel und einer 360°-Kugel einrichten. Wenn Sie diese Canvas-Formen verwenden, positionieren Sie die Oberfläche anhand der Kopfhaltung des Nutzers, um ein immersives Erlebnis zu bieten.

val devicePose = ArDevice.getInstance(xrSession).state.value.devicePose
val activitySpacePose = xrSession.scene.perceptionSpace.transformPoseTo(devicePose, xrSession.scene.activitySpace)

// Set up the surface for playing a 180° video on a hemisphere.
val hemisphereStereoSurfaceEntity =
    SurfaceEntity.create(
        session = xrSession,
        stereoMode = SurfaceEntity.StereoMode.SIDE_BY_SIDE,
        pose = activitySpacePose,
        shape = SurfaceEntity.Shape.Hemisphere(1.0f),
    )
// ... and use the surface for playing the media.

val devicePose = ArDevice.getInstance(xrSession).state.value.devicePose
val activitySpacePose = xrSession.scene.perceptionSpace.transformPoseTo(devicePose, xrSession.scene.activitySpace)
// Set up the surface for playing a 360° video on a sphere.
val sphereStereoSurfaceEntity =
    SurfaceEntity.create(
        session = xrSession,
        stereoMode = SurfaceEntity.StereoMode.TOP_BOTTOM,
        pose = activitySpacePose,
        shape = SurfaceEntity.Shape.Sphere(1.0f),
    )
// ... and use the surface for playing the media.

Erweiterte Steuerung von SurfaceEntity

Für eine erweiterte Steuerung der Video- und Bildwiedergabe, z. B. zum Anwenden benutzerdefinierter Materialeffekte, können Sie direkt mit SurfaceEntity aus der SceneCore-Bibliothek arbeiten.

In den folgenden Abschnitten werden einige der erweiterten Funktionen beschrieben, die für SurfaceEntity verfügbar sind.

Kantenweichzeichnung anwenden

Sie können die Kanten der Oberfläche weicher machen, damit sie besser in die Umgebung passt. Dazu legen Sie die Eigenschaft edgeFeatheringParams fest.

// Create a SurfaceEntity.
val surfaceEntity = SurfaceEntity.create(
    session = xrSession,
    pose = Pose(Vector3(0.0f, 0.0f, -1.5f))
)

// Feather the edges of the surface.
surfaceEntity.edgeFeatheringParams =
    SurfaceEntity.EdgeFeatheringParams.RectangleFeather(0.1f, 0.1f)

Alphamasken anwenden

Sie können Alphamasken anwenden, um nicht rechteckige Oberflächen zu erstellen oder Transparenzeffekte hinzuzufügen. Laden Sie zuerst ein Texture aus einem Asset und weisen Sie es dann der primaryAlphaMaskTexture Eigenschaft zu:

// Create a SurfaceEntity.
val surfaceEntity = SurfaceEntity.create(
    session = xrSession,
    pose = Pose(Vector3(0.0f, 0.0f, -1.5f))
)

// Load the texture in a coroutine scope.
activity.lifecycleScope.launch {
    val alphaMaskTexture =
        Texture.create(
            xrSession,
            Paths.get("textures", "alpha_mask.png"),
        )

    // Apply the alpha mask.
    surfaceEntity.primaryAlphaMaskTexture = alphaMaskTexture

    // To remove the mask, set the property to null.
    surfaceEntity.primaryAlphaMaskTexture = null
}

Räumliche Videos mit Jetpack Compose for XR abspielen

Wenn Sie erfahren möchten, wie Sie Videos mit Jetpack Compose for XR abspielen, lesen Sie den Leitfaden Oberflächen für Bild- oder Videoinhalte hinzufügen.