Kamera steuern

In dieser Lektion erfahren Sie, wie Sie die Kamera-Hardware direkt mit die Framework-APIs.

Hinweis:Diese Seite bezieht sich auf die Camera-Klasse, die eingestellt wurde. Wir empfehlen die Verwendung von CameraX oder, für bestimmte Anwendungsfälle, Camera2. Sowohl CameraX als auch Camera2 unterstützen Android 5.0 (API-Level 21) und höher.

Die direkte Steuerung einer Gerätekamera erfordert viel mehr Code als das Anfordern von Bildern oder Videos. aus vorhandenen Kamera-Apps. Wenn Sie jedoch eine spezielle Kamera-App oder etwas vollständig in Ihre App-UI integriert ist, erfahren Sie in dieser Lektion.

Weitere Informationen finden Sie in den folgenden verwandten Ressourcen:

Kameraobjekt öffnen

Das Abrufen einer Instanz des Camera-Objekts ist der erste Schritt im die Kamera direkt zu steuern. Wie bei der Kamera-App von Android ist das empfohlene Methode für den Zugriff auf die Kamera besteht darin, Camera in einem separaten Thread zu öffnen die ab onCreate() gestartet wurde. Dieser Ansatz ist eine gute Idee, da dies eine Weile dauern und den UI-Thread beeinträchtigen kann. Bei einer einfacheren Implementierung Das Öffnen der Kamera kann auf die onResume()-Methode übertragen werden, um die Wiederverwendung von Code zu erleichtern und den Ablauf des einfach steuern können.

Durch den Aufruf von Camera.open() wird eine Ausnahme, wenn die Kamera bereits von einer anderen Anwendung verwendet wird. in einem try-Block.

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

Seit API-Level 9 unterstützt das Kamera-Framework mehrere Kameras. Wenn Sie das alten API verwenden und open() ohne eine erhalten Sie die erste Rückkamera.

Kameravorschau erstellen

Nutzer, die ein Bild aufnehmen, müssen normalerweise eine Vorschau des Motivs sehen, bevor sie darauf klicken. den Auslöser. Dazu können Sie mit SurfaceView eine Vorschau des den Sensor der Kamera erkennt.

Vorschauklasse

Damit Sie eine Vorschau anzeigen können, benötigen Sie einen Vorschaukurs. Die Für die Vorschau ist eine Implementierung der android.view.SurfaceHolder.Callback-Schnittstelle erforderlich, die zum Übergeben von Bildern verwendet wird. von der Kamerahardware an die Anwendung übertragen.

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

Die Vorschauklasse muss vor dem Livestream an das Camera-Objekt übergeben werden. wie die Bildvorschau gestartet werden kann, wie im nächsten Abschnitt beschrieben.

Vorschau festlegen und starten

Eine Kamerainstanz und die zugehörige Vorschau müssen in einer bestimmten wobei das Kameraobjekt an erster Stelle steht. Im Snippet unten enthält der Prozess der Initialisierung der Kamera ist gekapselt, sodass Camera.startPreview() vom setCamera()-Methode, wenn der Nutzer eine Änderung an der Kamera. Die Vorschau muss auch in der Callback-Methode der Vorschauklasse surfaceChanged() neu gestartet werden.

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

Kameraeinstellungen ändern

Über die Kameraeinstellungen wird die Art und Weise geändert, wie die Kamera Bilder aufnimmt – vom Zoom zur Belichtungskompensation. In diesem Beispiel wird nur die Größe der Vorschau geändert. finden Sie im Quellcode der Kamera-App.

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

Vorschauausrichtung festlegen

Die meisten Kamera-Apps fixieren das Display im Querformat, da dies die natürliche Ausrichtung des Kamerasensors. Diese Einstellung hindert dich nicht daran, den Porträtmodus zu verwenden. Fotos, da die Ausrichtung des Geräts im EXIF-Header aufgezeichnet wird. Mit der Methode setCameraDisplayOrientation() können Sie wie die Vorschau angezeigt wird, ohne die Aufzeichnung des Bildes zu beeinflussen. In Android vor früheren API-Level 14 aktiviert haben, müssen Sie die Vorschau beenden, bevor Sie die Ausrichtung ändern, und sie dann neu starten.

Foto aufnehmen

Camera.takePicture() verwenden um ein Bild aufzunehmen, nachdem die Vorschau gestartet wurde. Sie können Camera.PictureCallback- und Camera.ShutterCallback-Objekte erstellen und an Camera.takePicture() übergeben.

Wenn Sie fortlaufend Bilder erfassen möchten, können Sie eine Camera.PreviewCallback erstellen, in der onPreviewFrame() implementiert ist. Für nur ausgewählte Vorschau-Frames aufnehmen oder eine verzögerte Aktion zum Aufruf von takePicture().

Vorschau erneut starten

Nachdem ein Bild aufgenommen wurde, müssen Sie die Vorschau erneut starten, bevor der Nutzer ein weiteres Bild machen kann. In diesem Beispiel erfolgt der Neustart durch Überlastung auf den Auslöser.

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

Vorschau beenden und Kamera wieder freigeben

Sobald Ihre Anwendung die Kamera nicht mehr benötigt, können Sie sie bereinigen. In muss das Objekt Camera freigegeben werden, da andernfalls die Gefahr besteht, dass andere einschließlich neuer Instanzen Ihrer eigenen Anwendung.

Wann sollten Sie die Vorschau beenden und die Kamera wieder freigeben? Nun, wenn Sie Ihre Vorschauoberfläche zerstört ist ein Hinweis darauf, dass es Zeit ist, Sehen Sie sich eine Vorschau an und lassen Sie die Kamera wieder los, wie in diesen Methoden aus der Klasse Preview gezeigt.

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

Zu Beginn der Lektion war dieser Vorgang auch Teil der setCamera()-Methode. Die Initialisierung einer Kamera beginnt also immer mit dem Anhalten des in der Vorschau ansehen.