ארכיטקטורת CameraX

בדף הזה נסביר על הארכיטקטורה של CameraX, כולל המבנה שלה, איך לעבוד עם ה-API, איך לעבוד עם מחזורי חיים ואיך לשלב תרחישים לדוגמה.

מבנה CameraX

תוכלו להשתמש ב- CameraX כדי להתממשק עם מצלמת המכשיר באמצעות מהפשטה שנקראת 'תרחיש לדוגמה'. אלה התרחישים לדוגמה שאפשר להשתמש בהם:

  • Preview: מאפשרת להשתמש בפלטפורמה להצגת תצוגה מקדימה, כמו PreviewView.
  • ניתוח תמונות: מספק מאגרים שנגישים למעבד (CPU), למשל לצורך ניתוח למידת מכונה.
  • צילום תמונה: צילום ושמירה של תמונה.
  • צילום וידאו: צילום וידאו ואודיו באמצעות VideoCapture

אפשר לשלב תרחישים לדוגמה ולהפעיל אותם בו-זמנית. לדוגמה, אפליקציה יכולה לאפשר למשתמש לצפות בתמונה שהמצלמה קולטת בתרחיש לדוגמה של תצוגה מקדימה, של ניתוח תמונות שקובע אם האנשים שמופיעים בתמונה מחייך, ולכלול תרחיש לדוגמה של צילום תמונה כדי לצלם תמונה.

מודל API

כדי לעבוד עם הספרייה, עליך לציין את הדברים הבאים:

  • התרחיש לדוגמה הרצוי עם אפשרויות הגדרה.
  • מה לעשות עם נתוני פלט על ידי צירוף מאזינים.
  • התהליך המיועד, למשל מתי להפעיל את המצלמות ומתי להפיק נתונים, קישור של התרחיש לדוגמה לארכיטקטורת Android מחזורי חיים.

יש שתי דרכים לכתוב באפליקציית CameraX: CameraController (נהדר אם הדרך הפשוטה ביותר להשתמש ב- CameraX) CameraProvider (מעולה אם יותר גמישות).

שלט רחוק למצלמה

CameraController מספק את רוב פונקציונליות הליבה של CameraX בכיתה. נדרש קוד הגדרה קצר, והוא מטפל במצלמה באופן אוטומטי אתחול, ניהול תרחישי שימוש, רוטציית יעדים, הקשה למיקוד, צביטה = שינוי מרחק התצוגה ועוד. מחלקת הבטון שמשתרעת על ידי CameraController היא LifecycleCameraController.

Kotlin

val previewView: PreviewView = viewBinding.previewView
var cameraController = LifecycleCameraController(baseContext)
cameraController.bindToLifecycle(this)
cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
previewView.controller = cameraController

Java

PreviewView previewView = viewBinding.previewView;
LifecycleCameraController cameraController = new LifecycleCameraController(baseContext);
cameraController.bindToLifecycle(this);
cameraController.setCameraSelector(CameraSelector.DEFAULT_BACK_CAMERA);
previewView.setController(cameraController);

ערכי ברירת המחדל של UseCase עבור CameraController הם Preview, ImageCapture ו ImageAnalysis כדי להשבית את ImageCapture או ImageAnalysis, או כדי להפעיל VideoCapture מופעל, צריך להשתמש ב setEnabledUseCases() .

לשימושים נוספים ב-CameraController אפשר לעיין ב דוגמה לסורק של קודי QR או סרטון בסיסי של CameraController.

CameraProvider

עדיין קל להשתמש ב-CameraProvider, אבל מפַתח האפליקציה מטפל יותר הגדרות, יש יותר הזדמנויות להתאים אישית את ההגדרות, כמו הפעלת סיבוב תמונה של פלט או הגדרת פורמט פלט תמונה ImageAnalysis. אפשר גם להשתמש ב-Surface בהתאמה אישית כדי לאפשר תצוגה מקדימה של המצלמה לספק גמישות רבה יותר. לעומת זאת, כשמשתמשים ב- CameraController, PreviewView. שימוש בקוד Surface הקיים יכול להיות שימושי שכבר מוגדר כקלט בחלקים אחרים של האפליקציה.

מגדירים תרחישים לדוגמה באמצעות methods של set() ומסיימים אותם באמצעות build() . כל אובייקט של תרחיש לדוגמה מספק קבוצה של ממשקי API ספציפיים לתרחיש לדוגמה. עבור למשל, התרחיש לדוגמה של צילום תמונה מספק הפעלת method takePicture().

במקום להשתמש באפליקציה שמבצעת הפעלות של שיטות ספציפיות להתחלה ולסיום onResume() ו-onPause(), האפליקציה מציינת מחזור חיים לשיוך המצלמה עם, באמצעות cameraProvider.bindToLifecycle(). לאחר מכן מחזור החיים הזה מודיע ל- CameraX מתי להגדיר את פעילות הצילום של המצלמה ומבטיח שמצב המצלמה משתנה בהתאם למעברים במחזור החיים.

לשלבים להטמעה לכל תרחיש לדוגמה, ראו יישום של תצוגה מקדימה, ניתוח תמונות, תמונה צילום מסך וצילום וידאו

התרחיש לדוגמה של התצוגה המקדימה מקיים אינטראקציה עם Surface לרשת המדיה. הגשת מועמדות יוצרים את התרחיש לדוגמה עם אפשרויות ההגדרה באמצעות הקוד הבא:

Kotlin

val preview = Preview.Builder().build()
val viewFinder: PreviewView = findViewById(R.id.previewView)

// The use case is bound to an Android Lifecycle with the following code
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// PreviewView creates a surface provider and is the recommended provider
preview.setSurfaceProvider(viewFinder.getSurfaceProvider())

Java

Preview preview = new Preview.Builder().build();
PreviewView viewFinder = findViewById(R.id.view_finder);

// The use case is bound to an Android Lifecycle with the following code
Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview);

// PreviewView creates a surface provider, using a Surface from a different
// kind of view will require you to implement your own surface provider.
preview.previewSurfaceProvider = viewFinder.getSurfaceProvider();

לקוד לדוגמה נוסף, אפשר לעיין בדוגמה הרשמית של CameraX app.

מחזורי חיים של CameraX

CameraX מזהה מחזור חיים כדי לקבוע מתי לפתוח את המצלמה, מתי יוצר סשן צילום ומתי להפסיק ולכבות. ממשקי API לתרחישים לדוגמה מספקים קריאות לפעולה וקריאות חוזרות (callback) כדי לעקוב אחר ההתקדמות.

כמו שמוסבר בקטע שילוב תרחישים לדוגמה, אפשר לקשר כמה תמהילים במחזור חיים אחד. מתי האפליקציה צריכה לתמוך בתרחישים לדוגמה את שילובי האפשרויות הבאות, אפשר לבצע אחת מהפעולות הבאות:

  • קיבוץ של תרחישים תואמים לדוגמה בכמה תרחישים לדוגמה מקטע ולאחר מכן לעבור בין מקטעים
  • יצירת רכיב במחזור חיים מותאם אישית ושימוש בו כדי לשלוט במצלמה באופן ידני מחזור חיים

אם מפרידים בין התרחישים לדוגמה של התצוגה והמצלמה הבעלים של מחזור החיים (לדוגמה: אם משתמשים במחזור חיים מותאם אישית או בשמירה מקטע), לאחר מכן חייב לוודא שכל התרחישים לדוגמה לא מוצמדים ל- CameraX באמצעות ProcessCameraProvider.unbindAll() או על ידי ביטול הקישור של כל תרחיש לדוגמה בנפרד. לחלופין, אחרי שתקשרו את השימוש למחזור חיים, ניתן לאפשר ל- CameraX ניהול פתיחה וסגירה של סשן הצילום וביטול הקישור בין תרחישים לדוגמה.

אם כל הפונקציונליות של המצלמה תואמת למחזור החיים של שמודע למחזור חיים, כמו AppCompatActivity או מקטע AppCompat, ולאחר מכן שימוש במחזור החיים של הרכיב הזה במהלך הקישור את כל התרחישים לדוגמה הרצויים יבטיחו שהפונקציונליות של המצלמה תהיה מוכנה כשהרכיב המודע למחזור החיים פעיל ומושליך באופן בטוח, וצריכת משאבים כלשהי, אחרת.

בעלים של מחזור חיים בהתאמה אישית

במקרים מתקדמים, אפשר ליצור LifecycleOwner כדי להפעיל את כדי לשלוט במפורש במחזור החיים של הפעלת CameraX במקום לקשר אותו משתמש רגיל של Android LifecycleOwner.

דוגמת הקוד הבאה מראה איך ליצור בעלים פשוט של מחזור חיים בהתאמה אישית:

Kotlin

class CustomLifecycle : LifecycleOwner {
    private val lifecycleRegistry: LifecycleRegistry

    init {
        lifecycleRegistry = LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }
    ...
    fun doOnResume() {
        lifecycleRegistry.markState(State.RESUMED)
    }
    ...
    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}

Java

public class CustomLifecycle implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;
    public CustomLifecycle() {
        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }
   ...
   public void doOnResume() {
        lifecycleRegistry.markState(State.RESUMED);
    }
   ...
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }
}

באמצעות LifecycleOwner הזה, האפליקציה יכולה לבצע מעברי מצבים לפי הצורך בקוד שלו. כדי לקבל מידע נוסף על הטמעת הפונקציונליות הזו באפליקציה, מידע נוסף זמין בקטע יישום של בעלים של מחזור חיים.

תרחישים לדוגמה בו-זמנית

תרחישים לדוגמה יכולים לפעול בו-זמנית. אומנם אפשר לקשר ברצף את התרחישים לדוגמה במחזור החיים, עדיף לקשר את כל התרחישים לדוגמה באמצעות קריאה אחת CameraProcessProvider.bindToLifecycle() לקבלת מידע נוסף על לשינויי הגדרות אישיות, אפשר לעיין במאמר הגדרת כינוי .

בדוגמת הקוד הבאה, האפליקציה מציינת את שני התרחישים לדוגמה שיש ליצור והם פועלים בו-זמנית. הוא גם מציין את מחזור החיים שבו צריך להשתמש כך ששניהם מתחילות ומפסיקים לפעול בהתאם למחזור החיים.

Kotlin

private lateinit var imageCapture: ImageCapture

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

    cameraProviderFuture.addListener(Runnable {
        // Camera provider is now guaranteed to be available
        val cameraProvider = cameraProviderFuture.get()

        // Set up the preview use case to display camera preview.
        val preview = Preview.Builder().build()

        // Set up the capture use case to allow users to take photos.
        imageCapture = ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .build()

        // Choose the camera by requiring a lens facing
        val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                .build()

        // Attach use cases to the camera with the same lifecycle owner
        val camera = cameraProvider.bindToLifecycle(
                this as LifecycleOwner, cameraSelector, preview, imageCapture)

        // Connect the preview use case to the previewView
        preview.setSurfaceProvider(
                previewView.getSurfaceProvider())
    }, ContextCompat.getMainExecutor(this))
}

Java

private ImageCapture imageCapture;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    PreviewView previewView = findViewById(R.id.previewView);

    ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
            ProcessCameraProvider.getInstance(this);

    cameraProviderFuture.addListener(() -> {
        try {
            // Camera provider is now guaranteed to be available
            ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

            // Set up the view finder use case to display camera preview
            Preview preview = new Preview.Builder().build();

            // Set up the capture use case to allow users to take photos
            imageCapture = new ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                    .build();

            // Choose the camera by requiring a lens facing
            CameraSelector cameraSelector = new CameraSelector.Builder()
                    .requireLensFacing(lensFacing)
                    .build();

            // Attach use cases to the camera with the same lifecycle owner
            Camera camera = cameraProvider.bindToLifecycle(
                    ((LifecycleOwner) this),
                    cameraSelector,
                    preview,
                    imageCapture);

            // Connect the preview use case to the previewView
            preview.setSurfaceProvider(
                    previewView.getSurfaceProvider());
        } catch (InterruptedException | ExecutionException e) {
            // Currently no exceptions thrown. cameraProviderFuture.get()
            // shouldn't block since the listener is being called, so no need to
            // handle InterruptedException.
        }
    }, ContextCompat.getMainExecutor(this));
}

שילובי ההגדרות הבאים מובטחים שנתמכים (כאשר נדרשת 'תצוגה מקדימה' או 'צילום וידאו', אבל לא את שניהם בו-זמנית):

תצוגה מקדימה או צילום וידאו צילום תמונה ניתוח תיאורים
לספק למשתמש תצוגה מקדימה או צילום סרטון, לצלם תמונה ולנתח הסטרימינג של התמונה.
  מצלמים תמונה ומנתחים את זרם התמונות.
  צריך לספק למשתמשים תצוגה מקדימה או צילום סרטון ולצלם תמונה.
  לספק למשתמש תצוגה מקדימה או להקליט סרטון, ולנתח את התמונה .

במקרים שבהם צריך גם תצוגה מקדימה וגם צילום וידאו, התרחיש לדוגמה הבא יש תמיכה בשילובים באופן מותנה:

תצוגה מקדימה צילום וידאו צילום תמונה ניתוח דרישה מיוחדת
    מובטח לכל המצלמות
  מכשיר מצלמה מוגבל (או טוב יותר).
  מכשיר מצלמה LEVEL_3 (או גבוה יותר).

בנוסף,

  • כל תרחיש לדוגמה יכול לפעול בפני עצמו. לדוגמה, אפליקציה יכולה להקליט סרטונים בלי להשתמש בתצוגה מקדימה.
  • כשהתוספים מופעלים, רק ImageCapture וPreview להבטיח שהשילוב יעבוד. בהתאם להטמעת ה-OEM, ייתכן שלא תהיה אפשרות להוסיף גם ImageAnalysis; תוספים לא יכולים בתרחיש לדוגמה VideoCapture. כדאי לבדוק את מסמך עזר בנושא תוסף לקבלת פרטים.
  • בהתאם ליכולת המצלמה, חלק מהמצלמות תומכות בשילוב הזה מצבי רזולוציה נמוכה יותר, אבל לא יכולים לתמוך באותו שילוב רזולוציות גבוהות יותר.

רמת החומרה הנתמכת ניתן לאחזר מ-Camera2CameraInfo. לדוגמה, הקוד הבא הפונקציה בודקת אם המצלמה האחורית שמוגדרת כברירת מחדל היא מכשיר LEVEL_3:

Kotlin

@androidx.annotation.OptIn(ExperimentalCamera2Interop::class)
fun isBackCameraLevel3Device(cameraProvider: ProcessCameraProvider) : Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return CameraSelector.DEFAULT_BACK_CAMERA
            .filter(cameraProvider.availableCameraInfos)
            .firstOrNull()
            ?.let { Camera2CameraInfo.from(it) }
            ?.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
    }
    return false
}

Java

@androidx.annotation.OptIn(markerClass = ExperimentalCamera2Interop.class)
Boolean isBackCameraLevel3Device(ProcessCameraProvider cameraProvider) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        List\ filteredCameraInfos = CameraSelector.DEFAULT_BACK_CAMERA
                .filter(cameraProvider.getAvailableCameraInfos());
        if (!filteredCameraInfos.isEmpty()) {
            return Objects.equals(
                Camera2CameraInfo.from(filteredCameraInfos.get(0)).getCameraCharacteristic(
                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL),
                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3);
        }
    }
    return false;
}

הרשאות

לאפליקציה שלך יידרשו הרשאה CAMERA. שפת תרגום לשמור תמונות בקבצים, נדרשת גם WRITE_EXTERNAL_STORAGE הרשאה, למעט במכשירים עם Android מגרסה 10 ואילך.

למידע נוסף על הגדרת הרשאות לאפליקציה, אפשר לקרוא את המאמר שליחת בקשה הרשאות הניתנות לאפליקציה.

הדרישות

ל- CameraX יש את דרישות הגרסה המינימליות הבאות:

  • Android API רמת 21
  • רכיבי ארכיטקטורה של Android גרסה 1.1.1

לפעילויות שמתחשבות למחזור החיים, השתמשו FragmentActivity או AppCompatActivity

הצהרה על יחסי תלות

כדי להוסיף תלות ב- CameraX, עליך להוסיף את Google Maven למאגר בפרויקט.

פותחים את הקובץ settings.gradle של הפרויקט ומוסיפים את המאגר google() כפי שמוצג באופן הבא:

מגניב

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

Kotlin

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

מוסיפים את הקוד הבא לסוף החסימה של Android:

מגניב

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    // For Kotlin projects
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    // For Kotlin projects
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

מוסיפים את הפרטים הבאים לקובץ build.gradle של כל מודול לאפליקציה:

מגניב

dependencies {
  // CameraX core library using the camera2 implementation
  def camerax_version = "1.4.0-rc01"
  // The following line is optional, as the core library is included indirectly by camera-camera2
  implementation "androidx.camera:camera-core:${camerax_version}"
  implementation "androidx.camera:camera-camera2:${camerax_version}"
  // If you want to additionally use the CameraX Lifecycle library
  implementation "androidx.camera:camera-lifecycle:${camerax_version}"
  // If you want to additionally use the CameraX VideoCapture library
  implementation "androidx.camera:camera-video:${camerax_version}"
  // If you want to additionally use the CameraX View class
  implementation "androidx.camera:camera-view:${camerax_version}"
  // If you want to additionally add CameraX ML Kit Vision Integration
  implementation "androidx.camera:camera-mlkit-vision:${camerax_version}"
  // If you want to additionally use the CameraX Extensions library
  implementation "androidx.camera:camera-extensions:${camerax_version}"
}

Kotlin

dependencies {
    // CameraX core library using the camera2 implementation
    val camerax_version = "1.4.0-rc01"
    // The following line is optional, as the core library is included indirectly by camera-camera2
    implementation("androidx.camera:camera-core:${camerax_version}")
    implementation("androidx.camera:camera-camera2:${camerax_version}")
    // If you want to additionally use the CameraX Lifecycle library
    implementation("androidx.camera:camera-lifecycle:${camerax_version}")
    // If you want to additionally use the CameraX VideoCapture library
    implementation("androidx.camera:camera-video:${camerax_version}")
    // If you want to additionally use the CameraX View class
    implementation("androidx.camera:camera-view:${camerax_version}")
    // If you want to additionally add CameraX ML Kit Vision Integration
    implementation("androidx.camera:camera-mlkit-vision:${camerax_version}")
    // If you want to additionally use the CameraX Extensions library
    implementation("androidx.camera:camera-extensions:${camerax_version}")
}

למידע נוסף על הגדרת האפליקציה כך שתעמוד בדרישות האלה, ראו הצהרה של יחסי התלות.

יכולת פעולה הדדית של CameraX עם Camera2

CameraX מבוסס על Camera2 ו- CameraX חושף דרכים לקרוא ואפילו לכתוב בהטמעה של Camera2. פרטים מלאים זמינים חבילה של יכולת פעולה הדדית.

לקבלת מידע נוסף על האופן שבו המצלמהX הגדירה מאפייני Camera2, השתמשו ב- Camera2CameraInfo כדי לקרוא את CameraCharacteristics הבסיסי. אפשר גם לכתוב את ה- Camera2 באחד משני המסלולים הבאים:

דוגמת הקוד הבאה משתמשת בתרחישים לדוגמה של סטרימינג כדי לבצע אופטימיזציה לשיחת וידאו. שימוש ב-Camera2CameraInfo כדי לאחזר אם התרחיש לדוגמה של שידור שיחת וידאו זמין. לאחר מכן, משתמשים Camera2Interop.Extender כדי להגדיר את התרחיש לדוגמה של השידור הבסיסי.

Kotlin

// Set underlying Camera2 stream use case to optimize for video calls.

val videoCallStreamId =
    CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong()

// Check available CameraInfos to find the first one that supports
// the video call stream use case.
val frontCameraInfo = cameraProvider.getAvailableCameraInfos()
    .first { cameraInfo ->
        val isVideoCallStreamingSupported = Camera2CameraInfo.from(cameraInfo)
            .getCameraCharacteristic(
                CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES
            )?.contains(videoCallStreamId)
        val isFrontFacing = (cameraInfo.getLensFacing() == 
                             CameraSelector.LENS_FACING_FRONT)
        (isVideoCallStreamingSupported == true) && isFrontFacing
    }

val cameraSelector = frontCameraInfo.cameraSelector

// Start with a Preview Builder.
val previewBuilder = Preview.Builder()
    .setTargetAspectRatio(screenAspectRatio)
    .setTargetRotation(rotation)

// Use Camera2Interop.Extender to set the video call stream use case.
Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId)

// Bind the Preview UseCase and the corresponding CameraSelector.
val preview = previewBuilder.build()
camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)

Java

// Set underlying Camera2 stream use case to optimize for video calls.

Long videoCallStreamId =
    CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong();

// Check available CameraInfos to find the first one that supports
// the video call stream use case.
List<CameraInfo> cameraInfos = cameraProvider.getAvailableCameraInfos();
CameraInfo frontCameraInfo = null;
for (cameraInfo in cameraInfos) {
    Long[] availableStreamUseCases = Camera2CameraInfo.from(cameraInfo)
        .getCameraCharacteristic(
            CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES
        );
    boolean isVideoCallStreamingSupported = Arrays.List(availableStreamUseCases)
                .contains(videoCallStreamId);
    boolean isFrontFacing = (cameraInfo.getLensFacing() ==
                             CameraSelector.LENS_FACING_FRONT);

    if (isVideoCallStreamingSupported && isFrontFacing) {
        frontCameraInfo = cameraInfo;
    }
}

if (frontCameraInfo == null) {
    // Handle case where video call streaming is not supported.
}

CameraSelector cameraSelector = frontCameraInfo.getCameraSelector();

// Start with a Preview Builder.
Preview.Builder previewBuilder = Preview.Builder()
    .setTargetAspectRatio(screenAspectRatio)
    .setTargetRotation(rotation);

// Use Camera2Interop.Extender to set the video call stream use case.
Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId);

// Bind the Preview UseCase and the corresponding CameraSelector.
Preview preview = previewBuilder.build()
Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)

מקורות מידע נוספים

למידע נוסף על CameraX, ניתן לעיין במשאבים הנוספים הבאים.

Codelab

  • תחילת העבודה עם CameraX
  • דוגמת קוד

  • אפליקציות לדוגמה של CameraX