Добавьте пространственное видео в свое приложение

Jetpack XR SDK поддерживает воспроизведение стереоскопического видео в режиме «бок о бок» на плоских поверхностях. В стереоскопическом видео каждый кадр состоит из изображений для левого и правого глаза, что создаёт у зрителей ощущение глубины, также известное как стереопсис .

Вы можете визуализировать нестереоскопическое 2D-видео в приложениях Android XR с помощью стандартных 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()

Воспроизведение видео MV-HEVC с помощью Jetpack SceneCore

Стандарт кодека MV-HEVC оптимизирован и разработан для стереоскопического видео, позволяя вашему приложению эффективно воспроизводить захватывающие видео в отличном качестве. Файлы MV-HEVC имеют основной поток, обычно для левого глаза, и стереопоток для другого глаза.

Аналогично параллельному видео, вы можете загрузить его с помощью Media3 Exoplayer и отрендерить с помощью SurfaceEntity . Вам нужно будет указать, является ли ваш файл MV-HEVC основным левым или правым, в параметре stereoMode при вызове SurfaceEntity.create .

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

Воспроизведение пространственного видео, защищенного DRM, с помощью Jetpack SceneCore

Jetpack XR SDK поддерживает воспроизведение зашифрованных видеопотоков с использованием встроенной в Android платформы управления цифровыми правами (DRM) . DRM защищает ваш контент, обеспечивая безопасное распространение и предотвращая несанкционированное копирование или воспроизведение.

Этот процесс включает обращение вашего медиаплеера к серверу лицензий для получения ключей дешифрования. В Android этот процесс осуществляется безопасно, а расшифрованные видеокадры визуализируются в защищённом графическом буфере, к которому система или другие приложения не имеют доступа, что предотвращает захват экрана.

Чтобы воспроизвести видео, защищенное DRM, с помощью Jetpack SceneCore, вам необходимо:

  1. Настройте SurfaceEntity для запроса защищенной поверхности.
  2. Настройте Media3 Exoplayer , используя необходимую информацию DRM для обработки обмена ключами.
  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 Media DRM можно найти в документации Media DRM на source.android.com .

Воспроизведение 180-градусного и 360-градусного видео с помощью Jetpack SceneCore

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

Для более расширенного управления рендерингом видео и изображений, например, для применения пользовательских эффектов материалов, вы можете работать напрямую с SurfaceEntity из библиотеки SceneCore.

В следующих разделах описываются некоторые расширенные функции, доступные в 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)

Применить альфа-маску

Примените альфа-маску для создания непрямоугольных поверхностей или добавления эффектов прозрачности. Сначала загрузите 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 для XR

Если вам интересно узнать, как воспроизводить видео с помощью Jetpack Compose для XR, узнайте, как добавить поверхность для изображений или видеоконтента .