API kamera

Framework Android mencakup dukungan untuk berbagai kamera dan fitur kamera yang tersedia di perangkat, yang memungkinkan Anda untuk mengambil gambar dan video di aplikasi. Dokumen ini membahas pendekatan cepat dan sederhana untuk pengambilan gambar dan video, serta menguraikan pendekatan lanjutan untuk menciptakan pengalaman kamera kustom bagi pengguna Anda.

Catatan: Halaman ini menjelaskan class Camera, yang sudah tidak digunakan lagi. Sebaiknya gunakan library Jetpack CameraX atau, untuk kasus penggunaan tertentu, class camera2. CameraX dan Camera2 berfungsi di Android 5.0 (API level 21) dan yang lebih tinggi.

Lihat referensi terkait berikut ini:

Pertimbangan

Sebelum mengaktifkan aplikasi untuk menggunakan kamera pada perangkat Android, Anda harus mempertimbangkan beberapa pertanyaan tentang bagaimana cara aplikasi Anda menggunakan fitur hardware ini.

  • Persyaratan Kamera - Apakah penggunaan kamera begitu penting untuk aplikasi sehingga Anda tidak ingin aplikasi diinstal pada perangkat yang tidak memiliki kamera? Jika demikian, Anda harus mendeklarasikan persyaratan kamera dalam manifes Anda.
  • Gambar Cepat atau Kamera Kustom - Bagaimana aplikasi Anda menggunakan kamera? Apakah Anda hanya tertarik untuk mengambil gambar cepat atau klip video, atau apakah aplikasi Anda akan menyediakan cara baru untuk menggunakan kamera? Untuk mendapatkan klip atau jepretan cepat, pertimbangkan Menggunakan Aplikasi Kamera yang Ada. Untuk mengembangkan fitur kamera kustom, lihat bagian Membuat Aplikasi Kamera.
  • Persyaratan Layanan Latar Depan - Kapan aplikasi Anda berinteraksi dengan kamera? Di Android 9 (API level 28) dan yang lebih baru, aplikasi yang berjalan di latar belakang tidak dapat mengakses kamera. Karena itu, Anda harus menggunakan kamera baik saat aplikasi berada di latar depan maupun sebagai bagian dari layanan latar depan.
  • Penyimpanan - Apakah gambar atau video yang dihasilkan aplikasi Anda ditujukan hanya untuk dapat dilihat oleh aplikasi Anda, atau dibagikan agar aplikasi lain seperti Galeri atau media dan aplikasi sosial lainnya dapat menggunakannya? Apakah Anda ingin gambar dan video tersedia bahkan jika aplikasi Anda di-uninstal? Lihat bagian Menyimpan File Media untuk mengetahui cara menerapkan opsi ini.

Dasar-dasarnya

Framework Android mendukung pengambilan gambar dan video melalui API android.hardware.camera2 atau kamera Intent. Berikut adalah class yang relevan:

android.hardware.camera2
Paket ini adalah API utama untuk mengontrol kamera perangkat. Paket ini dapat digunakan untuk mengambil gambar atau video saat Anda membuat aplikasi kamera.
Camera
Class ini adalah API lebih lama yang tidak digunakan lagi untuk mengontrol kamera perangkat.
SurfaceView
Class ini digunakan untuk menyajikan pratinjau kamera langsung kepada pengguna.
MediaRecorder
Class ini digunakan untuk merekam video dari kamera.
Intent
Jenis tindakan intent MediaStore.ACTION_IMAGE_CAPTURE atau MediaStore.ACTION_VIDEO_CAPTURE dapat digunakan untuk mengambil gambar atau video tanpa langsung menggunakan objek Camera.

Deklarasi manifes

Sebelum memulai pengembangan pada aplikasi dengan Camera API, pastikan manifes Anda memiliki deklarasi yang sesuai untuk mengizinkan penggunaan hardware kamera dan fitur terkait lainnya.

  • Izin Kamera - Aplikasi Anda harus meminta izin untuk menggunakan kamera perangkat.
    <uses-permission android:name="android.permission.CAMERA" />

    Catatan: Jika Anda menggunakan kamera dengan mengaktifkan aplikasi kamera yang ada, aplikasi Anda tidak perlu meminta izin ini.

  • Fitur Kamera - Aplikasi Anda juga harus mendeklarasikan penggunaan fitur kamera, misalnya:
    <uses-feature android:name="android.hardware.camera" />

    Untuk daftar fitur kamera, lihat manifes Referensi Fitur.

    Menambahkan fitur kamera ke manifes Anda menyebabkan Google Play mencegah aplikasi Anda diinstal ke perangkat yang tidak menyertakan kamera atau tidak mendukung fitur kamera yang Anda tentukan. Untuk informasi selengkapnya tentang penggunaan pemfilteran berbasis fitur dengan Google Play, lihat Pemfilteran Berbasis Fitur dan Google Play.

    Jika aplikasi Anda dapat menggunakan kamera atau fitur kamera untuk pengoperasian yang benar, tetapi tidak mengharuskannya, Anda harus menentukan hal ini dalam manifes dengan memasukkan atribut android:required, lalu menetapkannya ke false:

    <uses-feature android:name="android.hardware.camera" android:required="false" />
  • Izin Penyimpanan - Aplikasi Anda dapat menyimpan gambar atau video ke penyimpanan eksternal perangkat (Kartu SD) jika menargetkan Android 10 (API level 29) atau lebih rendah dan menentukan hal berikut dalam manifes.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • Izin Perekaman Audio - Untuk merekam audio dengan rekaman video, aplikasi Anda harus meminta izin rekaman audio.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
  • Izin Lokasi - Jika aplikasi Anda menandai gambar dengan informasi lokasi GPS, Anda harus meminta izin ACCESS_FINE_LOCATION. Ingat bahwa, jika aplikasi Anda menargetkan Android 5.0 (API level 21) atau lebih tinggi, Anda juga perlu mendeklarasikan bahwa aplikasi tersebut menggunakan GPS perangkat:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
    <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
    <uses-feature android:name="android.hardware.location.gps" />

    Untuk informasi selengkapnya tentang cara mendapatkan lokasi pengguna, lihat Strategi Lokasi.

Menggunakan aplikasi kamera yang ada

Cara cepat untuk mengaktifkan pengambilan gambar atau video di aplikasi Anda tanpa banyak kode tambahan adalah dengan menggunakan Intent untuk menjalankan aplikasi kamera Android yang ada. Detailnya dijelaskan dalam tutorial pelatihan Mengambil Foto Secara Sederhana dan Merekam Video Secara Sederhana.

Membuat aplikasi kamera

Beberapa developer mungkin memerlukan antarmuka pengguna kamera yang disesuaikan dengan tampilan aplikasi mereka atau menyediakan fitur khusus. Menulis kode pengambilan gambar sendiri dapat memberikan pengalaman yang lebih menarik bagi pengguna.

Catatan: Panduan berikut ini untuk Camera API lebih lama yang tidak digunakan lagi. Untuk aplikasi kamera baru atau lanjutan, android.hardware.camera2 API yang lebih baru direkomendasikan.

Langkah umum untuk membuat antarmuka kamera kustom bagi aplikasi Anda adalah sebagai berikut:

  • Mendeteksi dan Mengakses Kamera - Buat kode untuk meminta akses dan memeriksa keberadaan kamera.
  • Membuat Class Pratinjau - Buat class pratinjau kamera yang memperluas SurfaceView dan mengimplementasikan antarmuka SurfaceHolder. Class ini mempratinjau gambar langsung dari kamera.
  • Membuat Tata Letak Pratinjau - Setelah memiliki class pratinjau kamera, buat tata letak tampilan yang menggabungkan pratinjau dan kontrol antarmuka pengguna yang Anda inginkan.
  • Menyiapkan Pemroses untuk Pengambilan - Hubungkan pemroses untuk kontrol antarmuka guna memulai pengambilan gambar atau video sebagai respons terhadap tindakan pengguna, seperti menekan tombol.
  • Mengambil dan Menyimpan File - Siapkan kode untuk mengambil gambar atau video dan menyimpan hasilnya.
  • Merilis Kamera - Setelah menggunakan kamera, aplikasi Anda harus merilisnya dengan benar untuk digunakan oleh aplikasi lain.

Hardware kamera adalah sumber daya bersama yang harus dikelola dengan hati-hati agar aplikasi Anda tidak bertabrakan dengan aplikasi lain yang mungkin juga ingin menggunakannya. Bagian berikut membahas cara mendeteksi hardware kamera, cara meminta akses ke kamera, cara mengambil gambar atau video, dan cara merilis kamera setelah aplikasi Anda selesai menggunakannya.

Perhatian: Ingatlah untuk merilis objek Camera dengan memanggil Camera.release() setelah aplikasi Anda selesai menggunakannya. Jika aplikasi Anda tidak merilis kamera dengan benar, semua upaya berikutnya untuk mengakses kamera, termasuk yang dilakukan oleh aplikasi Anda sendiri, akan gagal dan dapat menyebabkan aplikasi Anda atau lainnya dinonaktifkan.

Mendeteksi hardware kamera

Jika aplikasi Anda secara khusus tidak membutuhkan kamera menggunakan deklarasi manifes, Anda harus memeriksa untuk melihat apakah kamera tersedia saat runtime. Untuk melakukan pemeriksaan ini, gunakan metode PackageManager.hasSystemFeature(), seperti yang ditunjukkan pada contoh kode di bawah ini:

Kotlin

/** Check if this device has a camera */
private fun checkCameraHardware(context: Context): Boolean {
    if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        // this device has a camera
        return true
    } else {
        // no camera on this device
        return false
    }
}

Java

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

Perangkat Android dapat memiliki beberapa kamera, misalnya kamera belakang untuk fotografi dan kamera depan untuk panggilan video. Android 2.3 (API Level 9) dan yang lebih baru memungkinkan Anda memeriksa jumlah kamera yang tersedia di perangkat menggunakan metode Camera.getNumberOfCameras().

Mengakses kamera

Setelah mengetahui bahwa perangkat yang menjalankan aplikasi Anda memiliki kamera, Anda harus meminta untuk mengaksesnya dengan mendapatkan instance Camera (kecuali jika Anda menggunakan intent untuk mengakses kamera).

Untuk mengakses kamera utama, gunakan metode Camera.open() dan pastikan untuk menangkap pengecualian apa pun, seperti yang ditunjukkan pada kode di bawah ini:

Kotlin

/** A safe way to get an instance of the Camera object. */
fun getCameraInstance(): Camera? {
    return try {
        Camera.open() // attempt to get a Camera instance
    } catch (e: Exception) {
        // Camera is not available (in use or does not exist)
        null // returns null if camera is unavailable
    }
}

Java

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

Perhatian: Selalu periksa pengecualian saat menggunakan Camera.open(). Gagal memeriksa pengecualian jika kamera sedang digunakan atau tidak ada akan menyebabkan aplikasi Anda dinonaktifkan oleh sistem.

Pada perangkat yang menjalankan Android 2.3 (API Level 9) atau lebih tinggi, Anda dapat mengakses kamera tertentu menggunakan Camera.open(int). Contoh kode di atas akan mengakses kamera belakang terlebih dahulu pada perangkat dengan lebih dari satu kamera.

Memeriksa fitur kamera

Setelah mendapatkan akses ke kamera, Anda dapat memperoleh informasi selengkapnya tentang kemampuannya menggunakan metode Camera.getParameters() dan memeriksa objek Camera.Parameters yang ditampilkan untuk kemampuan yang didukung. Saat menggunakan API Level 9 atau yang lebih tinggi, gunakan Camera.getCameraInfo() untuk menentukan apakah kamera ada di bagian depan atau belakang perangkat, dan orientasi gambarnya.

Membuat class pratinjau

Agar pengguna dapat mengambil gambar atau video secara efektif, mereka harus dapat melihat apa yang dilihat kamera perangkat. Class pratinjau kamera adalah SurfaceView yang dapat menampilkan data gambar langsung yang berasal dari kamera, sehingga pengguna dapat membingkai dan mengambil gambar atau video.

Contoh kode berikut menunjukkan cara membuat class pratinjau kamera dasar yang dapat dimasukkan dalam tata letak View. Class ini mengimplementasikan SurfaceHolder.Callback untuk mengambil peristiwa callback guna membuat dan menutup tampilan, yang diperlukan untuk menetapkan input pratinjau kamera.

Kotlin

/** A basic Camera preview class */
class CameraPreview(
        context: Context,
        private val mCamera: Camera
) : SurfaceView(context), SurfaceHolder.Callback {

    private val mHolder: SurfaceHolder = holder.apply {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        addCallback(this@CameraPreview)
        // deprecated setting, but required on Android versions prior to 3.0
        setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        mCamera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: IOException) {
                Log.d(TAG, "Error setting camera preview: ${e.message}")
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.surface == null) {
            // preview surface does not exist
            return
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview()
        } catch (e: Exception) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        mCamera.apply {
            try {
                setPreviewDisplay(mHolder)
                startPreview()
            } catch (e: Exception) {
                Log.d(TAG, "Error starting camera preview: ${e.message}")
            }
        }
    }
}

Java

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

Jika ingin menyetel ukuran tertentu untuk pratinjau kamera Anda, setel ini dalam metode surfaceChanged() seperti yang disebutkan dalam komentar di atas. Saat menyetel ukuran pratinjau, Anda harus menggunakan nilai dari getSupportedPreviewSizes(). Jangan setel nilai arbitrer dalam metode setPreviewSize().

Catatan: Dengan diperkenalkannya fitur Multi-Aplikasi di Android 7.0 (API level 24) dan yang lebih tinggi, Anda tidak dapat lagi mengasumsikan rasio lebar tinggi pratinjau sama seperti aktivitas Anda bahkan setelah memanggil setDisplayOrientation(). Bergantung pada ukuran jendela dan rasio lebar tinggi, Anda mungkin harus memasukkan pratinjau kamera lebar ke dalam tata letak berorientasi potret, atau sebaliknya, menggunakan tata letak tampilan lebar.

Menempatkan pratinjau dalam tata letak

Class pratinjau kamera, seperti contoh yang ditunjukkan pada bagian sebelumnya, harus ditempatkan dalam tata letak suatu aktivitas bersama dengan kontrol antarmuka pengguna lain untuk mengambil gambar atau video. Bagian ini menunjukkan kepada Anda cara membuat tata letak dan aktivitas dasar untuk pratinjau.

Kode tata letak berikut memberikan tampilan yang sangat mendasar yang dapat digunakan untuk menampilkan pratinjau kamera. Dalam contoh ini, elemen FrameLayout dimaksudkan sebagai container untuk class pratinjau kamera. Jenis tata letak ini digunakan sehingga informasi gambar tambahan atau kontrol dapat ditempatkan pada gambar pratinjau kamera langsung.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    />

  <Button
    android:id="@+id/button_capture"
    android:text="Capture"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    />
</LinearLayout>

Pada sebagian besar perangkat, orientasi default pratinjau kamera adalah lanskap. Tata letak contoh ini menentukan tata letak horizontal (lanskap), dan kode di bawah ini memperbaiki orientasi aplikasi ke lanskap. Untuk mempermudah dalam merender pratinjau kamera, Anda harus mengubah orientasi aktivitas pratinjau aplikasi Anda menjadi lanskap dengan menambahkan berikut ini ke manifes Anda.

<activity android:name=".CameraActivity"
          android:label="@string/app_name"

          android:screenOrientation="landscape">
          <!-- configure this activity to use landscape orientation -->

          <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Catatan: Pratinjau kamera tidak harus dalam mode lanskap. Mulai di Android 2.2 (API Level 8), Anda dapat menggunakan metode setDisplayOrientation() untuk menyetel rotasi gambar pratinjau. Untuk mengubah orientasi pratinjau saat pengguna mengorientasikan ulang ponsel, dalam metode surfaceChanged() dari class pratinjau Anda, pertama-tama hentikan pratinjau dengan Camera.stopPreview(), ubah orientasi, lalu mulai pratinjau lagi dengan Camera.startPreview().

Pada aktivitas untuk tampilan kamera, tambahkan class pratinjau Anda ke elemen FrameLayout yang ditunjukkan pada contoh di atas. Aktivitas kamera Anda juga harus memastikan bahwa ia merilis kamera ketika dijeda atau dimatikan. Contoh berikut menunjukkan cara memodifikasi aktivitas kamera untuk melampirkan class pratinjau yang ditunjukkan dalam Membuat class pratinjau.

Kotlin

class CameraActivity : Activity() {

    private var mCamera: Camera? = null
    private var mPreview: CameraPreview? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Create an instance of Camera
        mCamera = getCameraInstance()

        mPreview = mCamera?.let {
            // Create our Preview view
            CameraPreview(this, it)
        }

        // Set the Preview view as the content of our activity.
        mPreview?.also {
            val preview: FrameLayout = findViewById(R.id.camera_preview)
            preview.addView(it)
        }
    }
}

Java

public class CameraActivity extends Activity {

    private Camera mCamera;
    private CameraPreview mPreview;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create an instance of Camera
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);
    }
}

Catatan: Metode getCameraInstance() pada contoh di atas merujuk pada metode contoh yang ditampilkan di Mengakses kamera.

Mengambil foto

Setelah membuat class pratinjau dan tata letak tampilan untuk menampilkannya, Anda siap untuk mulai mengambil gambar dengan aplikasi Anda. Dalam kode aplikasi Anda, Anda harus menyiapkan pemroses untuk kontrol antarmuka pengguna demi merespons tindakan pengguna dengan mengambil gambar.

Untuk mengambil gambar, gunakan metode Camera.takePicture(). Metode ini mengambil tiga parameter yang menerima data dari kamera. Untuk menerima data dalam format JPEG, Anda harus mengimplementasikan antarmuka Camera.PictureCallback untuk menerima data gambar dan menulisnya ke file. Kode berikut menunjukkan implementasi dasar antarmuka Camera.PictureCallback untuk menyimpan gambar yang diterima dari kamera.

Kotlin

private val mPicture = Camera.PictureCallback { data, _ ->
    val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run {
        Log.d(TAG, ("Error creating media file, check storage permissions"))
        return@PictureCallback
    }

    try {
        val fos = FileOutputStream(pictureFile)
        fos.write(data)
        fos.close()
    } catch (e: FileNotFoundException) {
        Log.d(TAG, "File not found: ${e.message}")
    } catch (e: IOException) {
        Log.d(TAG, "Error accessing file: ${e.message}")
    }
}

Java

private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d(TAG, "Error creating media file, check storage permissions");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};

Pemicu mengambil gambar dengan memanggil metode Camera.takePicture(). Kode contoh berikut menunjukkan cara memanggil metode ini dari tombol View.OnClickListener.

Kotlin

val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    // get an image from the camera
    mCamera?.takePicture(null, null, picture)
}

Java

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // get an image from the camera
            mCamera.takePicture(null, null, picture);
        }
    }
);

Catatan: Anggota mPicture pada contoh berikut merujuk pada contoh kode di atas.

Perhatian: Ingatlah untuk merilis objek Camera dengan memanggil Camera.release() setelah aplikasi Anda selesai menggunakannya. Untuk informasi tentang cara merilis kamera, lihat Merilis kamera.

Mengambil video

Pengambilan video menggunakan framework Android membutuhkan pengelolaan objek Camera yang cermat dan koordinasi dengan class MediaRecorder. Saat merekam video dengan Camera, Anda harus mengatur panggilan Camera.lock() dan Camera.unlock() untuk mengizinkan akses MediaRecorder ke hardware kamera, selain panggilan Camera.open() dan Camera.release().

Catatan: Mulai dari Android 4.0 (API level 14), panggilan Camera.lock() dan Camera.unlock() dikelola untuk Anda secara otomatis.

Tidak seperti mengambil gambar dengan kamera perangkat, merekam video membutuhkan urutan panggilan yang sangat khusus. Anda harus mengikuti urutan eksekusi tertentu agar berhasil mempersiapkan dan mengambil video dengan aplikasi Anda, seperti yang dijelaskan di bawah ini.

  1. Membuka Kamera - Gunakan Camera.open() untuk mendapatkan instance objek kamera.
  2. Menghubungkan Pratinjau - Siapkan pratinjau gambar kamera langsung dengan menghubungkan SurfaceView ke kamera menggunakan Camera.setPreviewDisplay().
  3. Memulai Pratinjau - Panggil Camera.startPreview() untuk mulai menampilkan gambar kamera langsung.
  4. Memulai Rekaman Video - Langkah-langkah berikut harus diselesaikan agar berhasil merekam video:
    1. Membuka Kunci Kamera - Buka kunci kamera untuk digunakan oleh MediaRecorder dengan memanggil Camera.unlock().
    2. Mengonfigurasi MediaRecorder - Panggil metode MediaRecorder berikut dalam urutan ini. Untuk informasi selengkapnya, lihat dokumentasi referensi MediaRecorder.
      1. setCamera() - Setel kamera yang akan digunakan untuk pengambilan video, gunakan instance Camera aplikasi Anda saat ini.
      2. setAudioSource() - Setel sumber audio, gunakan MediaRecorder.AudioSource.CAMCORDER.
      3. setVideoSource() - Setel sumber video, gunakan MediaRecorder.VideoSource.CAMERA.
      4. Setel encoding dan format output video. Untuk Android 2.2 (API Level 8) dan lebih tinggi, gunakan metode MediaRecorder.setProfile, dan dapatkan instance profil menggunakan CamcorderProfile.get(). Untuk versi Android sebelum 2.2, Anda harus menyetel format output video dan parameter encoding:
        1. setOutputFormat() - Setel format output, tentukan setelan default atau MediaRecorder.OutputFormat.MPEG_4.
        2. setAudioEncoder() - Setel jenis encoding suara, tentukan setelan default atau MediaRecorder.AudioEncoder.AMR_NB.
        3. setVideoEncoder() - Setel jenis encoding video, tentukan setelan default atau MediaRecorder.VideoEncoder.MPEG_4_SP.
      5. setOutputFile() - Setel file output, gunakan getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() dari metode contoh di bagian Menyimpan File Media.
      6. setPreviewDisplay() - Tentukan elemen tata letak pratinjau SurfaceView untuk aplikasi Anda. Gunakan objek yang sama yang Anda tentukan untuk Menghubungkan Pratinjau.

      Perhatian: Anda harus memanggil metode konfigurasi MediaRecorder dalam urutan ini, jika tidak, aplikasi Anda akan mengalami error dan perekaman akan gagal.

    3. Menyiapkan MediaRecorder - Siapkan MediaRecorder dengan setelan konfigurasi yang disediakan dengan memanggil MediaRecorder.prepare().
    4. Memulai MediaRecorder - Mulai merekam video dengan memanggil MediaRecorder.start().
  5. Menghentikan Rekaman Video - Panggil metode berikut agar berhasil menyelesaikan rekaman video:
    1. Menghentikan MediaRecorder - Hentikan merekam video dengan memanggil MediaRecorder.stop().
    2. Mereset MediaRecorder - Secara opsional, hapus setelan konfigurasi dari perekam dengan memanggil MediaRecorder.reset().
    3. Merilis MediaRecorder - Rilis MediaRecorder dengan memanggil MediaRecorder.release().
    4. Mengunci Kamera - Kunci kamera sehingga sesi MediaRecorder berikutnya dapat menggunakannya dengan memanggil Camera.lock(). Mulai Android 4.0 (API level 14), panggilan ini tidak diperlukan kecuali jika panggilan MediaRecorder.prepare() gagal.
  6. Menghentikan Pratinjau - Saat aktivitas Anda selesai menggunakan kamera, hentikan pratinjau menggunakan Camera.stopPreview().
  7. Merilis Kamera - Rilis kamera sehingga aplikasi lain dapat menggunakannya dengan memanggil Camera.release().

Catatan: Dimungkinkan untuk menggunakan MediaRecorder tanpa membuat pratinjau kamera terlebih dahulu dan melewati beberapa langkah pertama proses ini. Namun, karena pengguna biasanya lebih suka melihat pratinjau sebelum memulai rekaman, proses itu tidak dibahas di sini.

Tips: Jika aplikasi Anda biasanya digunakan untuk merekam video, setel setRecordingHint(boolean) ke true sebelum memulai pratinjau. Setelan ini dapat membantu mengurangi waktu yang diperlukan untuk memulai rekaman.

Mengonfigurasi MediaRecorder

Saat menggunakan class MediaRecorder untuk merekam video, Anda harus melakukan langkah-langkah konfigurasi dalam urutan spesifik, lalu memanggil metode MediaRecorder.prepare() untuk memeriksa dan mengimplementasikan konfigurasi. Contoh kode berikut menunjukkan cara mengonfigurasi dan mempersiapkan class MediaRecorder untuk perekaman video dengan benar.

Kotlin

private fun prepareVideoRecorder(): Boolean {
    mediaRecorder = MediaRecorder()

    mCamera?.let { camera ->
        // Step 1: Unlock and set camera to MediaRecorder
        camera?.unlock()

        mediaRecorder?.run {
            setCamera(camera)

            // Step 2: Set sources
            setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
            setVideoSource(MediaRecorder.VideoSource.CAMERA)

            // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
            setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH))

            // Step 4: Set output file
            setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString())

            // Step 5: Set the preview output
            setPreviewDisplay(mPreview?.holder?.surface)

            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
            setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)


            // Step 6: Prepare configured MediaRecorder
            return try {
                prepare()
                true
            } catch (e: IllegalStateException) {
                Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            } catch (e: IOException) {
                Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            }
        }

    }
    return false
}

Java

private boolean prepareVideoRecorder(){

    mCamera = getCameraInstance();
    mediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    // Step 4: Set output file
    mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

    // Step 5: Set the preview output
    mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

    // Step 6: Prepare configured MediaRecorder
    try {
        mediaRecorder.prepare();
    } catch (IllegalStateException e) {
        Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    } catch (IOException e) {
        Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    }
    return true;
}

Sebelum Android 2.2 (API Level 8), Anda harus menyetel parameter format output dan format encoding secara langsung, daripada menggunakan CamcorderProfile. Pendekatan ini ditunjukkan dalam kode berikut:

Kotlin

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder?.apply {
        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
        setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)
    }

Java

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

Parameter perekaman video berikut untuk MediaRecorder diberi setelan default, tetapi Anda mungkin ingin menyesuaikan setelan ini untuk aplikasi Anda:

Memulai dan menghentikan MediaRecorder

Saat memulai dan menghentikan perekaman video menggunakan class MediaRecorder, Anda harus mengikuti urutan tertentu, seperti yang tercantum di bawah ini.

  1. Buka kunci kamera dengan Camera.unlock()
  2. Konfigurasi MediaRecorder seperti yang ditunjukkan pada contoh kode di atas
  3. Mulai perekaman menggunakan MediaRecorder.start()
  4. Rekam videonya
  5. Hentikan perekaman menggunakan MediaRecorder.stop()
  6. Rilis perekam media dengan MediaRecorder.release()
  7. Kunci kamera menggunakan Camera.lock()

Kode contoh berikut menunjukkan cara memasang tombol untuk memulai dan menghentikan perekaman video dengan benar menggunakan kamera dan class MediaRecorder.

Catatan: Saat menyelesaikan rekaman video, jangan rilis kamera atau pratinjau Anda akan dihentikan.

Kotlin

var isRecording = false
val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    if (isRecording) {
        // stop recording and release camera
        mediaRecorder?.stop() // stop the recording
        releaseMediaRecorder() // release the MediaRecorder object
        mCamera?.lock() // take camera access back from MediaRecorder

        // inform the user that recording has stopped
        setCaptureButtonText("Capture")
        isRecording = false
    } else {
        // initialize video camera
        if (prepareVideoRecorder()) {
            // Camera is available and unlocked, MediaRecorder is prepared,
            // now you can start recording
            mediaRecorder?.start()

            // inform the user that recording has started
            setCaptureButtonText("Stop")
            isRecording = true
        } else {
            // prepare didn't work, release the camera
            releaseMediaRecorder()
            // inform user
        }
    }
}

Java

private boolean isRecording = false;

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (isRecording) {
                // stop recording and release camera
                mediaRecorder.stop();  // stop the recording
                releaseMediaRecorder(); // release the MediaRecorder object
                mCamera.lock();         // take camera access back from MediaRecorder

                // inform the user that recording has stopped
                setCaptureButtonText("Capture");
                isRecording = false;
            } else {
                // initialize video camera
                if (prepareVideoRecorder()) {
                    // Camera is available and unlocked, MediaRecorder is prepared,
                    // now you can start recording
                    mediaRecorder.start();

                    // inform the user that recording has started
                    setCaptureButtonText("Stop");
                    isRecording = true;
                } else {
                    // prepare didn't work, release the camera
                    releaseMediaRecorder();
                    // inform user
                }
            }
        }
    }
);

Catatan: Dalam contoh di atas, metode prepareVideoRecorder() merujuk pada kode contoh yang ditunjukkan pada Mengonfigurasi MediaRecorder. Metode ini menangani penguncian kamera, konfigurasi, dan penyiapan instance MediaRecorder.

Merilis kamera

Kamera adalah sumber daya yang digunakan bersama oleh aplikasi pada perangkat. Aplikasi Anda dapat menggunakan kamera setelah mendapatkan instance Camera, dan Anda harus sangat berhati-hati untuk merilis objek kamera saat aplikasi berhenti menggunakannya, dan segera setelah aplikasi dijeda (Activity.onPause()). Jika aplikasi Anda tidak merilis kamera dengan benar, semua upaya berikutnya untuk mengakses kamera, termasuk yang dilakukan oleh aplikasi Anda sendiri, akan gagal dan dapat menyebabkan aplikasi Anda atau aplikasi lainnya dinonaktifkan.

Untuk merilis instance objek Camera, gunakan metode Camera.release() seperti yang ditunjukkan pada contoh kode di bawah ini.

Kotlin

class CameraActivity : Activity() {
    private var mCamera: Camera?
    private var preview: SurfaceView?
    private var mediaRecorder: MediaRecorder?

    override fun onPause() {
        super.onPause()
        releaseMediaRecorder() // if you are using MediaRecorder, release it first
        releaseCamera() // release the camera immediately on pause event
    }

    private fun releaseMediaRecorder() {
        mediaRecorder?.reset() // clear recorder configuration
        mediaRecorder?.release() // release the recorder object
        mediaRecorder = null
        mCamera?.lock() // lock camera for later use
    }

    private fun releaseCamera() {
        mCamera?.release() // release the camera for other applications
        mCamera = null
    }
}

Java

public class CameraActivity extends Activity {
    private Camera mCamera;
    private SurfaceView preview;
    private MediaRecorder mediaRecorder;

    ...

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaRecorder();       // if you are using MediaRecorder, release it first
        releaseCamera();              // release the camera immediately on pause event
    }

    private void releaseMediaRecorder(){
        if (mediaRecorder != null) {
            mediaRecorder.reset();   // clear recorder configuration
            mediaRecorder.release(); // release the recorder object
            mediaRecorder = null;
            mCamera.lock();           // lock camera for later use
        }
    }

    private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
}

Perhatian: Jika aplikasi Anda tidak merilis kamera dengan benar, semua upaya berikutnya untuk mengakses kamera, termasuk yang dilakukan oleh aplikasi Anda sendiri, akan gagal dan dapat menyebabkan aplikasi Anda atau lainnya dinonaktifkan.

Menyimpan file media

File media yang dibuat oleh pengguna seperti gambar dan video harus disimpan ke direktori penyimpanan eksternal perangkat (Kartu SD) untuk menghemat ruang sistem dan memungkinkan pengguna untuk mengakses file-file ini tanpa perangkat mereka. Ada banyak kemungkinan lokasi direktori untuk menyimpan file media pada perangkat, tetapi hanya ada dua lokasi standar yang harus Anda pertimbangkan sebagai developer:

  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) - Metode ini menampilkan lokasi standar, bersama, dan yang disarankan untuk menyimpan gambar dan video. Direktori ini dibagikan (publik), sehingga aplikasi lain dapat dengan mudah menemukan, membaca, mengubah, dan menghapus file yang disimpan di lokasi ini. Jika aplikasi Anda dihapus oleh pengguna, file media yang disimpan di lokasi ini tidak akan dihapus. Untuk menghindari gangguan pada pengguna yang ada gambar dan video, Anda harus membuat sub-direktori untuk file media aplikasi Anda dalam direktori ini, seperti yang ditunjukkan dalam contoh kode di bawah ini. Metode ini tersedia di Android 2.2 (API Level 8), untuk panggilan setara di versi API sebelumnya, lihat Menyimpan File Bersama.
  • Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) - Metode ini menampilkan lokasi standar untuk menyimpan gambar dan video yang terkait dengan aplikasi Anda. Jika aplikasi Anda dihapus, file apa pun yang disimpan di lokasi ini akan terhapus. Keamanan tidak diberlakukan untuk file di lokasi ini dan aplikasi lain dapat membaca, mengubah, dan menghapusnya.

Kode contoh berikut menunjukkan cara membuat lokasi File atau Uri untuk file media yang dapat digunakan saat mengaktifkan kamera perangkat dengan Intent atau sebagai bagian dari Membuat Aplikasi Kamera.

Kotlin

val MEDIA_TYPE_IMAGE = 1
val MEDIA_TYPE_VIDEO = 2

/** Create a file Uri for saving an image or video */
private fun getOutputMediaFileUri(type: Int): Uri {
    return Uri.fromFile(getOutputMediaFile(type))
}

/** Create a File for saving an image or video */
private fun getOutputMediaFile(type: Int): File? {
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    val mediaStorageDir = File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp"
    )
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    mediaStorageDir.apply {
        if (!exists()) {
            if (!mkdirs()) {
                Log.d("MyCameraApp", "failed to create directory")
                return null
            }
        }
    }

    // Create a media file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    return when (type) {
        MEDIA_TYPE_IMAGE -> {
            File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg")
        }
        MEDIA_TYPE_VIDEO -> {
            File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4")
        }
        else -> null
    }
}

Java

public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
      return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
              Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}

Catatan: Environment.getExternalStoragePublicDirectory() tersedia di Android 2.2 (API Level 8) atau lebih tinggi. Jika Anda menargetkan perangkat dengan versi Android yang lebih lama, gunakan Environment.getExternalStorageDirectory() sebagai gantinya. Untuk informasi selengkapnya, lihat Menyimpan File Bersama.

Untuk membuat URI mendukung profil kerja, pertama konversikan URI file ke URI konten. Kemudian, tambahkan URI konten untuk EXTRA_OUTPUT dari Intent.

Untuk informasi selengkapnya tentang menyimpan file di perangkat Android, lihat Penyimpanan Data.

Fitur kamera

Android mendukung beragam fitur kamera yang dapat Anda kontrol dengan aplikasi kamera, seperti format gambar, mode lampu flash, setelan fokus, dan banyak lagi. Bagian ini mencantumkan fitur-fitur kamera yang umum, dan secara singkat membahas cara menggunakannya. Sebagian besar fitur kamera dapat diakses dan disetel menggunakan objek Camera.Parameters. Namun, ada beberapa fitur penting yang memerlukan lebih dari sekadar setelan sederhana dalam Camera.Parameters. Fitur-fitur ini tercakup di bagian berikut:

Untuk informasi umum tentang cara menggunakan fitur yang dikontrol melalui Camera.Parameters, tinjau bagian Menggunakan fitur kamera. Untuk informasi lebih detail tentang cara menggunakan fitur yang dikontrol melalui objek parameter kamera, ikuti link dalam daftar fitur di bawah ini ke dokumentasi referensi API.

Tabel 1. Fitur kamera umum yang diurutkan berdasarkan Android API Level tempat fitur tersebut diperkenalkan.

Fitur API Level Deskripsi
Deteksi Wajah 14 Mengidentifikasi wajah manusia dalam gambar dan menggunakannya untuk fokus, pengukuran, dan keseimbangan putih
Area Pengukuran 14 Menentukan satu atau beberapa area dalam gambar untuk menghitung keseimbangan putih
Area Fokus 14 Menyetel satu atau beberapa area dalam gambar untuk digunakan untuk fokus
White Balance Lock 14 Menghentikan atau memulai penyesuaian keseimbangan putih otomatis
Exposure Lock 14 Menghentikan atau memulai penyesuaian eksposur otomatis
Video Snapshot 14 Mengambil foto saat merekam video (pengambilan bingkai)
Video Time Lapse 11 Merekam bingkai dengan penundaan yang disetel untuk merekam video time lapse
Multiple Cameras 9 Dukungan untuk lebih dari satu kamera pada perangkat, termasuk kamera depan dan belakang
Focus Distance 9 Melaporkan jarak antara kamera dan objek yang tampak dalam fokus
Zoom 8 Menyetel pembesaran gambar
Exposure Compensation 8 Menambah atau mengurangi level eksposur cahaya
GPS Data 5 Menyertakan atau menghapus data lokasi geografis dengan gambar
White Balance 5 Menyetel mode keseimbangan putih, yang memengaruhi nilai warna pada gambar yang diambil
Focus Mode 5 Menyetel cara kamera fokus pada objek, misalnya otomatis, tetap, makro, atau tak terbatas
Scene Mode 5 Menerapkan mode preset untuk jenis situasi fotografi tertentu seperti pemandangan malam, pantai, salju, atau cahaya lilin
JPEG Quality 5 Menyetel level kompresi untuk gambar JPEG, yang menambah atau mengurangi kualitas dan ukuran file output gambar
Flash Mode 5 Menyalakan atau mematikan flash, atau menggunakan setelan otomatis
Color Effects 5 Menerapkan efek warna pada gambar yang diambil seperti hitam dan putih, warna sepia atau negatif.
Anti-Banding 5 Mengurangi efek garis melintang pada gradien warna karena kompresi JPEG
Picture Format 1 Menentukan format file untuk gambar
Picture Size 1 Menentukan dimensi piksel dari gambar yang disimpan

Catatan: Fitur ini tidak didukung di semua perangkat karena perbedaan hardware dan penerapan software. Untuk informasi tentang cara memeriksa ketersediaan fitur pada perangkat tempat aplikasi Anda berjalan, lihat Memeriksa ketersediaan fitur.

Memeriksa ketersediaan fitur

Hal pertama yang harus dipahami saat menetapkan untuk menggunakan fitur kamera pada perangkat Android adalah tidak semua fitur kamera didukung pada semua perangkat. Selain itu, perangkat yang mendukung fitur tertentu dapat mendukungnya ke level yang berbeda atau dengan opsi yang berbeda. Oleh karena itu, bagian dari proses pengambilan keputusan saat Anda mengembangkan aplikasi kamera adalah memutuskan fitur kamera apa yang ingin Anda dukung dan pada level apa. Setelah membuat keputusan itu, Anda harus merencanakan untuk memasukkan kode dalam aplikasi kamera yang memeriksa apakah hardware perangkat mendukung fitur-fitur tersebut dan gagal dengan baik jika fitur tidak tersedia.

Anda dapat memeriksa ketersediaan fitur kamera dengan mendapatkan instance objek parameter kamera, dan memeriksa metode yang relevan. Contoh kode berikut menunjukkan cara mendapatkan objek Camera.Parameters dan memeriksa apakah kamera mendukung fitur fokus otomatis:

Kotlin

val params: Camera.Parameters? = camera?.parameters
val focusModes: List<String>? = params?.supportedFocusModes
if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) {
    // Autofocus mode is supported
}

Java

// get Camera parameters
Camera.Parameters params = camera.getParameters();

List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
  // Autofocus mode is supported
}

Anda dapat menggunakan teknik yang ditunjukkan di atas untuk sebagian besar fitur kamera. Objek Camera.Parameters menyediakan metode getSupported...(), is...Supported(), atau getMax...() untuk mengetahui apakah (dan sejauh mana) fitur didukung.

Jika aplikasi memerlukan fitur kamera tertentu agar berfungsi dengan benar, Anda dapat memintanya melalui penambahan pada manifes aplikasi Anda. Saat Anda mendeklarasikan penggunaan fitur kamera tertentu, seperti flash dan autofocus, Google Play membatasi aplikasi Anda agar tidak diinstal pada perangkat yang tidak mendukung fitur ini. Untuk daftar fitur kamera yang dapat dideklarasikan dalam manifes aplikasi Anda, lihat manifes Referensi Fitur.

Menggunakan fitur kamera

Sebagian besar fitur kamera diaktifkan dan dikontrol menggunakan objek Camera.Parameters. Anda mendapatkan objek ini dengan terlebih dahulu membuat instance objek Camera, memanggil metode getParameters(), mengubah objek parameter yang ditampilkan, lalu menyetelnya kembali ke objek kamera, seperti yang ditunjukkan dalam kode contoh berikut:

Kotlin

val params: Camera.Parameters? = camera?.parameters
params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
camera?.parameters = params

Java

// get Camera parameters
Camera.Parameters params = camera.getParameters();
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
camera.setParameters(params);

Teknik ini berfungsi untuk hampir semua fitur kamera, dan sebagian besar parameter dapat diubah kapan saja setelah Anda mendapatkan instance objek Camera. Perubahan pada parameter biasanya langsung terlihat oleh pengguna di pratinjau kamera aplikasi. Di sisi software, perubahan parameter mungkin memerlukan beberapa bingkai agar benar-benar berfungsi saat hardware kamera memproses instruksi baru dan kemudian mengirim data gambar yang diperbarui.

Penting: Beberapa fitur kamera tidak dapat diubah sesuai keinginan. Secara khusus, mengubah ukuran atau orientasi pratinjau kamera mengharuskan Anda terlebih dahulu menghentikan pratinjau, mengubah ukuran pratinjau, lalu memulai ulang pratinjau. Memulai dengan orientasi pratinjau Android 4.0 (API Level 14) dapat diubah tanpa memulai ulang pratinjau.

Fitur kamera lainnya memerlukan lebih banyak kode untuk diimplementasikan, termasuk:

  • Pengukuran dan area fokus
  • Deteksi wajah
  • Video time lapse

Garis besar singkat cara mengimplementasikan fitur-fitur ini disediakan di bagian berikut.

Pengukuran dan area fokus

Dalam beberapa skenario fotografi, pemfokusan otomatis dan pengukuran cahaya mungkin tidak menghasilkan hasil yang diinginkan. Mulai Android 4.0 (API Level 14), aplikasi kamera Anda dapat memberikan kontrol tambahan untuk memungkinkan aplikasi atau pengguna Anda menentukan area dalam gambar yang akan digunakan untuk menentukan fokus atau setelan level cahaya dan meneruskan nilai-nilai ini ke hardware kamera untuk digunakan dalam mengambil gambar atau video.

Area untuk pengukuran dan fokus berfungsi sangat mirip dengan fitur kamera lainnya, karena Anda mengontrolnya melalui metode pada objek Camera.Parameters. Kode berikut menunjukkan setelan dua area pengukuran cahaya untuk instance Camera:

Kotlin

// Create an instance of Camera
camera = getCameraInstance()

// set Camera parameters
val params: Camera.Parameters? = camera?.parameters

params?.apply {
    if (maxNumMeteringAreas > 0) { // check that metering areas are supported
        meteringAreas = ArrayList<Camera.Area>().apply {
            val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image
            add(Camera.Area(areaRect1, 600)) // set weight to 60%
            val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image
            add(Camera.Area(areaRect2, 400)) // set weight to 40%
        }
    }
    camera?.parameters = this
}

Java

// Create an instance of Camera
camera = getCameraInstance();

// set Camera parameters
Camera.Parameters params = camera.getParameters();

if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
    List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
    params.setMeteringAreas(meteringAreas);
}

camera.setParameters(params);

Objek Camera.Area berisi dua parameter data: Objek Rect untuk menentukan area dalam ruang pandang kamera dan nilai bobot, yang memberi tahu kamera berapa level nilai penting yang harus diberikan pada area ini dalam pengukuran cahaya atau perhitungan fokus.

Bidang Rect dalam objek Camera.Area menjelaskan bentuk persegi panjang yang dipetakan pada petak unit 2000 x 2000. Koordinat -1000, -1000 merepresentasikan sudut kiri atas gambar kamera, dan koordinat 1000, 1000 merepresentasikan sudut kanan bawah gambar kamera, seperti yang ditunjukkan pada ilustrasi di bawah ini.

Gambar 1. Garis merah menggambarkan sistem koordinat untuk menentukan Camera.Area dalam pratinjau kamera. Kotak biru menunjukkan lokasi dan bentuk area kamera dengan nilai Rect 333,333,667,667.

Batas-batas sistem koordinat ini selalu sesuai dengan tepi luar gambar yang terlihat di pratinjau kamera dan tidak menyusut atau melebar dengan level zoom. Demikian pula, rotasi pratinjau gambar menggunakan Camera.setDisplayOrientation() tidak memetakan ulang sistem koordinat.

Deteksi wajah

Untuk gambar yang menyertakan orang, wajah biasanya merupakan bagian terpenting dari gambar, dan harus digunakan untuk menentukan fokus dan keseimbangan putih saat mengambil foto. Framework Android 4.0 (API Level 14) menyediakan API untuk mengidentifikasi wajah dan menghitung setelan gambar menggunakan teknologi pengenalan wajah.

Catatan: Saat fitur deteksi wajah berjalan, setWhiteBalance(String), setFocusAreas(List<Camera.Area>), dan setMeteringAreas(List<Camera.Area>) tidak memiliki efek.

Menggunakan fitur deteksi wajah dalam aplikasi kamera Anda memerlukan beberapa langkah umum:

  • Periksa apakah deteksi wajah didukung pada perangkat
  • Buat pemroses deteksi wajah
  • Tambahkan pemroses deteksi wajah ke objek kamera
  • Mulai deteksi wajah setelah pratinjau (dan setelah setiap pratinjau dimulai ulang)

Fitur deteksi wajah tidak didukung di semua perangkat. Anda dapat memeriksa apakah fitur ini didukung dengan memanggil getMaxNumDetectedFaces(). Contoh pemeriksaan ini ditunjukkan dalam metode contoh startFaceDetection() di bawah ini.

Agar diberi tahu dan merespons deteksi wajah, aplikasi kamera Anda harus mengatur pemroses untuk peristiwa deteksi wajah. Untuk melakukannya, Anda harus membuat class pemroses yang mengimplementasikan antarmuka Camera.FaceDetectionListener seperti yang ditunjukkan pada contoh kode di bawah ini.

Kotlin

internal class MyFaceDetectionListener : Camera.FaceDetectionListener {

    override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) {
        if (faces.isNotEmpty()) {
            Log.d("FaceDetection", ("face detected: ${faces.size}" +
                    " Face 1 Location X: ${faces[0].rect.centerX()}" +
                    "Y: ${faces[0].rect.centerY()}"))
        }
    }
}

Java

class MyFaceDetectionListener implements Camera.FaceDetectionListener {

    @Override
    public void onFaceDetection(Face[] faces, Camera camera) {
        if (faces.length > 0){
            Log.d("FaceDetection", "face detected: "+ faces.length +
                    " Face 1 Location X: " + faces[0].rect.centerX() +
                    "Y: " + faces[0].rect.centerY() );
        }
    }
}

Setelah membuat class ini, Anda dapat menyetelnya ke dalam objek Camera aplikasi Anda, seperti yang ditunjukkan pada contoh kode di bawah ini:

Kotlin

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Java

camera.setFaceDetectionListener(new MyFaceDetectionListener());

Aplikasi Anda harus memulai fungsi deteksi wajah setiap kali memulai (atau memulai ulang) pratinjau kamera. Buat metode untuk memulai deteksi wajah sehingga Anda dapat memanggilnya sesuai kebutuhan, seperti yang ditunjukkan pada kode contoh di bawah ini.

Kotlin

fun startFaceDetection() {
    // Try starting Face Detection
    val params = mCamera?.parameters
    // start face detection only *after* preview has started

    params?.apply {
        if (maxNumDetectedFaces > 0) {
            // camera supports face detection, so can start it:
            mCamera?.startFaceDetection()
        }
    }
}

Java

public void startFaceDetection(){
    // Try starting Face Detection
    Camera.Parameters params = mCamera.getParameters();

    // start face detection only *after* preview has started
    if (params.getMaxNumDetectedFaces() > 0){
        // camera supports face detection, so can start it:
        mCamera.startFaceDetection();
    }
}

Anda harus memulai deteksi wajah setiap kali Anda memulai (atau memulai ulang) pratinjau kamera. Jika Anda menggunakan class pratinjau yang ditunjukkan dalam Membuat class pratinjau, tambahkan metode startFaceDetection() ke metode surfaceCreated() dan surfaceChanged() di class pratinjau Anda, seperti yang ditunjukkan pada kode contoh di bawah ini.

Kotlin

override fun surfaceCreated(holder: SurfaceHolder) {
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // start face detection feature
    } catch (e: IOException) {
        Log.d(TAG, "Error setting camera preview: ${e.message}")
    }
}

override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
    if (holder.surface == null) {
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null")
        return
    }
    try {
        mCamera.stopPreview()
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: ${e.message}")
    }
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // re-start face detection feature
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: ${e.message}")
    }
}

Java

public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // start face detection feature

    } catch (IOException e) {
        Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

    if (holder.getSurface() == null){
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null");
        return;
    }

    try {
        mCamera.stopPreview();

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: " + e.getMessage());
    }

    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // re-start face detection feature

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

Catatan: Ingat untuk memanggil metode ini setelah memanggil startPreview(). Jangan coba memulai deteksi wajah dalam metode onCreate() dari aktivitas utama aplikasi kamera Anda, karena pratinjau tidak tersedia pada titik ini dalam eksekusi aplikasi Anda.

Video time lapse

Video time lapse memungkinkan pengguna untuk membuat klip video yang menggabungkan gambar yang diambil terpisah selang beberapa detik atau menit. Fitur ini menggunakan MediaRecorder untuk merekam gambar untuk urutan time lapse.

Untuk merekam video time lapse dengan MediaRecorder, Anda harus mengonfigurasi objek perekam seolah-olah Anda merekam video normal, menyetel frame yang diambil per detik ke angka rendah, dan menggunakan salah satu setelan kualitas time lapse, seperti yang ditunjukkan pada contoh kode di bawah ini.

Kotlin

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

Java

// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH));
...
// Step 5.5: Set the video capture rate to a low number
mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds

Setelan ini harus dilakukan sebagai bagian dari prosedur konfigurasi yang lebih besar untuk MediaRecorder. Untuk contoh kode konfigurasi lengkap, lihat Mengonfigurasi MediaRecorder. Setelah konfigurasi selesai, mulai merekam video seolah-olah Anda sedang merekam klip video normal. Untuk informasi selengkapnya tentang cara mengonfigurasi dan menjalankan MediaRecorder, lihat Merekam video.

Contoh Camera2Video dan HdrViewfinder lebih lanjut menunjukkan penggunaan API yang dibahas di halaman ini.

Bidang kamera yang memerlukan izin

Aplikasi yang menjalankan Android 10 (API level 29) atau yang lebih tinggi harus memiliki izin CAMERA untuk mengakses nilai dari kolom berikut yang dihasilkan oleh metode getCameraCharacteristics():

  • LENS_POSE_ROTATION
  • LENS_POSE_TRANSLATION
  • LENS_INTRINSIC_CALIBRATION
  • LENS_RADIAL_DISTORTION
  • LENS_POSE_REFERENCE
  • LENS_DISTORTION
  • LENS_INFO_HYPERFOCAL_DISTANCE
  • LENS_INFO_MINIMUM_FOCUS_DISTANCE
  • SENSOR_REFERENCE_ILLUMINANT1
  • SENSOR_REFERENCE_ILLUMINANT2
  • SENSOR_CALIBRATION_TRANSFORM1
  • SENSOR_CALIBRATION_TRANSFORM2
  • SENSOR_COLOR_TRANSFORM1
  • SENSOR_COLOR_TRANSFORM2
  • SENSOR_FORWARD_MATRIX1
  • SENSOR_FORWARD_MATRIX2

Kode contoh tambahan

Untuk mendownload aplikasi sampel, lihat sampel Camera2Basic sample dan aplikasi sampel CameraX resmi.