在應用程式中加入空間定位影片

Jetpack XR SDK 支援在平面上播放立體並排影片。立體影片的每個影格都包含左眼和右眼影像,讓觀眾產生深度感,也就是立體視覺

您可以使用標準媒體 API,在 Android XR 應用程式上算繪非立體 2D 影片,這些 API 也用於其他板型規格的 Android 開發作業。

使用 Jetpack SceneCore 並排播放影片

並排影片會將每個立體影格呈現為兩張水平排列的相鄰圖片。上下兩個影片畫面會垂直相鄰排列。

並排視訊並非轉碼器,而是整理立體影格的方式,因此可使用Android 支援的任何轉碼器進行編碼。

你可以使用 Media3 Exoplayer 並排載入影片,然後使用新的 SurfaceEntity 算繪影片。如要建立 SurfaceEntity,請呼叫 SurfaceEntity.create,如以下範例所示。

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 SceneCore 播放 MV-HEVC 影片

MV-HEVC 轉碼器標準經過最佳化,專為立體影片設計,可讓應用程式以優異畫質有效率地播放沉浸式影片。MV-HEVC 檔案包含主要串流 (通常是左眼) 和立體聲串流 (另一隻眼睛)。

與並排影片類似,您可以使用 Media3 Exoplayer 載入影片,並使用 SurfaceEntity 算繪影片。呼叫 SurfaceEntity.create 時,您會想在 stereoMode 參數中指定 MV-HEVC 檔案是左側還是右側主要檔案。

// Create the SurfaceEntity with the StereoMode corresponding to the MV-HEVC content
val stereoSurfaceEntity = SurfaceEntity.create(
    xrSession,
    SurfaceEntity.StereoMode.MULTIVIEW_LEFT_PRIMARY,
    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("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()

使用 Jetpack SceneCore 播放受 DRM 保護的空間影片

Jetpack XR SDK 支援使用 Android 內建的數位版權管理 (DRM) 架構,播放加密的影片串流。DRM 可確保內容安全發布,並防止未經授權的複製或播放行為,藉此保護內容。

媒體播放器應用程式會聯絡授權伺服器,取得解密金鑰。在 Android 裝置上,這項程序會受到安全管理,解密的影片影格會算繪至受保護的圖形緩衝區,系統或其他應用程式無法存取,因此可防止擷取螢幕畫面。

如要使用 Jetpack SceneCore 播放受 DRM 保護的影片,請按照下列步驟操作:

  1. 設定 SurfaceEntity,要求受保護的介面。
  2. 使用必要的 DRM 資訊設定 Media3 Exoplayer,以處理金鑰交換作業。
  3. 將播放器的輸出內容設為 SurfaceEntity 的表面。

以下範例說明如何設定 ExoPlayer,播放受 DRM 保護的串流,並在 SurfaceEntity 上算繪:

// 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)),
    canvasShape = SurfaceEntity.CanvasShape.Quad(1.0f, 1.0f),
    contentSecurityLevel = SurfaceEntity.ContentSecurityLevel.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()

如要進一步瞭解 Android 的媒體 DRM 架構,請參閱 source.android.com 上的媒體 DRM 說明文件

使用 Jetpack SceneCore 播放 180 度和 360 度影片

SurfaceEntity 支援在半球形介面上播放 180 度影片,以及在球形介面上播放 360 度影片。radius 參數預設是指相應表面的徑向大小 (以公尺為單位)。

下列程式碼說明如何設定 SurfaceEntity,以便在 180° 半球和 360° 球體上播放。使用這些畫布形狀時,請利用使用者的頭部姿勢定位表面,提供沉浸式體驗。

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

進階 SurfaceEntity 控制項

如要進一步控制影片和圖片的算繪作業,例如套用自訂材質效果,可以直接使用 SceneCore 程式庫。SurfaceEntity

以下各節說明 SurfaceEntity 提供的部分進階功能。

套用邊緣柔邊

設定 edgeFeather 屬性,柔化表面邊緣,讓表面與環境融為一體。

// 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.edgeFeather =
    SurfaceEntity.EdgeFeatheringParams.SmoothFeather(0.1f, 0.1f)

套用 Alpha 遮罩

套用 Alpha 遮罩,建立非矩形表面或新增透明效果。首先,從資產載入 Texture,然後指派給 primaryAlphaMaskTexture 屬性:

// 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"),
            TextureSampler.create()
        )

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

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

使用 Jetpack Compose for XR 播放空間影片

如果您有興趣瞭解如何使用 Jetpack Compose for XR 播放影片,請參閱這篇文章,瞭解如何新增圖片或影片內容的介面。