Kamerayı kontrol etme

Bu derste, çerçeve API'lerini kullanarak kamera donanımını doğrudan nasıl kontrol edeceğimiz ele alınmaktadır.

Not: Bu sayfada, desteği sonlandırılan Kamera sınıfı ele alınmaktadır. CameraX'i veya belirli kullanım alanlarında Camera2'yi kullanmanızı öneririz. Hem CameraX hem de Camera2, Android 5.0 (API düzeyi 21) ve sonraki sürümleri destekler.

Bir cihaz kamerasını doğrudan kontrol etmek, mevcut kamera uygulamalarından resim veya video istemekten çok daha fazla kod gerektirir. Ancak özel bir kamera uygulaması veya uygulamanızın kullanıcı arayüzüne tamamen entegre bir şey oluşturmak istiyorsanız bu derste nasıl yapacağınız gösterilmektedir.

Aşağıdaki ilgili kaynaklara göz atın:

Kamera Nesnesini Açma

Camera nesnesinin bir örneğini almak, kamerayı doğrudan kontrol etme sürecinin ilk adımıdır. Android'in kendi Kamera uygulamasında olduğu gibi, kameraya erişmenin önerilen yolu onCreate()'den başlatılan ayrı bir iş parçacığında Camera'yı açmaktır. Bu yaklaşım, işlem biraz zaman alabileceğinden ve kullanıcı arayüzü iş parçacığını yavaşlatabileceğinden iyi bir fikirdir. Daha basit bir uygulamada, kodun yeniden kullanılmasını kolaylaştırmak ve kontrol akışını basit tutmak için kameranın açılması onResume() yöntemine ertelenebilir.

Kamera başka bir uygulama tarafından kullanılıyorsa Camera.open() çağrısı bir istisna oluşturur. Bu nedenle, bu çağrıyı bir try bloğuna sararız.

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;
    }
}

API düzeyi 9'dan itibaren kamera çerçevesi birden fazla kamerayı destekler. Eski API'yi kullanıyorsanız ve open() işlevini bağımsız değişken olmadan çağırırsanız arkaya bakan ilk kamerayı alırsınız.

Kamera önizlemesini oluşturma

Fotoğraf çekmek genellikle kullanıcılarınızın deklanşöre basmadan önce öznenin önizlemesini görmesini gerektirir. Bunu yapmak için SurfaceView kullanarak kamera sensörünün yakaladığı görüntülerin önizlemelerini çizebilirsiniz.

Önizleme sınıfı

Önizleme göstermeye başlamak için önizleme sınıfına ihtiyacınız vardır. Önizleme için, kamera donanımından uygulamaya görüntü verilerini aktarmak üzere kullanılan android.view.SurfaceHolder.Callback arayüzünün uygulanması gerekir.

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);
    }
...
}

Canlı resim önizlemesi başlatılmadan önce önizleme sınıfı, sonraki bölümde gösterildiği gibi Camera nesnesine iletilmelidir.

Önizlemeyi ayarlama ve başlatma

Bir kamera örneği ve ilgili önizlemesi belirli bir sırada oluşturulmalıdır. Önce kamera nesnesi oluşturulur. Aşağıdaki snippet'te, kullanıcı kamerayı değiştirmek için bir işlem yaptığında Camera.startPreview() işlevinin setCamera() yöntemi tarafından çağrılması için kamerayı başlatma işlemi kapsüllenmiştir. Önizleme, önizleme sınıfı surfaceChanged() geri çağırma yönteminde de yeniden başlatılmalıdır.

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();
    }
}

Kamera ayarlarını değiştirme

Kamera ayarları, kameranın fotoğraf çekme şeklini değiştirir. Bu ayarlar arasında yakınlaştırma düzeyi ve pozlama telafisi yer alır. Bu örnekte yalnızca önizleme boyutu değiştirilmektedir. Çok daha fazla örnek için Kamera uygulamasının kaynak koduna bakın.

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();
}

Önizleme yönünü ayarlama

Çoğu kamera uygulaması, kamera sensörünün doğal yönü olduğu için ekranı yatay moda kilitler. Bu ayar, cihazın yönü EXIF başlığında kaydedildiğinden portre modu fotoğraflar çekmenizi engellemez. setCameraDisplayOrientation() yöntemi, görüntünün kaydedilme şeklini etkilemeden önizlemenin nasıl görüntülendiğini değiştirmenize olanak tanır. Ancak API düzeyi 14'ten önceki Android sürümlerinde yönü değiştirmeden önce önizlemenizi durdurup yeniden başlatmanız gerekir.

Fotoğraf Çekme

Önizleme başlatıldıktan sonra fotoğraf çekmek için Camera.takePicture() yöntemini kullanın. Camera.PictureCallback ve Camera.ShutterCallback nesneleri oluşturup Camera.takePicture()'ye iletebilirsiniz.

Görüntüleri sürekli olarak almak istiyorsanız onPreviewFrame() işlevini uygulayan bir Camera.PreviewCallback oluşturabilirsiniz. İkisinin arasında bir seçenek olarak, yalnızca seçilen önizleme karelerini yakalayabilir veya takePicture() işlevini çağırmak için gecikmeli bir işlem ayarlayabilirsiniz.

Önizlemeyi yeniden başlatma

Bir fotoğraf çekildikten sonra kullanıcının başka bir fotoğraf çekebilmesi için önizlemeyi yeniden başlatmanız gerekir. Bu örnekte, deklanşör düğmesi aşırı yüklenerek yeniden başlatma işlemi yapılır.

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();
}

Önizlemeyi Durdurma ve Kamerayı Serbest Bırakma

Uygulamanız kamerayı kullanmayı bitirdikten sonra temizlik yapma zamanı gelir. Özellikle Camera nesnesini serbest bırakmanız gerekir. Aksi takdirde, kendi uygulamanızın yeni örnekleri de dahil olmak üzere diğer uygulamaların kilitlenmesi riskiyle karşılaşırsınız.

Önizlemeyi ne zaman durdurup kamerayı serbest bırakmalısınız? Önizleme yüzeyinizin bozulması, Preview sınıfındaki bu yöntemlerde gösterildiği gibi önizlemeyi durdurup kamerayı serbest bırakma zamanının geldiğine dair oldukça iyi bir ipucudur.

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;
    }
}

Bu prosedür, dersin önceki bölümlerinde setCamera() yönteminin bir parçası olarak da ele alınmıştı. Bu nedenle, kamerayı başlatmak için her zaman önizlemeyi durdurmanız gerekir.