הערה: הדף הזה מתייחס לחבילה Camera2. אלא אם האפליקציה שלך דורשת תכונות ספציפיות ברמה נמוכה מ-Camera2, מומלץ להשתמש ב-CameraX. CameraX ו-Camera2 תומכות ב-Android מגרסה 5.0 (רמת API 21) ואילך.
ממשקי ה-API של Camera2 תומכים בצילום וידאו בטווח דינמי גבוה (HDR), כך שאתם יכולים לצפות בתצוגה מקדימה של תוכן וידאו ב-HDR ולצלם אותו באמצעות המצלמה. בהשוואה לטווח דינמי רגיל (SDR), HDR מציע טווח צבעים רחב יותר ומגדיל את הטווח הדינמי של רכיב הבהירות (מ-100 cd/m2 הנוכחיים לאלפי cd/m2). התוצאה היא איכות וידאו שדומה יותר למציאות, עם צבעים עשירים יותר, נקודות אור בהירות יותר וצללים כהים יותר.
כך נראה שקיעה שמצולמת ב-HDR עם פרטים עשירים יותר.
דרישות מוקדמות לגבי מכשירים
לא כל מכשירי Android תומכים בצילום וידאו ב-HDR. לפני שמצלמים סרטון HDR באפליקציה, צריך לבדוק אם המכשיר עומד בדרישות המוקדמות הבאות:
- מטרגטת ל-Android 13 (רמת API 33).
- יש לו חיישן מצלמה עם יכולת של 10 ביט ומעלה. מידע נוסף על תמיכה ב-HDR זמין במאמר בדיקת התמיכה ב-HDR.
מכיוון שלא כל המכשירים עומדים בדרישות המוקדמות, אפשר להוסיף נתיב קוד נפרד כשמגדירים צילום וידאו באיכות HDR באפליקציה. כך האפליקציה יכולה לחזור ל-SDR במכשירים לא תואמים. כדאי גם להוסיף אפשרות בממשק המשתמש ל-SDR. המשתמש יכול לעבור בין SDR ל-HDR בהתאם לצרכים שלו בצילום הסרטון.
ארכיטקטורה של צילום ב-HDR
התרשים הבא מציג את הרכיבים העיקריים בארכיטקטורה של צילום HDR.
כשמצלמה מצלמת פריים ב-HDR, מסגרת Camera2 מקצה מאגר שבו מאוחסן הפלט המעובד של חיישן המצלמה.
הוא גם מצרף את המטא-נתונים המתאימים של HDR אם הם נדרשים בפרופיל ה-HDR.
לאחר מכן, מסגרת Camera2 מוסיפה את המאגר המאוכלס לתור של משטח הפלט שאליו מתייחס CaptureRequest, כמו תצוגה או מקודד וידאו, כפי שמוצג בתרשים.
בדיקת התמיכה ב-HDR
לפני שמצלמים סרטון HDR באפליקציה, צריך לבדוק אם המכשיר תומך בפרופיל ה-HDR הרצוי.
אפשר להשתמש בשיטה CameraManager getCameraCharacteristics() כדי לקבל מופע של CameraCharacteristics שאפשר לשלוח לו שאילתה לגבי יכולות ה-HDR של המכשיר.
כדי לבדוק אם מכשיר תומך ב-HLG10, פועלים לפי השלבים הבאים. HLG10 הוא תקן ה-HDR הבסיסי שיצרני מכשירים צריכים לתמוך בו במצלמות עם פלט של 10 ביט.
קודם כל, בודקים אם המכשיר תומך בפרופילים של 10 ביט (עומק הביט של HLG10):
Kotlin
private fun isTenBitProfileSupported(cameraId: String): Boolean { val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId) val availableCapabilities = cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) for (capability in availableCapabilities!!) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) { return true } } return false }
לאחר מכן, בודקים אם המכשיר תומך ב-HLG10 (או בפרופיל נתמך אחר):
Kotlin
@RequiresApi(api = 33) private fun isHLGSupported(cameraId: String): Boolean { if (isTenBitProfileSupported(cameraId)) { Val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId) val availableProfiles = cameraCharacteristics .get(CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES)!! .getSupportedProfiles() // Checks for the desired profile, in this case HLG10 return availableProfiles.contains(DynamicRangeProfiles.HLG10) } return false; }
אם המכשיר תומך ב-HDR, isHLGSupported() תמיד מחזירה true.
מידע נוסף מופיע בCameraCharacteristicsמאמרי העזרה.
הגדרת צילום ב-HDR
אחרי שמוודאים שהמכשיר תומך ב-HDR, מגדירים את האפליקציה כך שתצלם שידור וידאו בפורמט RAW HDR מהמצלמה.
משתמשים ב-setDynamicRangeProfile() כדי לספק ל-OutputConfiguration
פרופיל HDR שנתמך במכשיר, שמועבר לאחר מכן
ל-CameraCaptureSession
בזמן היצירה.
כאן אפשר לעיין ברשימת פרופילי ה-HDR הנתמכים.
בדוגמת הקוד הבאה, setupSessionDynamicRangeProfile() בודק קודם אם במכשיר פועלת מערכת Android 13.
לאחר מכן, הוא מגדיר את CameraCaptureSession עם פרופיל ה-HDR שנתמך במכשיר כOutputConfiguration:
Kotlin
/** * Creates a [CameraCaptureSession] with a dynamic range profile. */ private fun setupSessionWithDynamicRangeProfile( dynamicRange: Long, device: CameraDevice, targets: List, handler: Handler? = null, stateCallback: CameraCaptureSession.StateCallback ): Boolean { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) { val outputConfigs = mutableListOf () for (target in targets) { val outputConfig = OutputConfiguration(target) //sets the dynamic range profile, for example DynamicRangeProfiles.HLG10 outputConfig.setDynamicRangeProfile(dynamicRange) outputConfigs.add(outputConfig) } device.createCaptureSessionByOutputConfigurations( outputConfigs, stateCallback, handler ) return true } else { device.createCaptureSession(targets, stateCallback, handler) return false } }
כשאפליקציית המצלמה מאתחלת את המצלמה, היא שולחת CaptureRequest חוזר כדי להציג תצוגה מקדימה של ההקלטה:
Kotlin
session.setRepeatingRequest(previewRequest, null, cameraHandler)
כדי להתחיל את הקלטת הסרטון:
Kotlin
// Start recording repeating requests, which stops the ongoing preview // repeating requests without having to explicitly call // `session.stopRepeating` session.setRepeatingRequest(recordRequest, object : CameraCaptureSession.CaptureCallback() { override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) { if (currentlyRecording) { encoder.frameAvailable() } } }, cameraHandler)
קידוד של סטרימינג מהמצלמה באיכות HDR
כדי לקודד את הסטרימינג מהמצלמה ב-HDR ולכתוב את הקובץ לדיסק, משתמשים ב-MediaCodec.
קודם כל, מקבלים את OutputSurface,
שממופה למאגר שבו מאוחסנים נתוני וידאו גולמיים.
בשביל MediaCodec, משתמשים ב-createInputSurface().
כדי לאתחל את MediaCodec, אפליקציה צריכה ליצור MediaFormat עם פרופיל קודק, מרחב צבעים, טווח צבעים ופונקציית העברה מוגדרים:
Kotlin
val mimeType = when { dynamicRange == DynamicRangeProfiles.STANDARD -> MediaFormat.MIMETYPE_VIDEO_AVC dynamicRange < DynamicRangeProfiles.PUBLIC_MAX -> MediaFormat.MIMETYPE_VIDEO_HEVC else -> throw IllegalArgumentException("Unknown dynamic range format") } val codecProfile = when { dynamicRange == DynamicRangeProfiles.HLG10 -> MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10 dynamicRange == DynamicRangeProfiles.HDR10 -> MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10 dynamicRange == DynamicRangeProfiles.HDR10_PLUS -> MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus else -> -1 } // Failing to correctly set color transfer causes quality issues // for example, washout and color clipping val transferFunction = when (codecProfile) { MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10 -> MediaFormat.COLOR_TRANSFER_HLG MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10 -> MediaFormat.COLOR_TRANSFER_ST2084 MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus -> MediaFormat.COLOR_TRANSFER_ST2084 else -> MediaFormat.COLOR_TRANSFER_SDR_VIDEO } val format = MediaFormat.createVideoFormat(mimeType, width, height) // Set some properties. Failing to specify some of these can cause the MediaCodec // configure() call to throw an exception. format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate) format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate) format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL) if (codecProfile != -1) { format.setInteger(MediaFormat.KEY_PROFILE, codecProfile) format.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT2020) format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED) format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, transferFunction) format.setFeatureEnabled(MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing, true) } mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
פרטים נוספים על ההטמעה זמינים בEncoderWrapper.kt של אפליקציית הדוגמה Camera2Video.
פורמטים של HDR
החל מ-Android 13, מכשירי מצלמה עם יכולות פלט של 10 ביט חייבים לתמוך ב-HLG10 לצילום והפעלה של HDR. בנוסף, יצרני מכשירים יכולים להפעיל כל פורמט HDR לפי בחירתם באמצעות ארכיטקטורת צילום HDR.
בטבלה הבאה מפורטים פורמטי ה-HDR הזמינים והיכולות שלהם לצילום וידאו באיכות HDR.
| פורמט | פונקציית העברה (TF) | מטא-נתונים | קודק | עומק ביט |
|---|---|---|---|---|
| HLG10 | HLG | לא | HEVC | 10 ביט |
| HDR10 | PQ | סטטי | HEVC | 10 ביט |
| HDR10+ | PQ | דינמי | HEVC | 10 ביט |
| Dolby Vision 8.4 | HLG | דינמי | HEVC | 10 ביט |
משאבים
אפליקציה לדוגמה עם פונקציונליות של צילום וידאו באיכות HDR זמינה ב-GitHub בכתובת Camera2Video sample.