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עם רינדור של אפליקציות או פענוח של סרטונים. - הקוד הקומפוזבילי הזה לא יכול להופיע לפני חלוניות אחרות, לכן לא כדאי להשתמש ב-
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() } } } }
מידע חשוב על הקוד
- Protected Surface: Setting
surfaceProtection = SpatialExternalSurfaceProtection.ProtectedonSpatialExternalSurfaceis essential so that the underlyingSurfaceis backed by secure buffers suitable for DRM content. - הגדרת DRM: צריך להגדיר את
MediaItemעם סכימת ה-DRM (לדוגמה,C.WIDEVINE_UUID) ואת ה-URI של שרת הרישיונות. ExoPlayer משתמש במידע הזה כדי לנהל את סשן ה-DRM. - תוכן מאובטח: כשמעבדים קטע וידאו למשטח מוגן, התוכן מפוענח ומוצג בנתיב מאובטח, מה שעוזר לעמוד בדרישות רישיון לתוכן. כך גם התוכן לא יופיע בצילומי מסך.