sterować kamerą,

W tej lekcji omówimy, jak bezpośrednio sterować sprzętem fotograficznym za pomocą dla interfejsów API platformy Google.

Uwaga: ta strona dotyczy wycofanej klasy Camera. Zalecamy korzystanie z Aparatu X lub – w określonych przypadkach – z Aparatu 2. Aparaty CameraX i Aparat 2 obsługują Androida 5.0 (poziom interfejsu API 21) i nowsze wersje.

Bezpośrednie sterowanie aparatem urządzenia wymaga znacznie więcej kodu niż wysyłanie żądań zdjęć czy filmów z istniejących aplikacji aparatu. Jeśli jednak chcesz stworzyć specjalistyczną aplikację do obsługi aparatu lub w pełni zintegrowany z interfejsem aplikacji, z tej lekcji dowiesz się, jak to zrobić.

Zapoznaj się z tymi powiązanymi materiałami:

Otwórz obiekt kamery

Pierwszym krokiem w metodzie jest uzyskanie instancji Camera. bezpośredniego sterowania kamerą. Podobnie jak w przypadku aplikacji Aparat w systemie Android, zalecanym sposobem na dostęp do aparatu jest otwarcie pliku Camera w osobnym wątku uruchamiany od onCreate(). To dobry pomysł, bo może to chwilę potrwać i zakłócić wątek UI. W bardziej podstawowej implementacji otwarcie kamery można oprzeć na metodzie onResume(), aby ułatwić ponowne użycie kodu i zachować przepływ to proste.

Dzwonienie do Camera.open() powoduje zgłoszenie błędu Wyjątkiem są sytuacje, gdy kamera jest już używana przez inną aplikację, więc zapakujemy ją w bloku 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;
    }
}

Od poziomu interfejsu API na poziomie 9 platforma kamery obsługuje wiele kamer. Jeśli używasz tagu starszą wersję interfejsu API i wywołanie funkcji open() bez pierwszy tylny aparat.

Utwórz podgląd z aparatu

Zrobienie zdjęcia zazwyczaj wymaga, by użytkownicy zobaczyli podgląd obiektu, zanim go klikną. Migawka. Aby to zrobić, użyj obiektu SurfaceView, aby wyświetlić podgląd tego, jest wykrywany.

Podgląd zajęć

Aby zacząć wyświetlać podgląd, potrzebujesz klasy podglądu. podgląd wymaga implementacji interfejsu android.view.SurfaceHolder.Callback, który służy do przekazywania obrazu ze sprzętu aparatu do aplikacji.

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

Przed rozpoczęciem transmisji na żywo do obiektu Camera należy przekazać klasę podglądu jak wygląda podgląd obrazu, jak pokazano w następnej sekcji.

Ustaw i uruchom podgląd

Instancja kamery i powiązany z nią podgląd muszą być utworzone w określonym w kolejności, gdzie obiekt kamery jest pierwszy. We fragmencie kodu poniżej proces inicjowania kamery jest ograniczony tak, aby funkcja Camera.startPreview() była wywoływana przez setCamera(), gdy użytkownik wykona jakąś zmianę aparat fotograficzny. Podgląd trzeba też ponownie uruchomić z użyciem metody wywołania zwrotnego klasy podglądu surfaceChanged().

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

Zmiana ustawień aparatu

Ustawienia aparatu zmieniają sposób, w jaki aparat robi zdjęcia do kompensacji ekspozycji. W tym przykładzie zmienia się tylko rozmiar podglądu. znajdziesz w kodzie źródłowym aplikacji Aparat.

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

Ustawianie orientacji podglądu

Większość aplikacji aparatu blokuje ekran w trybie poziomym, ponieważ jest to naturalne od orientacji czujnika aparatu. To ustawienie nie blokuje trybu portretowego ponieważ orientacja urządzenia jest zapisywana w nagłówku EXIF. Metoda setCameraDisplayOrientation() umożliwia zmianę sposób wyświetlania podglądu, nie wpływając na sposób rejestrowania obrazu. Jednak na Androidzie przed do poziomu interfejsu API 14, przed zmianą orientacji musisz zatrzymać podgląd, a następnie uruchomić go ponownie.

Zrób zdjęcie

Użyj funkcji Camera.takePicture() zrobić zdjęcie po uruchomieniu podglądu. Możesz tworzyć obiekty Camera.PictureCallback i Camera.ShutterCallback oraz przekazywać je do Camera.takePicture().

Jeśli chcesz zbierać obrazy w sposób ciągły, możesz utworzyć obiekt Camera.PreviewCallback z implementacją onPreviewFrame(). Dla: można rejestrować tylko wybrane klatki podglądu lub skonfigurować działanie związane z opóźnieniem połączenia z numerem takePicture().

Ponownie uruchom podgląd

Po zrobieniu zdjęcia musisz ponownie uruchomić podgląd, zanim użytkownik może zrobić kolejne zdjęcie. W tym przykładzie ponowne uruchomienie odbywa się przez przeciążenie, przycisk migawki.

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

Zatrzymaj podgląd i puść aparat.

Gdy aplikacja zakończy działanie z użyciem aparatu, pora na oczyszczanie. W musisz zwolnić obiekt Camera, w przeciwnym razie istnieje ryzyko awarii innych aplikacji, w tym nowych instancji Twojej aplikacji.

Kiedy należy zatrzymać podgląd i puścić kamerę? Otwartość zniszczenie powierzchni podglądu to doskonała wskazówka, że trzeba zatrzymać wyświetlić podgląd i zwolnić kamerę, jak pokazano w tych metodach z klasy 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;
    }
}

Na początku lekcji ta procedura była też częścią metody setCamera(), więc inicjowanie kamery zawsze rozpoczyna się od zatrzymania podgląd.