SpatialExternalSurface – это composable-функция подпространства, которая создает Surface и управляет им. В этом элементе приложение может отрисовывать контент, например изображение или видео. SpatialExternalSurface поддерживает как стереоскопический, так и моноскопический контент.
Добавьте поверхность для изображений или видеоконтента
В примере ниже показано, как загрузить стереоскопическое видео в формате горизонтальной стереопары с помощью Media3 Exoplayer и SpatialExternalSurface.
@OptIn(ExperimentalComposeApi::class) @Composable fun SpatialExternalSurfaceContent() { val context = LocalContext.current Subspace { SpatialExternalSurface( modifier = SubspaceModifier .width(1200.dp) // Default width is 400.dp if no width modifier is specified .height(676.dp), // Default height is 400.dp if no height modifier is specified // Use StereoMode.Mono, StereoMode.SideBySide, or StereoMode.TopBottom, depending // upon which type of content you are rendering: monoscopic content, side-by-side stereo // content, or top-bottom stereo content stereoMode = StereoMode.SideBySide, ) { val exoPlayer = remember { ExoPlayer.Builder(context).build() } val videoUri = Uri.Builder() .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) // Represents a side-by-side stereo video, where each frame contains a pair of // video frames arranged side-by-side. The frame on the left represents the left // eye view, and the frame on the right represents the right eye view. .path("sbs_video.mp4") .build() val mediaItem = MediaItem.fromUri(videoUri) // onSurfaceCreated is invoked only one time, when the Surface is created onSurfaceCreated { surface -> exoPlayer.setVideoSurface(surface) exoPlayer.setMediaItem(mediaItem) exoPlayer.prepare() exoPlayer.play() } // onSurfaceDestroyed is invoked when the SpatialExternalSurface composable and its // associated Surface are destroyed onSurfaceDestroyed { exoPlayer.release() } } } }
Важные сведения о коде
- Задайте для параметра
StereoModeзначениеMono,SideBySideилиTopBottomв зависимости от типа контента, который вы показываете:Mono– изображение или кадр видео состоит из одного и того же изображения, которое показывается обоим глазам.SideBySide: изображение или кадр видео содержит пару изображений или кадров видео, расположенных рядом, где изображение или кадр слева представляет вид для левого глаза, а изображение или кадр справа – вид для правого глаза.TopBottom– изображение или кадр видео содержит пару изображений или кадров видео, расположенных вертикально, где изображение или кадр сверху представляет вид для левого глаза, а изображение или кадр снизу – вид для правого глаза.
SpatialExternalSurfaceподдерживает только прямоугольные поверхности.- Этот
Surfaceне регистрирует события ввода. - Изменения
StereoModeнельзя синхронизировать с отрисовкой приложения или декодированием видео. - Эта composable-функция не может отображаться перед другими панелями, поэтому не используйте
MovePolicy, если в макете есть другие панели.
Как добавить поверхность для видеоконтента, защищенного DRM
SpatialExternalSurface также поддерживает воспроизведение видеопотоков, защищенных технологиями DRM. Для этого необходимо создать защищенную поверхность, которая будет отрисовываться в защищенных графических буферах. Это позволяет предотвратить запись экрана и доступ к контенту со стороны небезопасных компонентов системы.
Чтобы создать защищенную поверхность, задайте для параметра SpatialExternalSurfaceProtection значение SpatialExternalSurfaceProtection.Protected в composable-функции SpatialExternalSurface. Кроме того, вам нужно настроить Media3 Exoplayer, указав информацию о DRM, чтобы получать лицензии от сервера лицензирования.
В следующем примере показано, как настроить SpatialExternalSurface и ExoPlayer для воспроизведения видеопотока, защищенного технологиями DRM:
@OptIn(ExperimentalComposeApi::class) @Composable fun DrmSpatialVideoPlayer() { val context = LocalContext.current Subspace { SpatialExternalSurface( modifier = SubspaceModifier .width(1200.dp) .height(676.dp), stereoMode = StereoMode.SideBySide, surfaceProtection = SpatialExternalSurfaceProtection.Protected ) { val exoPlayer = remember { ExoPlayer.Builder(context).build() } // 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" // 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() onSurfaceCreated { surface -> // The created surface is secure and can be used by the player. exoPlayer.setVideoSurface(surface) exoPlayer.setMediaItem(mediaItem) exoPlayer.prepare() exoPlayer.play() } onSurfaceDestroyed { exoPlayer.release() } } } }
Важные сведения о коде
- Защищенная поверхность. Настройка
surfaceProtection = SpatialExternalSurfaceProtection.ProtectedвSpatialExternalSurfaceнеобходима, чтобы базоваяSurfaceподдерживалась защищенными буферами, подходящими для контента с DRM. - Настройки DRM. Вам необходимо настроить
MediaItemс помощью схемы DRM (например,C.WIDEVINE_UUID) и URI сервера лицензирования. ExoPlayer использует эту информацию для управления сеансом DRM. - Защищенный контент. При отрисовке на защищенной поверхности видеоконтент декодируется и показывается по защищенному пути, что помогает соблюдать требования лицензирования контента. Это также предотвращает появление контента на снимках экрана.