Jetpack XR SDK поддерживает воспроизведение стереоскопического видео с разделением по вертикали на плоских поверхностях. В стереоскопическом видео каждый кадр состоит из двух изображений – для левого и правого глаза. Благодаря этому зритель ощущает глубину, или стереопсис.
В приложениях для Android XR можно воспроизводить обычные 2D-видео, используя стандартные медиа API, которые применяются при разработке приложений для Android на других типах устройств.
Как воспроизводить видео рядом друг с другом с помощью Jetpack SceneCore
В видео с разделением по горизонтали каждый стереоскопический кадр представлен в виде двух изображений, расположенных рядом друг с другом по горизонтали. Верхние и нижние кадры видео располагаются друг над другом.
Видео с разделением по горизонтали – это не кодек, а способ организации стереоскопических кадров, поэтому его можно закодировать с помощью любого кодека, поддерживаемого Android.
Вы можете загрузить видео с разделением экрана с помощью Media3 Exoplayer, а затем отрисовать его с помощью нового SurfaceEntity. Чтобы создать SurfaceEntity, вызовите SurfaceEntity.create, как показано в следующем примере.
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 с помощью Jetpack SceneCore
Стандарт кодека MV-HEVC оптимизирован и разработан для стереоскопического видео, поэтому ваше приложение сможет эффективно воспроизводить видео с эффектом погружения в высоком качестве. В файлах MV-HEVC есть основной поток (обычно для левого глаза) и стереопоток для другого глаза.
Как и в случае с видео, снятым бок о бок, его можно загрузить с помощью Media3 Exoplayer и воспроизвести с помощью SurfaceEntity. При вызове SurfaceEntity.create вам нужно будет указать, какой из файлов MV-HEVC является основным (левый или правый), с помощью параметра stereoMode.
// 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 с помощью Jetpack SceneCore
Jetpack XR SDK поддерживает воспроизведение зашифрованных видеопотоков с помощью встроенного в Android фреймворка для управления цифровыми правами (DRM). DRM защищает ваш контент, обеспечивая безопасное распространение и предотвращая несанкционированное копирование или воспроизведение.
Для этого медиапроигрыватель обращается к серверу лицензий, чтобы получить ключи дешифрования. На устройствах Android этот процесс надежно защищен. Расшифрованные кадры видео передаются в защищенный буфер графики, к которому не могут получить доступ ни система, ни другие приложения. Это предотвращает запись экрана.
Чтобы воспроизводить видео с защитой DRM с помощью Jetpack SceneCore, необходимо:
- Настройте
SurfaceEntity, чтобы запросить защищенную поверхность. - Настройте Media3 Exoplayer, указав необходимую информацию о DRM, чтобы обеспечить обмен ключами.
- Настройте вывод звука на поверхность
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)), 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()
Более подробную информацию о фреймворке Media DRM в Android можно найти в документации на сайте source.android.com.
Как воспроизводить панорамные видео с помощью Jetpack SceneCore
SurfaceEntity поддерживает воспроизведение 180-градусных видео на полусферических поверхностях и 360-градусных видео на сферических поверхностях. Параметр radius по умолчанию относится к радиальному размеру соответствующих поверхностей в метрах.
В приведенном ниже коде показано, как настроить параметр SurfaceEntity для воспроизведения на полусфере 180° и сфере 360°. При использовании этих фигур размещайте поверхность, учитывая положение головы пользователя, чтобы обеспечить эффект погружения.
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.
Расширенные настройки SurfaceEntity
Чтобы получить более точный контроль над обработкой видео и изображений, например применить специальные эффекты материалов, вы можете работать непосредственно с SurfaceEntity из библиотеки SceneCore.
В разделах ниже описаны некоторые расширенные функции, доступные на устройстве SurfaceEntity.
Как применить растушевку краев
Смягчите края поверхности, чтобы она лучше сочеталась с окружением, задав свойство edgeFeatheringParams.
// 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)
Как применить альфа-маску
Применяйте альфа-маску, чтобы создавать поверхности неправильной формы или добавлять эффекты прозрачности. Сначала загрузите 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"), ) // 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, прочитайте статью о том, как добавить поверхность для изображений или видеоконтента.