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

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

Вы можете визуализировать нестереоскопическое 2D-видео в приложениях Android XR с помощью стандартных API-интерфейсов мультимедиа, используемых для разработки Android на устройствах других форм-факторов.

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

При параллельном видео каждый стереокадр представлен двумя изображениями, расположенными рядом друг с другом по горизонтали. Верхний и нижний видеокадры расположены рядом друг с другом по вертикали.

Видео «бок о бок» — это не кодек, а скорее способ организации стереокадров, то есть его можно кодировать в любом из кодеков, поддерживаемых Android .

Вы можете загрузить параллельное видео с помощью Media3 Exoplayer , а затем отрендерить его с помощью нового SurfaceEntity . Чтобы создать SurfaceEntity , вызовите SurfaceEntity.create , как показано в следующем примере.

val stereoSurfaceEntity = SurfaceEntity.create(     session = xrSession,     stereoMode = SurfaceEntity.StereoMode.STEREO_MODE_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 . Вам нужно будет указать, является ли ваш файл MV-HEVC основным левым или правым, в параметре stereoMode при вызове SurfaceEntity.create .

// Create the SurfaceEntity with the StereoMode corresponding to the MV-HEVC content val stereoSurfaceEntity = SurfaceEntity.create(     session = xrSession,     stereoMode = SurfaceEntity.StereoMode.STEREO_MODE_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, вам необходимо:

  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.STEREO_MODE_SIDE_BY_SIDE,     pose = Pose(Vector3(0.0f, 0.0f, -1.5f)),     shape = SurfaceEntity.Shape.Quad(FloatSize2d(1.0f, 1.0f)),     surfaceProtection = SurfaceEntity.SurfaceProtection.SURFACE_PROTECTION_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(         session = xrSession,         stereoMode = SurfaceEntity.StereoMode.STEREO_MODE_SIDE_BY_SIDE,         pose = xrSession.scene.spatialUser.head?.transformPoseTo(             Pose.Identity,             xrSession.scene.activitySpace         )!!,         shape = SurfaceEntity.Shape.Hemisphere(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(         session = xrSession,         stereoMode = SurfaceEntity.StereoMode.STEREO_MODE_TOP_BOTTOM,         pose = xrSession.scene.spatialUser.head?.transformPoseTo(             Pose.Identity,             xrSession.scene.activitySpace         )!!,         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, узнайте, как добавить поверхность для изображений или видеоконтента .