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.