Opsi konfigurasi

Anda mengonfigurasi setiap kasus penggunaan CameraX untuk mengontrol berbagai aspek operasi kasus penggunaan.

Misalnya, pada kasus penggunaan pengambilan gambar, Anda dapat menentukan rasio lebar tinggi target dan mode flash. Kode berikut menampilkan satu contoh:

Kotlin

val imageCapture = ImageCapture.Builder()
    .setFlashMode(...)
    .setTargetAspectRatio(...)
    .build()

Java

ImageCapture imageCapture =
    new ImageCapture.Builder()
        .setFlashMode(...)
        .setTargetAspectRatio(...)
        .build();

Selain opsi konfigurasi, beberapa kasus penggunaan mengekspos API untuk secara dinamis mengubah setelan setelah kasus penggunaan dibuat. Untuk informasi tentang konfigurasi yang berlaku khusus bagi kasus penggunaan tertentu, lihat Mengimplementasikan pratinjau, Menganalisis gambar, dan Mengambil foto.

CameraXConfig

Untuk kemudahan, CameraX memiliki konfigurasi default seperti eksekutor dan pengendali internal yang cocok untuk sebagian besar skenario penggunaan. Namun, jika aplikasi Anda memiliki persyaratan khusus atau lebih memilih untuk menyesuaikan konfigurasi tersebut, CameraXConfig adalah antarmuka untuk tujuan tersebut.

Dengan CameraXConfig, aplikasi dapat melakukan hal berikut:

Model Penggunaan

Prosedur berikut menjelaskan cara menggunakan CameraXConfig:

  1. Membuat objek CameraXConfig dengan konfigurasi yang disesuaikan.
  2. Mengimplementasikan antarmuka CameraXConfig.Provider di Application, dan menampilkan objek CameraXConfig Anda di getCameraXConfig().
  3. Menambahkan class Application ke file AndroidManifest.xml, seperti yang dijelaskan di sini.

Misalnya, contoh kode berikut membatasi logging CameraX hanya untuk pesan error:

Kotlin

class CameraApplication : Application(), CameraXConfig.Provider {
   override fun getCameraXConfig(): CameraXConfig {
       return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
           .setMinimumLoggingLevel(Log.ERROR).build()
   }
}

Simpan salinan lokal objek CameraXConfig jika aplikasi Anda perlu mengetahui konfigurasi CameraX setelah menyetelnya.

Pembatas Kamera

Selama pemanggilan ProcessCameraProvider.getInstance() pertama, CameraX menguraikan dan mengirim kueri karakteristik kamera yang tersedia di perangkat. Karena CameraX perlu berkomunikasi dengan komponen hardware, proses ini dapat memakan waktu yang tidak singkat untuk setiap kamera, terutama pada perangkat kelas bawah. Jika aplikasi Anda hanya menggunakan kamera tertentu pada perangkat, seperti kamera depan default, Anda bisa menyetel CameraX untuk mengabaikan kamera lain sehingga dapat mengurangi latensi pengaktifan untuk kamera yang digunakan aplikasi.

Jika CameraSelector yang diteruskan ke CameraXConfig.Builder.setAvailableCamerasLimiter() memfilter kamera, CameraX akan berperilaku seolah-olah kamera tersebut tidak ada Google. Misalnya, kode berikut membatasi aplikasi untuk hanya menggunakan kamera belakang default perangkat:

Kotlin

class MainApplication : Application(), CameraXConfig.Provider {
   override fun getCameraXConfig(): CameraXConfig {
       return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
              .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA)
              .build()
   }
}

Thread

Banyak API platform tempat CameraX dibuat memerlukan pemblokiran komunikasi antar-proses (IPC) dengan hardware yang terkadang memerlukan waktu ratusan milidetik untuk merespons. Karena alasan ini, CameraX hanya memanggil API ini dari thread latar belakang sehingga thread utama tidak diblokir dan UI tetap berjalan. CameraX mengelola thread latar belakang ini secara internal sehingga perilaku ini terlihat transparan. Namun, beberapa aplikasi memerlukan kontrol thread yang ketat. CameraXConfig memungkinkan aplikasi menetapkan thread latar belakang yang digunakan melalui CameraXConfig.Builder.setCameraExecutor() dan CameraXConfig.Builder.setSchedulerHandler() Google.

Eksekutor Kamera

Eksekutor kamera digunakan untuk semua panggilan API platform Kamera internal, serta untuk callback dari API ini. CameraX mengalokasikan dan mengelola Executor internal untuk melakukan tugas ini. Namun, jika aplikasi Anda memerlukan kontrol thread yang lebih ketat, gunakan CameraXConfig.Builder.setCameraExecutor().

Pengendali Penjadwal

Pengendali penjadwal digunakan untuk menjadwalkan tugas internal pada interval tetap, seperti mencoba kembali membuka kamera saat tidak tersedia. Pengendali ini tidak menjalankan tugas, dan hanya mengirimkannya ke eksekutor kamera. Pengendali ini juga terkadang digunakan di platform API lama yang memerlukan Handler untuk callback. Dalam hal ini, callback masih hanya dikirim langsung ke eksekutor kamera. CameraX mengalokasikan dan mengelola HandlerThread internal untuk melakukan tugas ini, tetapi Anda dapat menggantinya dengan CameraXConfig.Builder.setSchedulerHandler().

Logging

Logging CameraX memungkinkan aplikasi memfilter pesan logcat karena ini adalah praktik yang baik untuk menghindari pesan panjang dalam kode produksi. CameraX mendukung empat level logging, dari yang paling panjang hingga yang paling berat:

  • Log.DEBUG (default)
  • Log.INFO
  • Log.WARN
  • Log.ERROR

Lihat dokumentasi Log Android untuk deskripsi mendetail tentang level log ini. Gunakan CameraXConfig.Builder.setMinimumLoggingLevel(int) untuk menetapkan level logging yang sesuai bagi aplikasi.

Pemilihan otomatis

CameraX otomatis menyediakan fungsionalitas yang berlaku khusus untuk perangkat yang menjalankan aplikasi Anda. Misalnya, CameraX akan otomatis menentukan resolusi terbaik yang akan digunakan jika Anda tidak menentukan resolusi, atau jika resolusi yang Anda tentukan tidak didukung. Semua ini ditangani oleh library sehingga Anda tidak perlu menuliskan kode khusus perangkat.

Sasaran CameraX adalah menginisialisasi sesi kamera dengan sukses. Ini berarti CameraX menerima resolusi dan rasio aspek berdasarkan kemampuan perangkat. Kompromi ini bisa terjadi karena:

  • Perangkat tidak mendukung resolusi yang diminta.
  • Perangkat memiliki masalah kompatibilitas, seperti perangkat lama yang memerlukan resolusi tertentu agar dapat beroperasi dengan benar.
  • Pada beberapa perangkat, format tertentu hanya tersedia pada rasio aspek tertentu.
  • Perangkat memiliki preferensi "nearest mod16" untuk encoding JPEG atau video. Untuk mengetahui informasi selengkapnya, lihat SCALER_STREAM_CONFIGURATION_MAP.

Meskipun CameraX membuat dan mengelola sesi, Anda harus selalu memeriksa ukuran gambar yang ditampilkan pada output kasus penggunaan dalam kode Anda dan menyesuaikannya.

Rotasi

Secara default, rotasi kamera disetel agar mengikuti rotasi tampilan default selama pembuatan kasus penggunaan. Dalam kasus default ini, CameraX menghasilkan output yang memungkinkan aplikasi mencocokkan dengan apa yang ingin Anda lihat di pratinjau. Anda dapat mengubah rotasi ke nilai kustom untuk mendukung perangkat multi-tampilan dengan meneruskan orientasi tampilan saat ini saat mengonfigurasi objek kasus penggunaan, atau secara dinamis setelah objek selesai dibuat.

Aplikasi Anda dapat menetapkan rotasi target menggunakan setelan konfigurasi. Kemudian, perangkat dapat memperbarui setelan rotasi menggunakan metode dari API kasus penggunaan (seperti ImageAnalysis.setTargetRotation()), bahkan saat siklus proses sedang berjalan. Anda dapat menggunakan cara ini saat aplikasi terkunci ke mode potret sehingga konfigurasi ulang tidak diperlukan saat rotasi terjadi, tetapi kasus penggunaan pengambilan foto atau analisis gambar perlu informasi rotasi saat ini dari perangkat. Misalnya, kemampuan mendeteksi rotasi mungkin diperlukan sehingga wajah diorientasikan dengan tepat untuk deteksi wajah, atau foto disetel ke mode lanskap atau potret.

Data untuk gambar yang diambil dapat disimpan tanpa informasi rotasi. Data Exif berisi informasi rotasi sehingga aplikasi galeri dapat menampilkan gambar dalam orientasi yang benar setelah disimpan.

Untuk menampilkan data pratinjau dengan orientasi yang benar, Anda dapat menggunakan output metadata dari Preview.PreviewOutput() untuk membuat transformasi.

Contoh kode berikut menunjukkan cara menentukan rotasi pada peristiwa orientasi:

Kotlin

override fun onCreate() {
    val imageCapture = ImageCapture.Builder().build()

    val orientationEventListener = object : OrientationEventListener(this as Context) {
        override fun onOrientationChanged(orientation : Int) {
            // Monitors orientation values to determine the target rotation value
            val rotation : Int = when (orientation) {
                in 45..134 -> Surface.ROTATION_270
                in 135..224 -> Surface.ROTATION_180
                in 225..314 -> Surface.ROTATION_90
                else -> Surface.ROTATION_0
            }

            imageCapture.targetRotation = rotation
        }
    }
    orientationEventListener.enable()
}

Java

@Override
public void onCreate() {
    ImageCapture imageCapture = new ImageCapture.Builder().build();

    OrientationEventListener orientationEventListener = new OrientationEventListener((Context)this) {
       @Override
       public void onOrientationChanged(int orientation) {
           int rotation;

           // Monitors orientation values to determine the target rotation value
           if (orientation >= 45 && orientation < 135) {
               rotation = Surface.ROTATION_270;
           } else if (orientation >= 135 && orientation < 225) {
               rotation = Surface.ROTATION_180;
           } else if (orientation >= 225 && orientation < 315) {
               rotation = Surface.ROTATION_90;
           } else {
               rotation = Surface.ROTATION_0;
           }

           imageCapture.setTargetRotation(rotation);
       }
    };

    orientationEventListener.enable();
}

Berdasarkan rotasi yang ditetapkan, setiap kasus penggunaan merotasi data gambar secara langsung atau memberikan metadata rotasi kepada pemakai data gambar yang tidak dirotasi.

  • Preview: Output metadata disediakan sehingga rotasi resolusi target diketahui menggunakan Preview.getTargetRotation().
  • ImageAnalysis: Output metadata disediakan sehingga koordinat buffer gambar diketahui relatif terhadap koordinat tampilan.
  • ImageCapture: Metadata Exif gambar, buffering, atau buffering beserta metadata akan diubah untuk mencatat setelan rotasi. Nilai yang diubah bergantung pada implementasi HAL.

Crop rect

Secara default, crop rect merupakan rect buffer penuh. Anda dapat menyesuaikannya dengan ViewPort dan UseCaseGroup. Dengan mengelompokkan kasus penggunaan dan menyetel area tampilan, CameraX menjamin bahwa crop rect semua kasus penggunaan dalam grup mengarah ke area yang sama di sensor kamera.

Cuplikan kode berikut menunjukkan cara menggunakan kedua class ini:

Kotlin

val viewPort =  ViewPort.Builder(Rational(width, height), display.rotation).build()
val useCaseGroup = UseCaseGroup.Builder()
    .addUseCase(preview)
    .addUseCase(imageAnalysis)
    .addUseCase(imageCapture)
    .setViewPort(viewPort)
    .build()
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup)

Java

ViewPort viewPort = new ViewPort.Builder(
         new Rational(width, height),
         getDisplay().getRotation()).build();
UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
    .addUseCase(preview)
    .addUseCase(imageAnalysis)
    .addUseCase(imageCapture)
    .setViewPort(viewPort)
    .build();
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);

ViewPort menentukan rect buffer yang terlihat oleh pengguna akhir. Kemudian CameraX menghitung kemungkinan crop rect terbesar berdasarkan properti area tampilan dan kasus penggunaan terlampir. Biasanya, untuk mendapatkan efek WYSIWYG, Anda dapat mengonfigurasi area tampilan berdasarkan kasus penggunaan pratinjau. Cara mudah untuk mendapatkan area tampilan adalah dengan menggunakan PreviewView.

Cuplikan kode berikut menunjukkan cara mendapatkan objek ViewPort:

Kotlin

val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort

Java

ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();

Pada contoh sebelumnya, objek yang didapat aplikasi dari ImageAnalysis dan ImageCapture cocok dengan yang dilihat pengguna akhir dalam PreviewView, dengan asumsi jenis skala PreviewView ditetapkan ke default, FILL_CENTER. Setelah menerapkan crop rect dan rotasi ke buffering output, gambar dari semua kasus penggunaan akan tetap sama, meskipun mungkin dengan resolusi yang berbeda. Untuk mengetahui informasi selengkapnya tentang cara menerapkan info transformasi, lihat mentransformasi output.

Pemilihan kamera

CameraX otomatis memilih perangkat kamera terbaik untuk persyaratan dan kasus penggunaan aplikasi Anda. Jika Anda ingin menggunakan perangkat selain yang dipilih untuk Anda, ada beberapa opsi:

Contoh kode berikut menggambarkan cara membuat CameraSelector untuk memengaruhi pemilihan perangkat:

Kotlin

fun selectExternalOrBestCamera(provider: ProcessCameraProvider):CameraSelector? {
   val cam2Infos = provider.availableCameraInfos.map {
       Camera2CameraInfo.from(it)
   }.sortedByDescending {
       // HARDWARE_LEVEL is Int type, with the order of:
       // LEGACY < LIMITED < FULL < LEVEL_3 < EXTERNAL
       it.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)
   }

   return when {
       cam2Infos.isNotEmpty() -> {
           CameraSelector.Builder()
               .addCameraFilter {
                   it.filter { camInfo ->
                       // cam2Infos[0] is either EXTERNAL or best built-in camera
                       val thisCamId = Camera2CameraInfo.from(camInfo).cameraId
                       thisCamId == cam2Infos[0].cameraId
                   }
               }.build()
       }
       else -> null
    }
}

// create a CameraSelector for the USB camera (or highest level internal camera)
val selector = selectExternalOrBestCamera(processCameraProvider)
processCameraProvider.bindToLifecycle(this, selector, preview, analysis)

Memilih beberapa kamera secara bersamaan

Mulai CameraX 1.3, Anda juga dapat memilih beberapa kamera secara serentak. Misalnya, Anda dapat mengikat ke kamera depan dan belakang untuk mengambil foto atau merekam video dari kedua perspektif secara bersamaan.

Saat menggunakan fitur Kamera Serentak, perangkat dapat mengoperasikan dua kamera dengan lensa menghadap berbeda secara bersamaan, atau mengoperasikan dua kamera belakang secara bersamaan. Blok kode berikut menunjukkan cara menetapkan dua kamera saat memanggil bindToLifecycle, dan cara mendapatkan kedua objek Kamera dari objek ConcurrentCamera yang ditampilkan.

Kotlin

// Build ConcurrentCameraConfig
val primary = ConcurrentCamera.SingleCameraConfig(
    primaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
)

val secondary = ConcurrentCamera.SingleCameraConfig(
    secondaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
)

val concurrentCamera = cameraProvider.bindToLifecycle(
    listOf(primary, secondary)
)

val primaryCamera = concurrentCamera.cameras[0]
val secondaryCamera = concurrentCamera.cameras[1]

Java

// Build ConcurrentCameraConfig
SingleCameraConfig primary = new SingleCameraConfig(
    primaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
);

SingleCameraConfig secondary = new SingleCameraConfig(
    primaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
);

ConcurrentCamera concurrentCamera =  
    mCameraProvider.bindToLifecycle(Arrays.asList(primary, secondary));

Camera primaryCamera = concurrentCamera.getCameras().get(0);
Camera secondaryCamera = concurrentCamera.getCameras().get(1);

Resolusi kamera

Anda dapat mengizinkan CameraX menyetel resolusi gambar berdasarkan kombinasi kapabilitas perangkat, tingkat hardware yang didukung perangkat, kasus penggunaan, dan rasio aspek yang tersedia. Cara lain, Anda dapat menetapkan resolusi target spesifik atau rasio aspek spesifik dalam kasus penggunaan yang mendukung konfigurasi tersebut.

Resolusi otomatis

CameraX dapat otomatis menentukan setelan resolusi terbaik berdasarkan kasus penggunaan yang ditentukan di cameraProcessProvider.bindToLifecycle(). Jika memungkinkan, tentukan semua kasus penggunaan yang diperlukan untuk dijalankan secara bersamaan dalam satu sesi dalam satu panggilan bindToLifecycle(). CameraX menentukan resolusi berdasarkan kumpulan kasus penggunaan dengan mempertimbangkan tingkat hardware yang didukung perangkat dan dengan memperhitungkan varian khusus perangkat (saat perangkat melebihi atau tidak memenuhi konfigurasi streaming tersedia). Tujuannya agar aplikasi dapat berjalan pada berbagai jenis perangkat sembari meminimalkan jalur kode khusus perangkat.

Rasio aspek default untuk kasus penggunaan pengambilan gambar dan analisis gambar adalah 4:3.

Kasus penggunaan memiliki rasio aspek yang dapat dikonfigurasi yang memungkinkan aplikasi menentukan rasio aspek yang diinginkan berdasarkan desain UI. Output CameraX dihasilkan untuk dicocokkan dengan rasio aspek yang diminta, yang sedekat mungkin dengan yang didukung perangkat. Jika tidak ada resolusi yang sama persis dengan yang didukung, resolusi yang memenuhi sebagian besar kondisi akan dipilih. Dengan begitu, aplikasi akan menentukan cara kamera ditampilkan pada aplikasi, dan CameraX menentukan setelan resolusi kamera terbaik untuk memenuhi kondisi itu di perangkat berbeda.

Misalnya, aplikasi dapat melakukan salah satu hal berikut:

  • Menentukan resolusi target sebesar 4:3 atau 16:9 untuk kasus penggunaan
  • Menentukan resolusi khusus yang akan digunakan CameraX untuk menemukan kecocokan terdekat
  • Menentukan rasio aspek pemangkasan untuk ImageCapture

CameraX memilih resolusi permukaan Camera2 internal secara otomatis. Tabel berikut menampilkan berbagai resolusi:

Kasus penggunaan Resolusi permukaan internal Resolusi data output
Pratinjau Rasio Lebar Tinggi: Resolusi yang paling sesuai untuk target berdasarkan setelan. Resolusi permukaan internal. Metadata disediakan agar Tampilan dapat dipangkas, diskalakan, dan dirotasi sesuai rasio aspek target.
Resolusi default: Resolusi pratinjau tertinggi, atau resolusi tertinggi pilihan perangkat yang cocok dengan rasio aspek Pratinjau.
Resolusi maksimum: Ukuran pratinjau, menunjukkan ukuran yang paling cocok dengan resolusi layar perangkat, atau dengan 1080p (1920x1080), mana pun yang lebih kecil.
Analisis gambar Rasio lebar tinggi: Resolusi yang paling sesuai untuk target berdasarkan setelan. Resolusi permukaan internal.
Resolusi default: Setelan resolusi target default adalah 640x480. Menyesuaikan resolusi target dan rasio aspek yang terkait akan menghasilkan resolusi terbaik yang didukung.
Resolusi maksimum: Resolusi output maksimum perangkat kamera dari format YUV_420_888 yang diambil dari StreamConfigurationMap.getOutputSizes(). Resolusi target disetel ke 640x480 secara default sehingga jika ingin resolusi lebih besar dari 640x480, Anda harus menggunakan setTargetResolution() dan setTargetAspectRatio() untuk mendapatkan yang terdekat dari resolusi yang didukung.
Pengambilan gambar Rasio lebar tinggi: Rasio lebar tinggi yang paling sesuai dengan setelan. Resolusi permukaan internal.
Resolusi default: Resolusi tertinggi yang tersedia, atau resolusi tertinggi pilihan perangkat yang cocok dengan rasio aspek ImageCapture.
Resolusi maksimum: Resolusi output maksimum perangkat kamera dalam format JPEG. Gunakan StreamConfigurationMap.getOutputSizes() untuk mengambilnya.

Menentukan resolusi

Anda dapat menentukan resolusi tertentu saat membuat kasus penggunaan menggunakan metode setTargetResolution(Size resolution), seperti yang ditunjukkan dalam contoh kode berikut:

Kotlin

val imageAnalysis = ImageAnalysis.Builder()
    .setTargetResolution(Size(1280, 720))
    .build()

Java

ImageAnalysis imageAnalysis =
  new ImageAnalysis.Builder()
    .setTargetResolution(new Size(1280, 720))
    .build();

Anda tidak dapat menetapkan rasio aspek target dan resolusi target pada kasus penggunaan yang sama. Tindakan ini akan memunculkan IllegalArgumentException saat mem-build objek konfigurasi.

Nyatakan Size resolusi dalam bingkai koordinat setelah memutar ukuran yang didukung oleh rotasi target. Misalnya, perangkat yang memiliki orientasi alami potret dengan rotasi target alami yang meminta gambar potret dapat menetapkan 480x640, dan perangkat yang sama, diputar 90 derajat serta menargetkan orientasi lanskap dapat menetapkan 640x480.

Resolusi target berupaya menetapkan batas minimum untuk resolusi gambar. Resolusi gambar yang sebenarnya adalah ukuran terdekat yang tersedia, yang tidak lebih kecil dari resolusi target, seperti yang ditentukan oleh penerapan Kamera.

Namun, jika tidak ada resolusi yang sama dengan atau lebih besar dari resolusi target, resolusi terdekat yang tersedia yang lebih kecil dari resolusi target akan dipilih. Resolusi dengan rasio aspek yang sama dengan Size yang disediakan akan diberi prioritas lebih tinggi daripada resolusi rasio aspek yang berbeda.

CameraX menerapkan resolusi terbaik yang sesuai berdasarkan permintaan. Jika kebutuhan utamanya adalah memenuhi rasio aspek, cukup tentukan setTargetAspectRatio, dan CameraX akan menentukan resolusi spesifik yang sesuai berdasarkan perangkatnya. Jika kebutuhan utama aplikasi adalah menentukan resolusi agar pemrosesan gambar lebih efisien (misalnya gambar kecil atau sedang berdasarkan kemampuan pemrosesan perangkat), gunakan setTargetResolution(Size resolution).

Jika aplikasi Anda memerlukan resolusi yang sama persis, lihat tabel dalam createCaptureSession() untuk menentukan resolusi maksimum yang didukung oleh setiap tingkat hardware. Untuk memeriksa resolusi spesifik yang didukung oleh perangkat saat ini, lihat StreamConfigurationMap.getOutputSizes(int).

Jika aplikasi Anda berjalan di Android 10 atau yang lebih baru, Anda dapat menggunakan isSessionConfigurationSupported() untuk memverifikasi SessionConfiguration spesifik.

Mengontrol output kamera

Selain memungkinkan Anda mengonfigurasi output kamera sesuai kebutuhan untuk setiap kasus penggunaan individual, CameraX juga menerapkan antarmuka berikut untuk mendukung operasi kamera yang umum pada semua kasus penggunaan terikat:

  • CameraControl memungkinkan Anda mengonfigurasi fitur kamera umum.
  • CameraInfo memungkinkan Anda meng-kueri status fitur kamera umum tersebut.

Berikut adalah fitur kamera yang didukung dengan CameraControl:

  • Zoom
  • Flash
  • Fokus dan Pengukuran (ketuk untuk memfokuskan)
  • Exposure Compensation

Mendapatkan instance CameraControl dan CameraInfo

Ambil instance CameraControl dan CameraInfo menggunakan objek Camera yang ditampilkan oleh ProcessCameraProvider.bindToLifecycle(). Kode berikut menampilkan contoh:

Kotlin

val camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// For performing operations that affect all outputs.
val cameraControl = camera.cameraControl
// For querying information and states.
val cameraInfo = camera.cameraInfo

Java

Camera camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// For performing operations that affect all outputs.
CameraControl cameraControl = camera.getCameraControl()
// For querying information and states.
CameraInfo cameraInfo = camera.getCameraInfo()

Misalnya, Anda dapat mengirimkan operasi zoom dan operasi CameraControl lainnya setelah memanggil bindToLifecycle(). Setelah Anda menghentikan atau menghancurkan aktivitas yang digunakan untuk mengikat instance kamera, CameraControl tidak dapat lagi menjalankan operasi dan menampilkan ListenableFuture yang gagal.

Zoom

CameraControl menawarkan dua metode untuk mengubah tingkat zoom:

  • setZoomRatio() menyetel zoom berdasarkan rasio zoom.

    Rasio harus berada dalam rentang CameraInfo.getZoomState().getValue().getMinZoomRatio() dan CameraInfo.getZoomState().getValue().getMaxZoomRatio(). Jika tidak, fungsi akan menampilkan ListenableFuture yang gagal.

  • setLinearZoom() menyetel zoom saat ini dengan nilai zoom linier yang berkisar dari 0 hingga 1,0.

    Keuntungan zoom linier adalah membuat ruang pandang (FOV) berskala dengan perubahan zoom. Ini membuatnya cocok untuk digunakan dengan tampilan Slider.

CameraInfo.getZoomState() menampilkan LiveData dari status zoom saat ini. Nilainya berubah saat kamera diinisialisasi atau jika tingkat zoom disetel menggunakan setZoomRatio() atau setLinearZoom(). Memanggil salah satu metode akan menetapkan nilai yang mendukung ZoomState.getZoomRatio() dan ZoomState.getLinearZoom(). Hal ini berguna jika Anda ingin menampilkan teks rasio zoom di samping penggeser. Cukup amati ZoomState LiveData untuk memperbarui keduanya tanpa perlu melakukan konversi.

ListenableFuture yang ditampilkan oleh kedua API menawarkan opsi bagi aplikasi untuk diberi tahu kapan permintaan berulang dengan nilai zoom yang ditentukan selesai. Selain itu, jika Anda menetapkan nilai zoom baru saat operasi sebelumnya masih dijalankan, ListenableFuture operasi zoom sebelumnya akan langsung gagal.

Flash

CameraControl.enableTorch(boolean) mengaktifkan atau menonaktifkan flash (juga dikenal sebagai senter).

CameraInfo.getTorchState() dapat digunakan untuk meng-kueri status flash saat ini. Anda dapat memeriksa nilai yang ditampilkan oleh CameraInfo.hasFlashUnit() untuk menentukan apakah flash tersedia. Jika tidak, memanggil CameraControl.enableTorch(boolean) akan menyebabkan ListenableFuture yang ditampilkan segera selesai dengan hasil yang gagal dan menyetel status flash ke TorchState.OFF.

Saat diaktifkan, flash akan tetap aktif selama pengambilan foto dan video terlepas dari setelan flashMode. flashMode di ImageCapture hanya berfungsi jika flash dinonaktifkan.

Fokus dan Pengukuran

CameraControl.startFocusAndMetering() memicu fokus otomatis dan pengukuran eksposur dengan menyetel area pengukuran AF/AE/AWB berdasarkan FocusMeteringAction yang ditentukan. Ini sering digunakan untuk mengimplementasikan fitur “ketuk untuk fokus” di banyak aplikasi kamera.

MeteringPoint

Untuk memulai, buat MeteringPoint menggunakan MeteringPointFactory.createPoint(float x, float y, float size). MeteringPoint mewakili satu titik pada kamera Surface. Ini disimpan dalam bentuk yang dinormalkan sehingga dapat dengan mudah dikonversi ke koordinat sensor untuk menentukan area AF/AE/AWB.

Ukuran MeteringPoint berkisar dari 0 hingga 1 dengan ukuran default 0,15f. Saat memanggil MeteringPointFactory.createPoint(float x, float y, float size), CameraX akan membuat area persegi panjang yang berpusat pada (x, y) untuk size yang disediakan.

Kode berikut menunjukkan cara membuat MeteringPoint:

Kotlin

// Use PreviewView.getMeteringPointFactory if PreviewView is used for preview.
previewView.setOnTouchListener((view, motionEvent) ->  {
val meteringPoint = previewView.meteringPointFactory
    .createPoint(motionEvent.x, motionEvent.y)
…
}

// Use DisplayOrientedMeteringPointFactory if SurfaceView / TextureView is used for
// preview. Please note that if the preview is scaled or cropped in the View,
// it’s the application's responsibility to transform the coordinates properly
// so that the width and height of this factory represents the full Preview FOV.
// And the (x,y) passed to create MeteringPoint might need to be adjusted with
// the offsets.
val meteringPointFactory = DisplayOrientedMeteringPointFactory(
     surfaceView.display,
     camera.cameraInfo,
     surfaceView.width,
     surfaceView.height
)

// Use SurfaceOrientedMeteringPointFactory if the point is specified in
// ImageAnalysis ImageProxy.
val meteringPointFactory = SurfaceOrientedMeteringPointFactory(
     imageWidth,
     imageHeight,
     imageAnalysis)

startFocusAndMetering dan FocusMeteringAction

Untuk memanggil startFocusAndMetering(), aplikasi harus membangun FocusMeteringAction, yang terdiri dari satu atau beberapa MeteringPoints dengan kombinasi mode pengukuran opsional dari FLAG_AF, FLAG_AE, FLAG_AWB. Kode berikut menunjukkan penggunaan ini:

Kotlin

val meteringPoint1 = meteringPointFactory.createPoint(x1, x1)
val meteringPoint2 = meteringPointFactory.createPoint(x2, y2)
val action = FocusMeteringAction.Builder(meteringPoint1) // default AF|AE|AWB
      // Optionally add meteringPoint2 for AF/AE.
      .addPoint(meteringPoint2, FLAG_AF | FLAG_AE)
      // The action is canceled in 3 seconds (if not set, default is 5s).
      .setAutoCancelDuration(3, TimeUnit.SECONDS)
      .build()

val result = cameraControl.startFocusAndMetering(action)
// Adds listener to the ListenableFuture if you need to know the focusMetering result.
result.addListener({
   // result.get().isFocusSuccessful returns if the auto focus is successful or not.
}, ContextCompat.getMainExecutor(this)

Seperti yang ditunjukkan dalam kode sebelumnya, startFocusAndMetering() mengambil FocusMeteringAction yang terdiri dari satu MeteringPoint untuk area pengukuran AF/AE/AWB dan satu lagi MeteringPoint hanya untuk AF dan AE.

Secara internal, CameraX mengonversinya menjadi MeteringRectangles Camera2 dan menyetel parameter CONTROL_AF_REGIONS / CONTROL_AE_REGIONS / CONTROL_AWB_REGIONS yang sesuai ke permintaan pengambilan.

Karena tidak semua perangkat mendukung AF/AE/AWB dan beberapa area, CameraX mengeksekusi FocusMeteringAction dengan upaya terbaik. CameraX menggunakan jumlah maksimum MeteringPoint yang didukung, sesuai urutan penambahan titik. Semua MeteringPoint ditambahkan setelah jumlah maksimum diabaikan. Misalnya, jika FocusMeteringAction dilengkapi dengan 3 MeteringPoint di platform yang hanya mendukung 2 MeteringPoint, hanya 2 MeteringPoint pertama yang akan digunakan. MeteringPoint terakhir akan diabaikan oleh CameraX.

Exposure Compensation

Exposure compensation berguna saat aplikasi perlu meningkatkan nilai eksposur (EV) di luar hasil output eksposur otomatis (AE). Nilai exposure compensation digabungkan dengan cara berikut untuk menentukan eksposur yang diperlukan untuk kondisi gambar saat ini:

Exposure = ExposureCompensationIndex * ExposureCompensationStep

CameraX menyediakan fungsi Camera.CameraControl.setExposureCompensationIndex() untuk menetapkan exposure compensation sebagai nilai indeks.

Nilai indeks positif membuat gambar lebih cerah, sedangkan nilai negatif meredupkan gambar. Aplikasi dapat mengkueri rentang yang didukung oleh CameraInfo.ExposureState.exposureCompensationRange() yang dijelaskan di bagian berikutnya. Jika nilainya didukung, ListenableFuture yang ditampilkan akan selesai saat nilai berhasil diaktifkan dalam permintaan pengambilan; jika indeks yang ditentukan berada di luar rentang yang didukung, setExposureCompensationIndex() akan menyebabkan ListenableFuture yang ditampilkan segera selesai dengan hasil yang gagal.

CameraX hanya menyimpan permintaan setExposureCompensationIndex() terbaru yang belum diproses, dan memanggil fungsi beberapa kali sebelum permintaan sebelumnya menyebabkan eksekusi dibatalkan.

Cuplikan berikut menetapkan indeks exposure compensation dan mendaftarkan callback saat permintaan perubahan eksposur telah dijalankan:

Kotlin

camera.cameraControl.setExposureCompensationIndex(exposureCompensationIndex)
   .addListener({
      // Get the current exposure compensation index, it might be
      // different from the asked value in case this request was
      // canceled by a newer setting request.
      val currentExposureIndex = camera.cameraInfo.exposureState.exposureCompensationIndex
      …
   }, mainExecutor)
  • Camera.CameraInfo.getExposureState() mengambil ExposureState saat ini, termasuk:

    • Kemampuan dukungan kontrol exposure compensation.
    • Indeks exposure compensation saat ini.
    • Rentang indeks exposure compensation.
    • Langkah exposure compensation yang digunakan dalam penghitungan nilai exposure compensation.

Misalnya, kode berikut menginisialisasi setelan untuk eksposur SeekBar dengan nilai ExposureState saat ini:

Kotlin

val exposureState = camera.cameraInfo.exposureState
binding.seekBar.apply {
   isEnabled = exposureState.isExposureCompensationSupported
   max = exposureState.exposureCompensationRange.upper
   min = exposureState.exposureCompensationRange.lower
   progress = exposureState.exposureCompensationIndex
}

Referensi lainnya

Untuk mempelajari CameraX lebih lanjut, lihat referensi tambahan berikut.

Codelab

  • Mulai Menggunakan CameraX
  • Contoh kode

  • Aplikasi contoh CameraX
  • Komunitas developer

    Grup Diskusi CameraX Android