SpatialExternalSurface là một thành phần kết hợp không gian con tạo và quản lý Surface mà ứng dụng của bạn có thể vẽ nội dung, chẳng hạn như hình ảnh hoặc video. SpatialExternalSurface hỗ trợ nội dung hình nổi hoặc hình phẳng.
Thêm một nền tảng cho nội dung hình ảnh hoặc nội dung video
Ví dụ này minh hoạ cách tải video hình nổi cạnh nhau bằng Media3 Exoplayer và 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() } } } }
Các điểm chính về mã
- Đặt
StereoModethànhMono,SideBySidehoặcTopBottomtuỳ thuộc vào loại nội dung bạn đang hiển thị:Mono: Khung hình ảnh hoặc video bao gồm một hình ảnh duy nhất, giống hệt nhau được hiển thị cho cả hai mắt.SideBySide: Hình ảnh hoặc khung video chứa một cặp hình ảnh hoặc khung video được sắp xếp cạnh nhau, trong đó hình ảnh hoặc khung hình bên trái đại diện cho chế độ xem bằng mắt trái và hình ảnh hoặc khung hình bên phải đại diện cho chế độ xem bằng mắt phải.TopBottom: Hình ảnh hoặc khung video chứa một cặp hình ảnh hoặc khung video xếp chồng lên nhau theo chiều dọc, trong đó hình ảnh hoặc khung hình ở trên cùng thể hiện góc nhìn của mắt trái và hình ảnh hoặc khung hình ở dưới cùng thể hiện góc nhìn của mắt phải.
SpatialExternalSurfacechỉ hỗ trợ các nền tảng hình chữ nhật.Surfacenày không ghi lại sự kiện nhập.- Không thể đồng bộ hoá các thay đổi về
StereoModevới quá trình kết xuất ứng dụng hoặc giải mã video. - Thành phần kết hợp này không thể hiển thị trước các bảng điều khiển khác, vì vậy, bạn không nên sử dụng
MovePolicynếu có các bảng điều khiển khác trong bố cục.
Thêm một nền tảng cho nội dung video được bảo vệ bằng DRM
SpatialExternalSurface cũng hỗ trợ phát các luồng video được bảo vệ bằng DRM. Để bật tính năng này, bạn phải tạo một nền tảng bảo mật hiển thị cho
bộ đệm đồ hoạ được bảo vệ. Việc này giúp ngăn nội dung bị ghi màn hình hoặc bị các thành phần hệ thống không an toàn truy cập.
Để tạo một nền tảng bảo mật, hãy đặt tham số SpatialExternalSurfaceProtection thành SpatialExternalSurfaceProtection.Protected trên thành phần kết hợp SpatialExternalSurface. Ngoài ra, bạn phải định cấu hình Media3 Exoplayer bằng thông tin DRM thích hợp để xử lý việc thu nạp giấy phép từ máy chủ cấp phép.
Ví dụ sau đây minh hoạ cách định cấu hình SpatialExternalSurface và ExoPlayer để phát một luồng video được bảo vệ bằng 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() } } } }
Các điểm chính về mã
- Protected Surface: Việc đặt
surfaceProtection = SpatialExternalSurfaceProtection.ProtectedtrênSpatialExternalSurfacelà cần thiết đểSurfacecơ bản được hỗ trợ bởi các vùng đệm bảo mật phù hợp với nội dung DRM. - Cấu hình DRM: Bạn phải định cấu hình
MediaItembằng lược đồ DRM (ví dụ:C.WIDEVINE_UUID) và URI của máy chủ cấp phép. ExoPlayer sử dụng thông tin này để quản lý phiên DRM. - Nội dung bảo mật: Khi kết xuất trên một nền tảng được bảo vệ, nội dung video sẽ được giải mã và hiển thị trên một đường dẫn bảo mật, giúp đáp ứng các yêu cầu về giấy phép nội dung. Việc này cũng ngăn nội dung xuất hiện trong ảnh chụp màn hình.