Dalam tutorial ini, kita akan membahas cara mengontrol hardware kamera secara langsung menggunakan API framework.
Catatan: Halaman ini merujuk ke class Camera, yang sudah tidak digunakan lagi. Sebaiknya gunakan CameraX atau, untuk kasus penggunaan tertentu, gunakan Camera2. CameraX dan Camera2 mendukung Android 5.0 (API level 21) dan versi yang lebih baru.
Mengontrol kamera perangkat secara langsung memerlukan lebih banyak kode daripada meminta gambar atau video dari aplikasi kamera yang ada. Namun, jika Anda ingin membuat aplikasi kamera khusus atau sesuatu yang terintegrasi sepenuhnya di UI aplikasi, pelajaran ini akan menunjukkan caranya.
Lihat referensi terkait berikut ini:
Membuka Objek Kamera
Mendapatkan instance objek Camera
adalah langkah pertama dalam
proses mengontrol kamera secara langsung. Seperti yang dilakukan oleh aplikasi Kamera Android,
cara yang direkomendasikan untuk mengakses kamera adalah dengan membuka Camera
di thread
terpisah yang diluncurkan dari onCreate()
. Ini merupakan pendekatan yang bagus
karena prosesnya dapat memerlukan waktu agak lama dan dapat mengacaukan UI thread. Dalam implementasi yang lebih mendasar,
operasi membuka kamera dapat dialihkan ke metode onResume()
untuk memfasilitasi penggunaan ulang kode dan menyederhanakan
alur kontrol.
Memanggil Camera.open()
akan memunculkan
pengecualian jika kamera sudah digunakan oleh aplikasi lain, jadi kami menggabungkannya
dalam blok try
.
Kotlin
private fun safeCameraOpen(id: Int): Boolean { return try { releaseCameraAndPreview() mCamera = Camera.open(id) true } catch (e: Exception) { Log.e(getString(R.string.app_name), "failed to open Camera") e.printStackTrace() false } } private fun releaseCameraAndPreview() { preview?.setCamera(null) mCamera?.also { camera -> camera.release() mCamera = null } }
Java
private boolean safeCameraOpen(int id) { boolean qOpened = false; try { releaseCameraAndPreview(); camera = Camera.open(id); qOpened = (camera != null); } catch (Exception e) { Log.e(getString(R.string.app_name), "failed to open Camera"); e.printStackTrace(); } return qOpened; } private void releaseCameraAndPreview() { preview.setCamera(null); if (camera != null) { camera.release(); camera = null; } }
Sejak API level 9, framework kamera mendukung multi-kamera. Jika Anda menggunakan
API lama dan memanggil open()
tanpa argumen,
Anda akan mendapatkan kamera hadap belakang yang pertama.
Membuat Pratinjau Kamera
Proses pengambilan gambar biasanya mengharuskan pengguna untuk melihat pratinjau subjek sebelum mengklik
tombol shutter. Untuk keperluan tersebut, Anda dapat menggunakan SurfaceView
untuk menggambar pratinjau dari
objek yang ditangkap oleh sensor kamera.
Class Pratinjau
Untuk mulai menampilkan pratinjau, Anda memerlukan class pratinjau. Pratinjau
memerlukan penerapan antarmuka android.view.SurfaceHolder.Callback
, yang digunakan untuk meneruskan data
gambar dari hardware kamera ke aplikasi.
Kotlin
class Preview( context: Context, val surfaceView: SurfaceView = SurfaceView(context) ) : ViewGroup(context), SurfaceHolder.Callback { var mHolder: SurfaceHolder = surfaceView.holder.apply { addCallback(this@Preview) setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } ... }
Java
class Preview extends ViewGroup implements SurfaceHolder.Callback { SurfaceView surfaceView; SurfaceHolder holder; Preview(Context context) { super(context); surfaceView = new SurfaceView(context); addView(surfaceView); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. holder = surfaceView.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } ... }
Class pratinjau harus diteruskan ke objek Camera
sebelum
pratinjau gambar aktif dapat dimulai, seperti ditunjukkan dalam bagian di bawah.
Menetapkan dan Memulai Pratinjau
Instance kamera dan pratinjau terkaitnya harus dibuat sesuai urutan tertentu,
dengan objek kamera sebagai yang pertama. Dalam cuplikan kode di bawah,
proses inisialisasi kamera diringkas sedemikian rupa sehingga Camera.startPreview()
dipanggil oleh metode
setCamera()
setiap kali pengguna melakukan sesuatu untuk mengubah
kamera. Pratinjau juga harus dimulai ulang dalam metode callback surfaceChanged()
class pratinjau.
Kotlin
fun setCamera(camera: Camera?) { if (mCamera == camera) { return } stopPreviewAndFreeCamera() mCamera = camera mCamera?.apply { mSupportedPreviewSizes = parameters.supportedPreviewSizes requestLayout() try { setPreviewDisplay(holder) } catch (e: IOException) { e.printStackTrace() } // Important: Call startPreview() to start updating the preview // surface. Preview must be started before you can take a picture. startPreview() } }
Java
public void setCamera(Camera camera) { if (mCamera == camera) { return; } stopPreviewAndFreeCamera(); mCamera = camera; if (mCamera != null) { List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes(); supportedPreviewSizes = localSizes; requestLayout(); try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } // Important: Call startPreview() to start updating the preview // surface. Preview must be started before you can take a picture. mCamera.startPreview(); } }
Memodifikasi Setelan Kamera
Setelan kamera mengubah cara kamera mengambil gambar, dari tingkat zoom hingga exposure compensation. Contoh ini hanya mengubah ukuran pratinjau. Lihat kode sumber aplikasi Kamera untuk informasi yang lebih lengkap lagi.
Kotlin
override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { mCamera?.apply { // Now that the size is known, set up the camera parameters and begin // the preview. parameters?.also { params -> params.setPreviewSize(previewSize.width, previewSize.height) requestLayout() parameters = params } // Important: Call startPreview() to start updating the preview surface. // Preview must be started before you can take a picture. startPreview() } }
Java
@Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(previewSize.width, previewSize.height); requestLayout(); mCamera.setParameters(parameters); // Important: Call startPreview() to start updating the preview surface. // Preview must be started before you can take a picture. mCamera.startPreview(); }
Menetapkan Orientasi Pratinjau
Sebagian besar aplikasi kamera mengunci layar ke mode lanskap karena mode tersebut merupakan orientasi yang natural
untuk sensor kamera. Setelan ini tidak mencegah Anda mengambil foto dalam mode potret,
karena orientasi perangkat direkam dalam header EXIF. Metode setCameraDisplayOrientation()
memungkinkan Anda mengubah
tampilan pratinjau tanpa memengaruhi cara gambar direkam. Namun, pada Android sebelum
API level 14, Anda harus menghentikan pratinjau sebelum mengubah orientasi, lalu memulainya ulang.
Mengambil Gambar
Gunakan metode Camera.takePicture()
untuk mengambil gambar setelah pratinjau dimulai. Anda dapat membuat objek Camera.PictureCallback
dan Camera.ShutterCallback
lalu meneruskannya ke Camera.takePicture()
.
Jika ingin mengambil gambar secara kontinu, Anda dapat membuat Camera.PreviewCallback
yang menerapkan onPreviewFrame()
. Untuk
sesuatu di antaranya, Anda hanya dapat mengambil frame pratinjau yang dipilih, atau menyiapkan
tindakan tertunda untuk memanggil takePicture()
.
Memulai Ulang Pratinjau
Setelah gambar diambil, Anda harus memulai ulang pratinjau agar pengguna dapat mengambil gambar lain. Dalam contoh ini, proses mulai ulang dilakukan dengan meng-overload tombol shutter.
Kotlin
fun onClick(v: View) { previewState = if (previewState == K_STATE_FROZEN) { camera?.startPreview() K_STATE_PREVIEW } else { camera?.takePicture(null, rawCallback, null) K_STATE_BUSY } shutterBtnConfig() }
Java
@Override public void onClick(View v) { switch(previewState) { case K_STATE_FROZEN: camera.startPreview(); previewState = K_STATE_PREVIEW; break; default: camera.takePicture( null, rawCallback, null); previewState = K_STATE_BUSY; } // switch shutterBtnConfig(); }
Menghentikan Pratinjau dan Melepas Kamera
Setelah aplikasi Anda selesai menggunakan kamera, saatnya untuk membersihkan. Secara
khusus, Anda harus melepas objek Camera
; jika tidak, Anda berisiko menimbulkan error pada aplikasi
lain, termasuk instance baru aplikasi Anda sendiri.
Kapan sebaiknya Anda menghentikan pratinjau dan melepas kamera? Menghilangnya
permukaan pratinjau adalah indikasi yang tepat bahwa sudah saatnya untuk menghentikan
pratinjau dan melepas kamera, seperti yang ditunjukkan dalam metode ini dari class Preview
.
Kotlin
override fun surfaceDestroyed(holder: SurfaceHolder) { // Surface will be destroyed when we return, so stop the preview. // Call stopPreview() to stop updating the preview surface. mCamera?.stopPreview() } /** * When this function returns, mCamera will be null. */ private fun stopPreviewAndFreeCamera() { mCamera?.apply { // Call stopPreview() to stop updating the preview surface. stopPreview() // Important: Call release() to release the camera for use by other // applications. Applications should release the camera immediately // during onPause() and re-open() it during onResume()). release() mCamera = null } }
Java
@Override public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. if (mCamera != null) { // Call stopPreview() to stop updating the preview surface. mCamera.stopPreview(); } } /** * When this function returns, mCamera will be null. */ private void stopPreviewAndFreeCamera() { if (mCamera != null) { // Call stopPreview() to stop updating the preview surface. mCamera.stopPreview(); // Important: Call release() to release the camera for use by other // applications. Applications should release the camera immediately // during onPause() and re-open() it during onResume()). mCamera.release(); mCamera = null; } }
Seperti disinggung di atas, prosedur ini juga merupakan bagian dari metode setCamera()
, jadi inisialisasi kamera selalu dimulai dengan menghentikan
pratinjau.