ארכיטקטורת CameraX

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

המבנה של CameraX

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

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

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

מודל API

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

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

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

CameraController

‫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, משתמשים ב-method‏ setEnabledUseCases().

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

CameraProvider

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

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

במקום שהאפליקציה תציב קריאות ספציפיות ל-method של התחלה ועצירה ב-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.

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

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

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

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

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

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

‫LifecycleOwners בהתאמה אישית

במקרים מתקדמים, אפשר ליצור LifecycleOwner בהתאמה אישית כדי לאפשר לאפליקציה לשלוט באופן מפורש במחזור החיים של הסשן ב-CameraX, במקום לקשר אותו ל-LifecycleOwner רגיל של 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, האפליקציה יכולה להציב מעברי מצב בנקודות הרצויות בקוד שלה. כדי לקבל מידע נוסף על הטמעת הפונקציונליות הזו באפליקציה, קראו את המאמר הטמעת 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));
}

‫CameraX מאפשר שימוש בו-זמני במופע אחד של כל אחד מהרכיבים הבאים: Preview,‏ VideoCapture,‏ ImageAnalysis ו-ImageCapture. בנוסף,

  • כל תרחיש לדוגמה יכול לפעול בפני עצמו. לדוגמה, אפליקציה יכולה לצלם סרטון בלי להשתמש בתצוגה מקדימה.
  • כשהתוספים מופעלים, רק השילוב של ImageCapture ו-Preview יפעל בוודאות. בהתאם להטמעה של ה-OEM, יכול להיות שאי אפשר להוסיף גם את ImageAnalysis. אי אפשר להפעיל תוספים לתרחיש לדוגמה של VideoCapture. לפרטים נוספים, עיינו במסמך העזר בנושא תוספים.
  • בהתאם ליכולות של המצלמה, יכול להיות שחלק מהמצלמות יתמכו בשילוב במצבי רזולוציה נמוכים יותר, אבל לא יתמכו באותו שילוב ברזולוציות גבוהות יותר.
  • במכשירים עם רמת חומרה של מצלמה FULL או פחות, שילוב של Preview, VideoCapture ו-ImageCapture או ImageAnalysis עלול לאלץ את CameraX לשכפל את הסטרימינג של PRIV במצלמה בשביל Preview ו-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\<CameraInfo\> 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 של כל מודול באפליקציה:

Groovy

dependencies {
  // CameraX core library using the camera2 implementation
  def camerax_version = "1.7.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.7.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, והיא חושפת דרכים לקרוא ואפילו לכתוב מאפיינים בהטמעה של Camera2. לפרטים מלאים, ראו חבילת Interop.

כדי לקבל מידע נוסף על האופן שבו CameraX הגדירה את המאפיינים של 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