בדרך כלל מערכת צילום וידאו מקליטה וידאו ואודיו, דוחסת אותם, מאחזרת את שני הזרמים, ואז כותבת את הזרם שנוצר בדיסק.
ב- CameraX, הפתרון לצילום וידאו הוא
VideoCapture
תרחיש לדוגמה:
כפי שמוצג באיור 2, צילום הווידאו של CameraX כולל מספר רכיבים ארכיטקטוניים:
SurfaceProvider
למקור הסרטון.AudioSource
למקור האודיו.- שני מקודדים לקידוד ולדחיסה של וידאו/אודיו.
- מיקסר מדיה שמשלב בין שני השידורים.
- שומר קבצים לכתיבה של התוצאה.
VideoCapture API מפשט את מנוע הצילום המורכב ומספק באמצעות ממשק API פשוט ופשוט יותר.
סקירה כללית על VideoCapture API
VideoCapture
הוא תרחיש לדוגמה של CameraX שפועל היטב בפני עצמו או כאשר
בשילוב עם תרחישים לדוגמה אחרים. השילובים הנתמכים הספציפיים תלויים
יכולות של חומרת מצלמה, אבל Preview
ו-VideoCapture
הם
שילוב תקין של תרחישי שימוש בכל המכשירים.
VideoCapture API מורכב מהאובייקטים הבאים שמתקשרים עם אפליקציות:
VideoCapture
הוא ברמה העליונה של תרחיש לדוגמה.VideoCapture
מקושר אלLifecycleOwner
עםCameraSelector
ו- CameraX אחר תרחישים לדוגמה. למידע נוסף על המושגים והשימושים האלה, ראו ארכיטקטורת CameraX.Recorder
הוא של VideoOutput בשילוב עםVideoCapture
. האפליקציהRecorder
משמשת לצילום וידאו ואודיו. האפליקציה יוצרת הקלטות מ-Recorder
.PendingRecording
מגדיר הקלטה, ומספק אפשרויות כמו הפעלת אודיו והגדרות האזנה לאירועים. כדי ליצורPendingRecording
צריך להשתמש ב-Recorder
.PendingRecording
לא מקליטה שום דבר.- הקוד
Recording
מבצע את של ההקלטה בפועל. כדי ליצורRecording
צריך להשתמש ב-PendingRecording
.
איור 3 מציג את הקשרים בין האובייקטים הבאים:
מקרא:
- יצירת
Recorder
באמצעותQualitySelector
- מגדירים את
Recorder
באמצעות אחת מהאפשרויות הבאות:OutputOptions
. - הפעלת אודיו באמצעות
withAudioEnabled()
במקרה הצורך. - חיוג אל
start()
עםVideoRecordEvent
כדי להתחיל להקליט. - שימוש ב-
pause()
/resume()
/stop()
בRecording
כדי לשלוט בהקלטה. - שליחת תשובה לגבי
VideoRecordEvents
בתוך event listener.
הרשימה המפורטת של ממשקי ה-API נמצאת בקובץ current.txt שבתוך קוד המקור.
שימוש ב-VideoCapture API
כדי לשלב את התרחיש לדוגמה VideoCapture
של CameraX באפליקציה שלך,
לבצע את הפעולות הבאות:
- קישור
VideoCapture
. - הכנות והגדרת הקלטה.
- איך מתחילים את ההקלטה של סביבת זמן הריצה ושולטים בה.
בקטעים הבאים מפורט מה אפשר לעשות בכל שלב כדי לקבל צילום סרטון מקצה לקצה.
קישור צילום וידאו
כדי לקשר את התרחיש לדוגמה VideoCapure
:
- יוצרים אובייקט
Recorder
. - יצירת אובייקט
VideoCapture
. - קישור ל-
Lifecycle
.
CameraX VideoCapture API תואם לדפוס העיצוב של ה-builder. הגשת מועמדות
יש להשתמש ב-Recorder.Builder
כדי ליצור Recorder
. אפשר גם להגדיר
רזולוציית הסרטון של Recorder
דרך אובייקט QualitySelector
.
CameraX Recorder
תומך בתקנים הבאים המוגדרים מראש Qualities
לרזולוציות של סרטונים:
Quality.UHD
לצילום וידאו באיכות 4K ultra HD (2160p)Quality.FHD
לסרטון באיכות HD מלאה (1080p)Quality.HD
לגודל וידאו באיכות HD (720p)Quality.SD
לגודל וידאו באיכות SD (480p)
חשוב לשים לב ש- CameraX יכול לבחור גם רזולוציות אחרות לאחר קבלת הרשאה מהאפליקציה.
הגודל המדויק של כל סרטון שנבחר תלוי במצלמה ובמקודד
יכולות. מידע נוסף זמין במשאבי העזרה של
CamcorderProfile
אפליקציות יכולות להגדיר פתרון על ידי יצירת
QualitySelector
אפשר ליצור QualitySelector
באחת מהשיטות הבאות:
לספק כמה רזולוציות מועדפות באמצעות
fromOrderedList()
. לכלול אסטרטגיה חלופית לשימוש במקרה יש תמיכה ברזולוציות המועדפות.CameraX יכול לקבוע את התאמת הגיבוי הטובה ביותר על סמך המצלמה שנבחרה יכולות לעיין ב-
FallbackStrategy specification
שלQualitySelector
אפשר לקבל פרטים נוספים. לדוגמה, הקוד הבא מבקש את הערך הגבוה ביותר שנתמך להקלטה, ואם לא ניתן לתמוך באף אחת מרזולוציות הבקשה, מתן הרשאה ל- CameraX לבחור את המצלמה הקרובה ביותר לרזולוציית Quality.SD:val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
קודם כול צריך להריץ שאילתות על יכולות המצלמה ולבחור אחת מבין האפשרויות הנתמכות רזולוציות באמצעות
QualitySelector::from()
:val cameraInfo = cameraProvider.availableCameraInfos.filter { Camera2CameraInfo .from(it) .getCameraCharacteristic(CameraCharacteristics.LENS\_FACING) == CameraMetadata.LENS_FACING_BACK } val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo[0]) val filteredQualities = arrayListOf (Quality.UHD, Quality.FHD, Quality.HD, Quality.SD) .filter { supportedQualities.contains(it) } // Use a simple ListView with the id of simple_quality_list_view viewBinding.simpleQualityListView.apply { adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, filteredQualities.map { it.qualityToString() }) // Set up the user interaction to manually show or hide the system UI. setOnItemClickListener { _, _, position, _ -> // Inside View.OnClickListener, // convert Quality.* constant to QualitySelector val qualitySelector = QualitySelector.from(filteredQualities[position]) // Create a new Recorder/VideoCapture for the new quality // and bind to lifecycle val recorder = Recorder.Builder() .setQualitySelector(qualitySelector).build() // ... } } // A helper function to translate Quality to a string fun Quality.qualityToString() : String { return when (this) { Quality.UHD -> "UHD" Quality.FHD -> "FHD" Quality.HD -> "HD" Quality.SD -> "SD" else -> throw IllegalArgumentException() } }
שימו לב שהיכולת שהוחזרה
QualitySelector.getSupportedQualities()
פועל בתרחיש לדוגמה שלVideoCapture
או שילוב שלVideoCapture
ו-Preview
תרחישים לדוגמה. כשמבצעים קישור יחד עם תרחיש לדוגמה:ImageCapture
אוImageAnalysis
, CameraX הקישור עדיין עשוי להיכשל כאשר השילוב הנדרש אינו נתמך ב- את המצלמה המבוקשת.
ברגע שיש לך QualitySelector
, האפליקציה יכולה ליצור
VideoCapture
ומבצעים את הקישור. הקישור הזה
בדיוק כמו בתרחישים אחרים לדוגמה:
val recorder = Recorder.Builder()
.setExecutor(cameraExecutor).setQualitySelector(qualitySelector)
.build()
val videoCapture = VideoCapture.withOutput(recorder)
try {
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, CameraSelector.DEFAULT_BACK_CAMERA, preview, videoCapture)
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
שימו לב ש-bindToLifecycle()
מחזיר אובייקט Camera
. במדריך הזה אפשר למצוא מידע נוסף לגבי שליטה בפלט של המצלמה, כמו זום וחשיפה.
השדה Recorder
בוחר את הפורמט המתאים ביותר למערכת. במידה הרבה ביותר
קודק וידאו נפוץ הוא
H.264 AVC) עם
פורמט של מאגר תגים
MPEG-4.
הגדרה ויצירה של הקלטה
החל מ-Recorder
, האפליקציה יכולה ליצור אובייקטי הקלטה כדי
מבצעים את הקלטת הווידאו והאודיו. האפליקציות יוצרות הקלטות באמצעות
הבאים:
- מגדירים את
OutputOptions
באמצעותprepareRecording()
. - (אופציונלי) מפעילים הקלטת אודיו.
- יש להשתמש ב-
start()
כדי לרשוםVideoRecordEvent
Listener, והתחילו לצלם את הסרטון.
הפונקציה Recorder
מחזירה אובייקט Recording
כשקוראים לפונקציה start()
.
האפליקציה שלך יכולה להשתמש באובייקט Recording
הזה כדי לסיים
תיעוד או ביצוע פעולות אחרות, כמו השהיה או המשך.
Recorder
תומך באובייקט Recording
אחד בכל פעם. אפשר להתחיל
הקלטה חדשה אחרי שתתקשרו אל Recording.stop()
או
Recording.close()
באובייקט Recording
הקודם.
נבחן את השלבים האלה לעומק. ראשית, האפליקציה מגדירה
OutputOptions
של מכשיר הקלטה עם Recorder.prepareRecording()
.
Recorder
תומך בסוגים הבאים של OutputOptions
:
FileDescriptorOutputOptions
לצילום לתרחישFileDescriptor
.FileOutputOptions
לצילום לתוךFile
.MediaStoreOutputOptions
לצילום לתרחישMediaStore
.
כל הסוגים של OutputOptions
מאפשרים להגדיר גודל קובץ מקסימלי עם
setFileSizeLimit()
. אפשרויות אחרות הן ספציפיות לפלט הספציפי
סוג, למשל ParcelFileDescriptor
עבור FileDescriptorOutputOptions
.
prepareRecording()
מחזירה אובייקט PendingRecording
, שהוא
אובייקט הביניים שמשמש ליצירה של הפונקציה
אובייקט Recording
. PendingRecording
היא מחלקה זמנית שצריך
יהיה בלתי נראה ברוב המקרים, ורק לעתים רחוקות נשמר במטמון על ידי האפליקציה.
אפליקציות יכולות להוסיף הגדרות נוספות להקלטה, למשל:
- הפעלת האודיו באמצעות
withAudioEnabled()
. - רישום מאזינים כדי לקבל אירועים של הקלטת וידאו
עם
start(Executor, Consumer<VideoRecordEvent>)
. - מתן הרשאה להקלטה לפעול ברציפות בזמן צירוף VideoCapture
שחוזר למצלמה אחרת,
PendingRecording.asPersistentRecording()
כדי להתחיל להקליט, צריך להתקשר למספר PendingRecording.start()
. CameraX מסובב את
PendingRecording
בתוך Recording
, נכנס לתור של בקשת ההקלטה,
ומחזירה לאפליקציה את האובייקט Recording
החדש שנוצר.
אחרי שההקלטה מתחילה במכשיר המצלמה המתאים, CameraX שולחת
אירוע מסוג VideoRecordEvent.EVENT_TYPE_START
.
הדוגמה הבאה מראה איך להקליט וידאו ואודיו לתוך
קובץ MediaStore
:
// Create MediaStoreOutputOptions for our recorder
val name = "CameraX-recording-" +
SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis()) + ".mp4"
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name)
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(this.contentResolver,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(contentValues)
.build()
// 2. Configure Recorder and Start recording to the mediaStoreOutput.
val recording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(this), captureListener)
בזמן שהתצוגה המקדימה של המצלמה משוכפלת במצלמה הקדמית כברירת מחדל, סרטונים כברירת מחדל, שהוקלטו על ידי VideoCapture לא עוברים שיקוף. עם CameraX 1.3, לשקף הקלטות וידאו, כך שהתצוגה המקדימה של המצלמה הקדמית התאמה של סרטון מוקלט.
קיימות שלוש אפשרויות MirrorMode: MIRROR_mode_OFF, MIRROR_מצב_ON ו
MIRROR_מצב_ON_FRONT_ONLY. כדי ליישר עם
תצוגה מקדימה של המצלמה, Google ממליצה להשתמש ב-MIROR_מצב_ON_FRONT_ONLY.
ש
שיקוף מסך לא מופעל במצלמה האחורית, אבל הוא מופעל בחזית
מצלמה. למידע נוסף על MirrorMode, יש לעיין
MirrorMode constants
קטע הקוד הזה מראה איך להתקשר
VideoCapture.Builder.setMirrorMode()
באמצעות MIRROR_MODE_ON_FRONT_ONLY
. עבור
למידע נוסף, ראו setMirrorMode()
.
Kotlin
val recorder = Recorder.Builder().build() val videoCapture = VideoCapture.Builder(recorder) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build() useCases.add(videoCapture);
Java
Recorder.Builder builder = new Recorder.Builder(); if (mVideoQuality != QUALITY_AUTO) { builder.setQualitySelector( QualitySelector.from(mVideoQuality)); } VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(builder.build()) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build(); useCases.add(videoCapture);
שליטה בהקלטה פעילה
ניתן להשהות, להמשיך ולהפסיק Recording
שפועל כרגע על ידי
באמצעות השיטות הבאות:
pause
כדי להשהות את ההקלטה הפעילה הנוכחית.resume()
כדי להמשיך הקלטה פעילה שמושהית.stop()
כדי לסיים את ההקלטה ולרוקן את כל אובייקטי ההקלטה המשויכים.mute()
כדי להשתיק או לבטל את ההשתקה של ההקלטה הנוכחית.
לתשומת ליבך, אפשר לקרוא ל-stop()
כדי לסיים Recording
ללא קשר
אם ההקלטה במצב מושהה או במצב הקלטה פעיל.
אם רשמת EventListener
ב:
PendingRecording.start()
, Recording
מתקשר
באמצעות שימוש
VideoRecordEvent
VideoRecordEvent.EVENT_TYPE_STATUS
משמש לתיעוד נתונים סטטיסטיים כמו בגודל הקובץ הנוכחי ובטווח הזמן המתועד.- הפונקציה
VideoRecordEvent.EVENT_TYPE_FINALIZE
משמשת לתוצאת ההקלטה והוא כולל מידע כמו ה-URI של הקובץ הסופי, שגיאות קשורות.
לאחר שהאפליקציה מקבלת EVENT_TYPE_FINALIZE
שמצביע על כך
סשן הקלטה, לאחר מכן תוכלו לגשת לסרטון שצולם מהמיקום
צוין ב-OutputOptions
.
מקורות מידע נוספים
למידע נוסף על CameraX, ניתן לעיין במשאבים הנוספים הבאים:
- תחילת העבודה עם CameraX Codelab
- אפליקציה רשמית לדוגמה של CameraX
- רשימת ממשקי ה-API האחרונים של צילום וידאו של CameraX
- נתוני הגרסה של CameraX
- קוד המקור של CameraX