Halaman ini mencakup arsitektur CameraX, termasuk strukturnya, cara menggunakan API ini, cara menggunakan siklus proses, dan cara menggabungkan kasus penggunaan.
Struktur CameraX
Anda dapat menggunakan CameraX untuk berinteraksi dengan kamera perangkat melalui abstraksi yang disebut kasus penggunaan. Kasus penggunaan berikut tersedia:
- Pratinjau: menerima platform untuk menampilkan pratinjau, seperti
PreviewView
. - Analisis gambar: menyediakan buffering yang dapat diakses CPU untuk analisis, misalnya untuk machine learning.
- Pengambilan gambar: mengambil dan menyimpan foto.
- Perekaman video: merekam video dan audio dengan
VideoCapture
.
Kasus penggunaan dapat digabungkan dan aktif serentak. Misalnya, sebuah aplikasi dapat mengizinkan pengguna untuk menampilkan gambar yang dilihat kamera menggunakan kasus penggunaan pratinjau, memiliki kasus penggunaan analisis gambar yang menentukan apakah orang-orang dalam foto tersenyum, dan mencakup kasus penggunaan pengambilan gambar untuk mengambil gambar saat orang-orang tersebut tersenyum.
Model API
Untuk menggunakan library ini, Anda harus menentukan hal berikut:
- Kasus penggunaan yang diinginkan dengan opsi konfigurasi.
- Tindakan yang dilakukan terhadap data output dengan menambahkan pemroses.
- Alur yang diinginkan, seperti kapan mengaktifkan kamera dan kapan menghasilkan data, dengan mengikatkan kasus penggunaan ke Siklus Proses Arsitektur Android.
Ada 2 cara untuk menulis aplikasi CameraX:
CameraController
(cocok jika
Anda menginginkan cara paling sederhana untuk menggunakan CameraX) atau
CameraProvider
(cocok jika Anda
memerlukan fleksibilitas lebih).
CameraController
CameraController
menyediakan sebagian besar fungsi inti CameraX dalam satu
class. Cara ini memerlukan sedikit kode penyiapan, dan secara otomatis menangani inisialisasi
kamera, pengelolaan kasus penggunaan, rotasi target, ketuk untuk fokus,
cubit untuk zoom, dan lainnya. Class konkret yang memperluas CameraController
adalah
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
default untuk CameraController
adalah Preview
, ImageCapture
, dan
ImageAnalysis
. Untuk menonaktifkan ImageCapture
atau ImageAnalysis
, atau mengaktifkan
VideoCapture
, gunakan
metode
setEnabledUseCases()
.
Untuk penggunaan CameraController
lainnya, lihat
contoh pemindai Kode QR
atau
video dasar-dasar CameraController
.
CameraProvider
CameraProvider
masih mudah digunakan, tetapi karena developer aplikasi menangani
lebih banyak penyiapan, maka ada lebih banyak peluang untuk menyesuaikan konfigurasi,
seperti mengaktifkan rotasi gambar output atau menyetel format gambar output di
ImageAnalysis
. Anda juga dapat menggunakan Surface
kustom untuk pratinjau kamera agar
lebih fleksibel, sedangkan dengan CameraController, Anda harus menggunakan
PreviewView
. Menggunakan kode Surface
yang ada dapat bermanfaat jika sudah menjadi input untuk bagian lain aplikasi Anda.
Anda mengonfigurasi kasus penggunaan menggunakan metode set()
dan menyelesaikannya dengan metode build()
. Setiap objek kasus penggunaan menyediakan sekumpulan API khusus kasus penggunaan. Misalnya,
kasus penggunaan pengambilan gambar menyediakan panggilan metode takePicture()
.
Sebagai ganti melakukan panggilan metode mulai dan berhenti spesifik dalam
onResume()
dan onPause()
, aplikasi menentukan siklus proses untuk dikaitkan dengan
kamera, menggunakan
cameraProvider.bindToLifecycle()
.
Siklus proses tersebut selanjutnya memberi tahu CameraX kapan harus mengonfigurasi sesi pengambilan gambar kamera
dan memastikan kamera berubah ke status yang tepat untuk menyesuaikan dengan peralihan siklus proses.
Untuk mengetahui langkah-langkah implementasi setiap kasus penggunaan, lihat Mengimplementasikan pratinjau, Menganalisis gambar, Pengambilan gambar, dan Perekaman video
Kasus penggunaan pratinjau berinteraksi dengan
Surface
untuk tampilan. Aplikasi
membuat kasus penggunaan ini dengan opsi konfigurasi menggunakan kode berikut:
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();
Untuk kode contoh lainnya, lihat aplikasi contoh CameraX resmi.
Siklus proses CameraX
CameraX mengamati siklus proses untuk menentukan kapan harus membuka kamera, memulai sesi pengambilan gambar, serta berhenti dan menutup kamera. API kasus penggunaan menyediakan panggilan metode dan callback untuk memantau progres.
Sebagaimana dijelaskan dalam Menggabungkan kasus penggunaan, Anda dapat mengikat beberapa campuran kasus penggunaan menjadi satu siklus proses. Jika aplikasi Anda perlu mendukung kasus penggunaan yang tidak dapat digabungkan, Anda dapat melakukan salah satu langkah berikut:
- Mengelompokkan kasus penggunaan yang kompatibel menjadi beberapa fragmen, lalu beralih antarfragmen
- Membuat komponen siklus proses kustom dan menggunakannya untuk mengontrol siklus proses kamera secara manual
Jika Anda memisahkan tampilan dan pemilik Siklus Proses kasus penggunaan kamera (misalnya,
jika menggunakan siklus proses kustom atau mempertahankan
fragmen), maka Anda
harus memastikan bahwa semua kasus penggunaan tidak terikat dengan CameraX menggunakan
ProcessCameraProvider.unbindAll()
atau dengan memisahkan setiap kasus penggunaan satu per satu. Atau, saat Anda mengikatkan kasus penggunaan
ke Siklus Proses, Anda dapat mengizinkan CameraX
mengelola pembukaan dan penutupan sesi pengambilan gambar, serta pemisahan kasus penggunaan.
Jika semua fungsi kamera sesuai dengan siklus proses komponen tunggal
berbasis siklus proses seperti
AppCompatActivity
atau
fragmen AppCompat
, penggunaan siklus proses komponen tersebut saat mengikat
semua kasus penggunaan yang diinginkan akan memastikan bahwa fungsi kamera siap
saat komponen berbasis siklus proses aktif dan dibuang dengan aman sehingga
tidak memakai resource apa pun.
LifecycleOwner kustom
Untuk kasus lanjutan, Anda dapat membuat
LifecycleOwner
kustom untuk memungkinkan
aplikasi mengontrol siklus proses sesi CameraX secara eksplisit, bukan mengikatnya ke
LifecycleOwner
Android standar.
Contoh kode berikut menunjukkan cara membuat LifecycleOwner kustom sederhana:
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; } }
Dengan menggunakan LifecycleOwner
ini, aplikasi Anda dapat melakukan transisi status pada poin yang diinginkan
dalam kodenya. Untuk informasi selengkapnya tentang cara mengimplementasikan fungsi ini pada aplikasi,
lihat Mengimplementasikan
LifecycleOwner kustom.
Kasus penggunaan serentak
Kasus penggunaan dapat berjalan secara serentak. Meskipun kasus penggunaan dapat secara berurutan terikat ke
siklus proses, sebaiknya ikatkan semua kasus penggunaan dengan satu panggilan ke
CameraProcessProvider.bindToLifecycle()
. Untuk informasi selengkapnya tentang praktik terbaik
perubahan konfigurasi, lihat Menangani perubahan
konfigurasi.
Dalam contoh kode berikut, aplikasi menentukan dua kasus penggunaan yang akan dibuat dan dijalankan secara bersamaan. Aplikasi juga menentukan siklus proses yang digunakan untuk kedua kasus penggunaan, sehingga keduanya dimulai dan dihentikan sesuai dengan siklus prosesnya.
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)); }
Kombinasi konfigurasi berikut dijamin akan didukung (saat salah satu dari Pratinjau dan Perekaman Video diperlukan, tetapi tidak didukung saat keduanya diperlukan secara bersamaan):
Pratinjau atau Perekaman Video | Pengambilan gambar | Analisis | Deskripsi |
---|---|---|---|
Menyediakan pratinjau kepada pengguna atau merekam video, mengambil foto, dan menganalisis aliran gambar. | |||
Mengambil foto dan menganalisis aliran gambar. | |||
Menyediakan pratinjau kepada pengguna atau merekam video, dan mengambil foto. | |||
Menyediakan pratinjau kepada pengguna atau merekam video, dan menganalisis aliran gambar. |
Jika Pratinjau dan Perekaman Video diperlukan, kombinasi kasus penggunaan berikut dapat didukung secara bersyarat:
Pratinjau | Perekaman video | Pengambilan gambar | Analisis | Persyaratan khusus |
---|---|---|---|---|
Dijamin untuk semua kamera | ||||
Perangkat kamera LIMITED (atau yang lebih baik). | ||||
Perangkat kamera LEVEL_3 (atau yang lebih baik). |
Selain itu,
- Setiap kasus penggunaan dapat berfungsi sendiri. Misalnya, aplikasi dapat merekam video tanpa menggunakan pratinjau.
- Jika ekstensi diaktifkan, hanya kombinasi
ImageCapture
danPreview
yang dijamin akan berfungsi. Bergantung pada implementasi OEM, Anda juga mungkin tidak dapat menambahkanImageAnalysis
; ekstensi tidak dapat diaktifkan untuk kasus penggunaanVideoCapture
. Lihat Dokumen referensi ekstensi untuk mengetahui detailnya. - Bergantung pada kemampuan kamera, beberapa kamera mungkin mendukung kombinasi tersebut dalam mode resolusi rendah, tetapi tidak dapat mendukung kombinasi yang sama pada beberapa resolusi yang lebih tinggi.
Level hardware yang didukung
dapat diambil dari Camera2CameraInfo
. Misalnya, kode berikut
memeriksa apakah kamera belakang default adalah perangkat 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; }
Izin
Aplikasi Anda membutuhkan
izin CAMERA
. Untuk
menyimpan gambar ke file, tindakan ini juga memerlukan izin
WRITE_EXTERNAL_STORAGE
,
kecuali pada perangkat yang menjalankan Android 10 atau yang lebih baru.
Untuk informasi selengkapnya tentang cara mengonfigurasi izin untuk aplikasi Anda, baca Meminta Izin Aplikasi.
Persyaratan
CameraX memiliki persyaratan versi minimum berikut:
- Android API level 21
- Komponen Arsitektur Android 1.1.1
Untuk aktivitas berbasis siklus proses, gunakan
FragmentActivity
atau
AppCompatActivity
.
Mendeklarasikan dependensi
Untuk menambahkan dependensi pada CameraX, Anda harus menambahkan repositori Maven Google ke project Anda.
Buka file settings.gradle
untuk project Anda dan tambahkan repositori google()
seperti yang ditunjukkan berikut:
Groovy
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Tambahkan item berikut ke bagian akhir blok Android:
Groovy
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" } }
Tambahkan kode berikut ke file build.gradle
setiap modul untuk aplikasi:
Groovy
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}") }
Untuk informasi selengkapnya tentang cara mengonfigurasi aplikasi agar sesuai dengan persyaratan ini, lihat Mendeklarasikan dependensi.
Interoperabilitas CameraX dengan Camera2
CameraX dibuat di Camera2, dan CameraX menampilkan cara untuk membaca dan bahkan menulis properti dalam implementasi Camera2. Untuk mengetahui detail selengkapnya, lihat paket Interop.
Untuk informasi selengkapnya tentang cara CameraX mengonfigurasi properti Camera2, gunakan
Camera2CameraInfo
untuk membaca CameraCharacteristics
yang mendasarinya. Anda juga dapat memilih untuk menulis properti Camera2 yang mendasarinya
di salah satu dari dua jalur berikut:
Gunakan
Camera2CameraControl
, yang memungkinkan Anda menetapkan properti padaCaptureRequest
yang mendasarinya, seperti mode fokus otomatis.Perluas
UseCase
CameraX denganCamera2Interop.Extender
. Hal ini memungkinkan Anda menetapkan properti pada CaptureRequest, seperti halnyaCamera2CameraControl
. Tindakan ini juga memberi Anda beberapa kontrol tambahan, seperti menetapkan kasus penggunaan streaming guna mengoptimalkan kamera untuk skenario penggunaan Anda. Untuk mengetahui informasi selengkapnya, lihat Menggunakan Kasus Penggunaan Streaming untuk performa yang lebih baik.
Contoh kode berikut menggunakan kasus penggunaan streaming untuk mengoptimalkan panggilan video.
Gunakan Camera2CameraInfo
untuk mengetahui ketersediaan kasus penggunaan streaming panggilan video. Kemudian, gunakan
Camera2Interop.Extender
untuk menetapkan kasus penggunaan streaming yang mendasarinya.
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)
Referensi tambahan
Untuk mempelajari CameraX lebih lanjut, lihat referensi tambahan berikut.
Codelab
Contoh kode