สถาปัตยกรรม CameraX

หน้านี้ครอบคลุมสถาปัตยกรรมของ CameraX ซึ่งรวมถึงโครงสร้าง วิธีทำงานกับ API วิธีทำงานกับวงจร และวิธีรวม Use Case

โครงสร้าง CameraX

คุณสามารถใช้ CameraX เพื่อเชื่อมต่อกับกล้องของอุปกรณ์ผ่านนามธรรมที่เรียกว่า Use Case กรณีการใช้งานที่พร้อมใช้งานมีดังนี้

  • Preview: ยอมรับแพลตฟอร์มสำหรับการแสดงตัวอย่าง เช่น PreviewView
  • การวิเคราะห์รูปภาพ: มีบัฟเฟอร์ที่ CPU เข้าถึงได้สำหรับการวิเคราะห์ เช่น สำหรับแมชชีนเลิร์นนิง
  • การจับภาพ: จับภาพและบันทึกรูปภาพ
  • การจับภาพวิดีโอ: จับภาพวิดีโอและเสียงด้วย VideoCapture

คุณสามารถรวม Use Case และใช้งานพร้อมกันได้ ตัวอย่างเช่น แอปสามารถให้ผู้ใช้ดูรูปภาพที่กล้องเห็นโดยใช้ Use Case ของตัวอย่าง มี Use Case ของการวิเคราะห์รูปภาพที่ระบุว่าผู้คนในรูปภาพยิ้มอยู่หรือไม่ และรวม Use Case ของการจับภาพเพื่อถ่ายภาพเมื่อผู้คนยิ้ม

โมเดล API

หากต้องการทำงานกับไลบรารี ให้ระบุสิ่งต่อไปนี้

  • กรณีการใช้งานที่ต้องการพร้อมตัวเลือกการกำหนดค่า
  • สิ่งที่ต้องทำกับข้อมูลเอาต์พุตโดยการแนบ Listener
  • ขั้นตอนที่ต้องการ เช่น เวลาที่ควรเปิดใช้กล้องและเวลาที่ควรสร้างข้อมูล โดยการเชื่อมโยง Use Case กับวงจรของสถาปัตยกรรม Android

การเขียนแอป CameraX มี 2 วิธี ได้แก่ CameraController (เหมาะอย่างยิ่งหากคุณต้องการวิธีที่ง่ายที่สุดในการใช้ CameraX) หรือ CameraProvider (เหมาะอย่างยิ่งหากคุณต้องการความยืดหยุ่นมากขึ้น)

CameraController

CameraController มีฟังก์ชันหลักของ CameraX ส่วนใหญ่ในคลาสเดียว โดยใช้โค้ดการตั้งค่าเพียงเล็กน้อย และจะจัดการการเริ่มต้นกล้อง การจัดการ Use Case การหมุนเป้าหมาย การแตะเพื่อโฟกัส การบีบเพื่อซูม และอื่นๆ โดยอัตโนมัติ คลาสที่เป็นรูปธรรมซึ่งขยาย 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 เพิ่มเติมได้ที่ตัวอย่างตัวสแกนคิวอาร์โค้ดหรือวิดีโอข้อมูลเบื้องต้นเกี่ยวกับ CameraController

CameraProvider

CameraProvider ยังคงใช้งานง่าย แต่เนื่องจากนักพัฒนาแอปเป็นผู้จัดการการตั้งค่าส่วนใหญ่ จึงมีโอกาสปรับแต่งการกำหนดค่าได้มากขึ้น เช่น การเปิดใช้การหมุนรูปภาพเอาต์พุตหรือการตั้งค่ารูปแบบรูปภาพเอาต์พุตใน ImageAnalysis นอกจากนี้ คุณยังใช้ Surface ที่กำหนดเองสำหรับตัวอย่างภาพจากกล้องได้ด้วย ซึ่งช่วยให้มีความยืดหยุ่นมากขึ้น ขณะที่ CameraController กำหนดให้คุณต้องใช้ PreviewView การใช้โค้ด Surface ที่มีอยู่อาจเป็นประโยชน์หากโค้ดดังกล่าวเป็นอินพุตไปยังส่วนอื่นๆ ของแอปอยู่แล้ว

คุณกำหนดค่ากรณีการใช้งานโดยใช้เมธอด set() และสรุปผลด้วยเมธอด build() ออบเจ็กต์กรณีการใช้งานแต่ละรายการจะมีชุด API เฉพาะสำหรับกรณีการใช้งาน ตัวอย่างเช่น กรณีการใช้งานการจับภาพจะมีการเรียกใช้เมธอด takePicture()

แทนที่แอปพลิเคชันจะวางการเรียกใช้เมธอดเริ่มต้นและหยุดที่เฉพาะเจาะจงใน onResume() และ onPause() แอปพลิเคชันจะระบุวงจรเพื่อเชื่อมโยงกล้องกับ cameraProvider.bindToLifecycle() จากนั้นวงจรดังกล่าวจะแจ้งให้ CameraX ทราบว่าควรกำหนดค่าเซสชันการจับภาพของกล้องเมื่อใด และตรวจสอบว่าสถานะของกล้องเปลี่ยนแปลงอย่างเหมาะสมเพื่อให้สอดคล้องกับการเปลี่ยนผ่านของวงจร

ดูขั้นตอนการใช้งานสำหรับ Use Case แต่ละกรณีได้ที่ใช้ตัวอย่าง วิเคราะห์รูปภาพ Image Capture และจับภาพวิดีโอ

กรณีการใช้งานตัวอย่างจะโต้ตอบกับ Surface เพื่อแสดงผล แอปพลิเคชันจะสร้าง Use Case ที่มีตัวเลือกการกำหนดค่าโดยใช้โค้ดต่อไปนี้

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 กรณีการใช้งานจะมีการเรียกใช้เมธอดและ Callback เพื่อตรวจสอบความคืบหน้า

ตามที่อธิบายไว้ในรวมกรณีการใช้งาน คุณสามารถเชื่อมโยงกรณีการใช้งานบางรายการเข้ากับวงจรเดียวได้ เมื่อแอปของคุณต้องรองรับ Use Case ที่ไม่สามารถรวมกันได้ คุณสามารถทำอย่างใดอย่างหนึ่งต่อไปนี้

  • จัดกลุ่มกรณีการใช้งานที่เข้ากันได้ไว้ด้วยกันในส่วนย่อยมากกว่า 1 ส่วน แล้วสลับไปมาระหว่างส่วนย่อยต่างๆ
  • สร้างคอมโพเนนต์วงจรที่กำหนดเองและใช้เพื่อควบคุมวงจรของกล้องด้วยตนเอง

หากคุณแยก LifecycleOwner ของ Use Case ของมุมมองและกล้องออกจากกัน (เช่น หากคุณใช้ Lifecycle ที่กำหนดเองหรือ retain fragment) คุณต้องตรวจสอบว่า Use Case ทั้งหมดไม่ได้เชื่อมโยงกับ CameraX โดยใช้ ProcessCameraProvider.unbindAll() หรือโดยการยกเลิกการเชื่อมโยง Use Case แต่ละรายการแยกกัน หรือเมื่อคุณเชื่อมโยง Use Case กับวงจร คุณสามารถให้ CameraX จัดการการเปิดและปิดเซสชันการจับภาพและการยกเลิกการเชื่อมโยง Use Case ได้

หากฟังก์ชันการทำงานทั้งหมดของกล้องสอดคล้องกับวงจรของคอมโพเนนต์ที่รับรู้วงจรรายการเดียว เช่น AppCompatActivity หรือ Fragment AppCompat การใช้วงจรของคอมโพเนนต์นั้นเมื่อเชื่อมโยง Use Case ที่ต้องการทั้งหมดจะช่วยให้มั่นใจได้ว่าฟังก์ชันการทำงานของกล้องจะพร้อมใช้งานเมื่อคอมโพเนนต์ที่รับรู้วงจรทำงานอยู่ และจะถูกกำจัดอย่างปลอดภัยโดยไม่ใช้ทรัพยากรใดๆ

LifecycleOwner ที่กำหนดเอง

สำหรับกรณีขั้นสูง คุณสามารถสร้าง 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() เพียงครั้งเดียวจะดีกว่า ดูข้อมูลเพิ่มเติมเกี่ยวกับแนวทางปฏิบัติแนะนำสำหรับการเปลี่ยนแปลงการกำหนดค่าได้ที่หัวข้อจัดการการเปลี่ยนแปลงการกำหนดค่า

ในตัวอย่างโค้ดต่อไปนี้ แอปจะระบุกรณีการใช้งาน 2 กรณีที่จะสร้างและเรียกใช้พร้อมกัน นอกจากนี้ยังระบุวงจรที่จะใช้สำหรับทั้ง 2 Use Case เพื่อให้ทั้ง 2 Use Case เริ่มต้นและหยุดตามวงจร

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 พร้อมกันได้ 1 อินสแตนซ์ต่อรายการ นอกจากนี้

  • กรณีการใช้งานแต่ละกรณีสามารถทำงานได้ด้วยตัวเอง เช่น แอปสามารถบันทึกวิดีโอได้โดยไม่ต้องใช้ตัวอย่าง
  • เมื่อเปิดใช้ส่วนขยาย ระบบจะรับประกันการทำงานเฉพาะเมื่อใช้ ImageCapture และ Preview ร่วมกันเท่านั้น ทั้งนี้ขึ้นอยู่กับการติดตั้งใช้งานของ OEM โดยอาจเพิ่ม ImageAnalysis ไม่ได้ และไม่สามารถเปิดใช้ส่วนขยายสำหรับ Use Case 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

ประกาศทรัพยากร Dependency

หากต้องการเพิ่มทรัพยากร Dependency ใน 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}")
}

ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดค่าแอปให้เป็นไปตามข้อกำหนดเหล่านี้ได้ที่การประกาศทรัพยากร Dependency

ความสามารถในการทำงานร่วมกันของ CameraX กับ Camera2

CameraX สร้างขึ้นบน Camera2 และ CameraX แสดงวิธีอ่านและเขียนพร็อพเพอร์ตี้ในการใช้งาน Camera2 ดูรายละเอียดทั้งหมดได้ที่แพ็กเกจ Interop

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ CameraX กำหนดค่าพร็อพเพอร์ตี้ Camera2 โดยใช้ Camera2CameraInfo เพื่ออ่าน CameraCharacteristics ที่สำคัญ นอกจากนี้ คุณยังเลือกเขียนพร็อพเพอร์ตี้ Camera2 ที่สำคัญได้ด้วยวิธีใดวิธีหนึ่งจาก 2 วิธีต่อไปนี้

  • ใช้ Camera2CameraControl ซึ่งช่วยให้คุณตั้งค่าพร็อพเพอร์ตี้ใน CaptureRequest ที่สำคัญได้ เช่น โหมดโฟกัสอัตโนมัติ

  • ขยาย UseCase ของ CameraX ด้วย Camera2Interop.Extender ซึ่งช่วยให้คุณตั้งค่าพร็อพเพอร์ตี้ใน CaptureRequest ได้เช่นเดียวกับ Camera2CameraControl นอกจากนี้ ยังให้การควบคุมเพิ่มเติมบางอย่าง เช่น การตั้งค่า Use Case ของสตรีมเพื่อเพิ่มประสิทธิภาพกล้องสำหรับสถานการณ์การใช้งานของคุณ ดูข้อมูลเพิ่มเติมได้ที่ใช้ Use Case ของสตรีมเพื่อประสิทธิภาพที่ดีขึ้น

ตัวอย่างโค้ดต่อไปนี้ใช้ Use Case ของสตรีมเพื่อเพิ่มประสิทธิภาพสำหรับวิดีโอคอล ใช้ 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