Platforma Androida obsługuje różne aparaty i funkcje aparatu dostępne na urządzeniach, co umożliwia robienie zdjęć i nagrywanie filmów w aplikacjach. W tym dokumencie omawiamy szybkie i proste podejście do robienia zdjęć i nagrywania filmów oraz przedstawiamy zaawansowane podejście do tworzenia niestandardowych funkcji aparatu dla użytkowników.
Uwaga: na tej stronie opisano klasę Camera, która została wycofana. Zalecamy używanie biblioteki Jetpack CameraX lub, w określonych przypadkach, klasy camera2. Zarówno CameraX, jak i Camera2 działają na Androidzie 5.0 (poziom interfejsu API 21) i nowszych wersjach.
Zapoznaj się z tymi przydatnymi materiałami:
Uwagi
Zanim włączysz w aplikacji możliwość korzystania z aparatów na urządzeniach z Androidem, zastanów się nad kilkoma kwestiami dotyczącymi sposobu, w jaki aplikacja będzie używać tej funkcji sprzętowej.
- Wymagania dotyczące aparatu – czy korzystanie z aparatu jest tak ważne dla Twojej aplikacji, że nie chcesz, aby była ona instalowana na urządzeniu, które nie ma aparatu? Jeśli tak, musisz zadeklarować wymaganie dotyczące aparatu w pliku manifestu.
- Szybkie zdjęcie lub dostosowany aparat – jak aplikacja będzie korzystać z aparatu? Czy chcesz tylko zrobić szybkie zdjęcie lub nagrać klip wideo, czy Twoja aplikacja będzie oferować nowy sposób korzystania z aparatów? Jeśli chcesz szybko zrobić zdjęcie lub nagrać klip, rozważ użycie istniejących aplikacji aparatu. Informacje o tworzeniu niestandardowej funkcji aparatu znajdziesz w sekcji Tworzenie aplikacji aparatu.
- Wymagania dotyczące usług na pierwszym planie – kiedy aplikacja korzysta z aparatu? Na Androidzie 9 (poziom interfejsu API 28) i nowszych aplikacje działające w tle nie mają dostępu do aparatu. Dlatego należy używać aparatu, gdy aplikacja działa na pierwszym planie lub jako część usługi na pierwszym planie.
- Pamięć – czy obrazy lub filmy generowane przez aplikację mają być widoczne tylko dla niej, czy też mają być udostępniane, aby mogły z nich korzystać inne aplikacje, takie jak Galeria lub inne aplikacje multimedialne i społecznościowe? Czy chcesz, aby zdjęcia i filmy były dostępne nawet po odinstalowaniu aplikacji? Aby dowiedzieć się, jak wdrożyć te opcje, zapoznaj się z sekcją Zapisywanie plików multimedialnych.
Podstawy
Platforma Androida obsługuje robienie zdjęć i nagrywanie filmów za pomocą interfejsu API android.hardware.camera2 lub Intent aparatu. Oto odpowiednie klasy:
android.hardware.camera2- Ten pakiet jest głównym interfejsem API do sterowania aparatami urządzenia. Można go używać do robienia zdjęć lub nagrywania filmów podczas tworzenia aplikacji aparatu.
Camera- Ta klasa to starszy, wycofany interfejs API do sterowania kamerami urządzeń.
SurfaceView- Ta klasa służy do wyświetlania użytkownikowi podglądu z kamery na żywo.
MediaRecorder- Ta klasa służy do nagrywania filmów za pomocą aparatu.
Intent- Do robienia zdjęć lub nagrywania filmów bez bezpośredniego użycia obiektu
Cameramożna użyć typu działania intencjiMediaStore.ACTION_IMAGE_CAPTURElubMediaStore.ACTION_VIDEO_CAPTURE.
Deklaracje w pliku manifestu
Zanim zaczniesz tworzyć aplikację za pomocą interfejsu Camera API, upewnij się, że plik manifestu zawiera odpowiednie deklaracje umożliwiające korzystanie ze sprzętu aparatu i innych powiązanych funkcji.
- Uprawnienia dostępu do aparatu – aplikacja musi poprosić o uprawnienia do korzystania z aparatu urządzenia.
<uses-permission android:name="android.permission.CAMERA" />
Uwaga: jeśli używasz aparatu, wywołując istniejącą aplikację aparatu, Twoja aplikacja nie musi prosić o to uprawnienie.
- Funkcje aparatu – aplikacja musi też deklarować użycie funkcji aparatu, na przykład:
<uses-feature android:name="android.hardware.camera" />
Listę funkcji aparatu znajdziesz w dokumentacji funkcji w pliku manifestu.
Dodanie funkcji aparatu do pliku manifestu powoduje, że Google Play uniemożliwia instalowanie aplikacji na urządzeniach, które nie mają aparatu lub nie obsługują określonych funkcji aparatu. Więcej informacji o używaniu filtrowania na podstawie funkcji w Google Play znajdziesz w artykule Google Play i filtrowanie na podstawie funkcji.
Jeśli aplikacja może używać aparatu lub funkcji aparatu do prawidłowego działania, ale nie jest to wymagane, należy to określić w pliku manifestu, dodając atrybut
android:requiredi ustawiając go nafalse:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Uprawnienia do pamięci – aplikacja może zapisywać obrazy lub filmy w pamięci zewnętrznej urządzenia (na karcie SD), jeśli jest przeznaczona na Androida 10 (interfejs API na poziomie 29) lub starszego i zawiera w pliku manifestu te informacje:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Uprawnienia do nagrywania dźwięku – aby nagrywać dźwięk podczas nagrywania filmu, aplikacja musi poprosić o uprawnienia do nagrywania dźwięku.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
Dostęp do lokalizacji – jeśli aplikacja dodaje do obrazów tagi z informacjami o lokalizacji GPS, musisz poprosić o uprawnienie
ACCESS_FINE_LOCATION. Pamiętaj, że jeśli aplikacja jest kierowana na Androida 5.0 (poziom interfejsu API 21) lub nowszego, musisz też zadeklarować, że korzysta ona z GPS-u urządzenia:<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" />
Więcej informacji o uzyskiwaniu lokalizacji użytkownika znajdziesz w artykule Strategie lokalizacji.
Korzystanie z istniejących aplikacji do obsługi aparatu
Szybkim sposobem na umożliwienie robienia zdjęć lub nagrywania filmów w aplikacji bez konieczności dodawania dużej ilości kodu jest użycie Intent do wywołania istniejącej aplikacji aparatu na Androida.
Szczegółowe informacje znajdziesz w lekcjach Robienie zdjęć w prosty sposób i Nagrywanie filmów w prosty sposób.
Tworzenie aplikacji aparatu
Niektórzy deweloperzy mogą wymagać interfejsu aparatu dostosowanego do wyglądu aplikacji lub oferującego specjalne funkcje. Napisanie własnego kodu do robienia zdjęć może zapewnić użytkownikom lepsze wrażenia.
Uwaga: ten przewodnik dotyczy starszego, wycofanego interfejsu API Camera. W przypadku nowych lub zaawansowanych aplikacji aparatu zalecamy korzystanie z nowszego interfejsu API android.hardware.camera2.
Ogólne instrukcje tworzenia niestandardowego interfejsu aparatu w aplikacji:
- Wykrywanie i uzyskiwanie dostępu do aparatu – utwórz kod, aby sprawdzić, czy są dostępne aparaty, i poprosić o dostęp.
- Utworzenie klasy podglądu – utwórz klasę podglądu kamery, która rozszerza klasę
SurfaceViewi implementuje interfejsSurfaceHolder. Ta klasa wyświetla podgląd obrazów na żywo z kamery. - Tworzenie układu podglądu – gdy masz już klasę podglądu z kamery, utwórz układ widoku, który zawiera podgląd i wybrane elementy sterujące interfejsu.
- Konfigurowanie detektorów do przechwytywania – połącz detektory z elementami sterującymi interfejsu, aby rozpocząć przechwytywanie obrazu lub filmu w odpowiedzi na działania użytkownika, takie jak naciśnięcie przycisku.
- Przechwytywanie i zapisywanie plików – skonfiguruj kod do robienia zdjęć lub nagrywania filmów i zapisywania danych wyjściowych.
- Zwolnienie aparatu – po użyciu aparatu aplikacja musi go prawidłowo zwolnić, aby mogły z niego korzystać inne aplikacje.
Sprzęt aparatu jest zasobem współdzielonym, którym należy ostrożnie zarządzać, aby aplikacja nie kolidowała z innymi aplikacjami, które również mogą chcieć go używać. W poniższych sekcjach opisano, jak wykrywać sprzęt aparatu, jak prosić o dostęp do aparatu, jak robić zdjęcia i nagrywać filmy oraz jak zwolnić aparat, gdy aplikacja zakończy jego używanie.
Uwaga: pamiętaj, aby zwolnić obiekt Camera, wywołując Camera.release(), gdy aplikacja przestanie go używać. Jeśli aplikacja nie zwolni prawidłowo aparatu, wszystkie kolejne próby uzyskania do niego dostępu, w tym przez Twoją aplikację, zakończą się niepowodzeniem i mogą spowodować zamknięcie Twojej lub innych aplikacji.
Wykrywanie sprzętu aparatu
Jeśli Twoja aplikacja nie wymaga aparatu w deklaracji w pliku manifestu, sprawdź, czy aparat jest dostępny w czasie działania. Aby przeprowadzić tę weryfikację, użyj metody PackageManager.hasSystemFeature(), jak pokazano w tym przykładowym kodzie:
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; } }
Urządzenia z Androidem mogą mieć kilka aparatów, na przykład tylny do robienia zdjęć i przedni do rozmów wideo. Android 2.3 (interfejs API na poziomie 9) i nowsze wersje umożliwiają sprawdzenie liczby aparatów dostępnych na urządzeniu za pomocą metody Camera.getNumberOfCameras().
Dostęp do kamer
Jeśli ustalisz, że urządzenie, na którym działa aplikacja, ma aparat, musisz poprosić o dostęp do niego, pobierając instancję Camera (chyba że używasz intencji, aby uzyskać dostęp do aparatu).
Aby uzyskać dostęp do głównego aparatu, użyj metody Camera.open() i pamiętaj o obsłudze wyjątków, jak pokazano w kodzie poniżej:
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 }
Uwaga: podczas korzystania z funkcji Camera.open() zawsze sprawdzaj, czy nie występują wyjątki. Jeśli nie sprawdzisz, czy występują wyjątki, gdy aparat jest używany lub nie istnieje, system zamknie aplikację.
Na urządzeniach z Androidem 2.3 (poziom interfejsu API 9) lub nowszym możesz uzyskać dostęp do określonych aparatów za pomocą Camera.open(int). Powyższy przykładowy kod uzyska dostęp do pierwszego tylnego aparatu na urządzeniu z więcej niż 1 aparatem.
Sprawdzanie funkcji aparatu
Po uzyskaniu dostępu do aparatu możesz uzyskać więcej informacji o jego możliwościach, używając metody Camera.getParameters() i sprawdzając zwrócony obiekt Camera.Parameters pod kątem obsługiwanych funkcji. Jeśli używasz interfejsu API na poziomie 9 lub wyższym, użyj Camera.getCameraInfo(), aby określić, czy aparat znajduje się z przodu czy z tyłu urządzenia, oraz orientację obrazu.
Tworzenie wersji testowej klasy
Aby użytkownicy mogli skutecznie robić zdjęcia lub nagrywać filmy, muszą widzieć, co widzi aparat urządzenia. Klasa podglądu z aparatu to SurfaceView, która może wyświetlać dane obrazu na żywo pochodzące z aparatu, dzięki czemu użytkownicy mogą kadrować i robić zdjęcia lub nagrywać filmy.
Poniższy przykładowy kod pokazuje, jak utworzyć podstawową klasę podglądu z kamery, którą można uwzględnić w układzie View. Ta klasa implementuje interfejs SurfaceHolder.Callback, aby przechwytywać zdarzenia wywołania zwrotnego na potrzeby tworzenia i niszczenia widoku, które są potrzebne do przypisania danych wejściowych podglądu z kamery.
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()); } } }
Jeśli chcesz ustawić konkretny rozmiar podglądu z kamery, ustaw go w metodzie surfaceChanged(), jak opisano w komentarzach powyżej. Podczas ustawiania rozmiaru podglądu musisz użyć wartości z pola getSupportedPreviewSizes().
Nie ustawiaj dowolnych wartości w metodzie setPreviewSize().
Uwaga: po wprowadzeniu funkcji
wielu okien w Androidzie 7.0 (poziom interfejsu API 24) i nowszych nie można już zakładać, że format obrazu podglądu jest taki sam jak format aktywności, nawet po wywołaniu metody setDisplayOrientation().
W zależności od rozmiaru okna i formatu obrazu może być konieczne dopasowanie szerokiego podglądu z kamery do układu pionowego lub odwrotnie, przy użyciu układu letterbox.
Umieszczanie podglądu w układzie
Klasa podglądu z aparatu, taka jak w przykładzie pokazanym w poprzedniej sekcji, musi być umieszczona w układzie aktywności wraz z innymi elementami sterującymi interfejsu do robienia zdjęć lub nagrywania filmów. W tej sekcji dowiesz się, jak utworzyć podstawowy układ i aktywność na potrzeby podglądu.
Poniższy kod układu zapewnia bardzo podstawowy widok, który może służyć do wyświetlania podglądu z kamery. W tym przykładzie element FrameLayout ma być kontenerem klasy podglądu z aparatu. Ten typ układu jest używany, aby na obrazach podglądu z kamery na żywo można było nakładać dodatkowe informacje o zdjęciu lub elementy sterujące.
<?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>
Na większości urządzeń domyślna orientacja podglądu z aparatu jest pozioma. Ten przykładowy układ określa układ poziomy, a poniższy kod ustala orientację aplikacji na poziomą. Aby uprościć renderowanie podglądu z kamery, zmień orientację aktywności podglądu aplikacji na poziomą, dodając do pliku manifestu poniższy kod.
<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>
Uwaga: podgląd z aparatu nie musi być w trybie poziomym.
Na Androidzie 2.2 (interfejs API na poziomie 8) i nowszych wersjach możesz używać metody setDisplayOrientation(), aby ustawić obrót obrazu podglądu. Aby zmienić orientację podglądu, gdy użytkownik zmienia orientację telefonu, w metodzie surfaceChanged() klasy podglądu najpierw zatrzymaj podgląd za pomocą Camera.stopPreview(), zmień orientację, a następnie ponownie uruchom podgląd za pomocą Camera.startPreview().
W aktywności widoku kamery dodaj klasę podglądu do elementu FrameLayout pokazanego w przykładzie powyżej. Aktywność kamery musi też zapewniać jej zwolnienie, gdy jest wstrzymana lub wyłączona. Poniższy przykład pokazuje, jak zmodyfikować aktywność aparatu, aby dołączyć klasę podglądu pokazaną w sekcji Tworzenie klasy podglądu.
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); } }
Uwaga: metoda getCameraInstance() w przykładzie powyżej odnosi się do przykładowej metody pokazanej w sekcji Uzyskiwanie dostępu do kamer.
Robienie zdjęć
Po utworzeniu klasy podglądu i układu widoku, w którym ma być wyświetlany, możesz zacząć robić zdjęcia za pomocą aplikacji. W kodzie aplikacji musisz skonfigurować detektory elementów sterujących interfejsu, aby reagowały na działanie użytkownika przez zrobienie zdjęcia.
Aby pobrać zdjęcie, użyj metody Camera.takePicture(). Ta metoda przyjmuje 3 parametry, które otrzymują dane z aparatu.
Aby otrzymywać dane w formacie JPEG, musisz zaimplementować interfejs Camera.PictureCallback, który będzie odbierać dane obrazu i zapisywać je w pliku. Poniższy kod pokazuje podstawową implementację interfejsu Camera.PictureCallback, która umożliwia zapisanie obrazu otrzymanego z aparatu.
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()); } } };
Wywołaj metodę Camera.takePicture(), aby zrobić zdjęcie. Poniższy przykładowy kod pokazuje, jak wywołać tę metodę za pomocą przycisku 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); } } );
Uwaga: element mPicture w poniższym przykładzie odnosi się do przykładowego kodu powyżej.
Uwaga: pamiętaj, aby zwolnić obiekt Camera, wywołując metodę Camera.release(), gdy aplikacja zakończy korzystanie z niego. Informacje o tym, jak zwolnić kamerę, znajdziesz w sekcji Zwalnianie kamery.
Nagrywanie filmów
Nagrywanie filmów za pomocą platformy Androida wymaga starannego zarządzania obiektem Camera i koordynacji z klasą MediaRecorder. Podczas nagrywania filmu za pomocą Camera musisz zarządzać wywołaniami Camera.lock() i Camera.unlock(), aby umożliwić MediaRecorder dostęp do sprzętu kamery, oprócz wywołań Camera.open() i Camera.release().
Uwaga: od Androida 4.0 (interfejs API na poziomie 14) wywołania Camera.lock() i Camera.unlock() są zarządzane automatycznie.
W przeciwieństwie do robienia zdjęć aparatem urządzenia nagrywanie filmów wymaga bardzo konkretnej kolejności wywołań. Aby prawidłowo przygotować i nagrać film za pomocą aplikacji, musisz wykonać czynności w określonej kolejności, jak opisano poniżej.
- Otwórz aparat – użyj
Camera.open(), aby uzyskać instancję obiektu aparatu. - Podgląd połączenia – przygotuj podgląd obrazu z kamery na żywo, łącząc urządzenie
SurfaceViewz kamerą za pomocąCamera.setPreviewDisplay(). - Rozpocznij podgląd – wywołaj
Camera.startPreview(), aby rozpocząć wyświetlanie obrazu na żywo z kamery. - Rozpoczynanie nagrywania filmu – aby nagrać film, musisz wykonać te czynności w podanej kolejności:
- Unlock the Camera – odblokowuje aparat, aby umożliwić korzystanie z niego przez
MediaRecorder, wywołując funkcjęCamera.unlock(). - Skonfiguruj MediaRecorder – wywołaj te metody
MediaRecorderw podanej kolejności. Więcej informacji znajdziesz w dokumentacji referencyjnejMediaRecorder.setCamera()– ustaw kamerę, która ma być używana do nagrywania filmów, użyj bieżącej instancjiCameraaplikacji.setAudioSource()– ustaw źródło dźwięku, użyjMediaRecorder.AudioSource.CAMCORDER.setVideoSource()– ustaw źródło wideo, użyjMediaRecorder.VideoSource.CAMERA.- Ustaw format wyjściowy i kodowanie filmu. W przypadku Androida 2.2 (poziom interfejsu API 8) i nowszych wersji użyj metody
MediaRecorder.setProfilei pobierz instancję profilu za pomocąCamcorderProfile.get(). W przypadku wersji Androida starszych niż 2.2 musisz ustawić format wyjściowy filmu i parametry kodowania:setOutputFormat()– ustaw format wyjściowy, określ ustawienie domyślne lubMediaRecorder.OutputFormat.MPEG_4.setAudioEncoder()– ustaw typ kodowania dźwięku, określ ustawienie domyślne lubMediaRecorder.AudioEncoder.AMR_NB.setVideoEncoder()– ustaw typ kodowania wideo, określ ustawienie domyślne lubMediaRecorder.VideoEncoder.MPEG_4_SP.
setOutputFile()– ustaw plik wyjściowy, użyjgetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()z przykładowej metody w sekcji Zapisywanie plików multimedialnych.setPreviewDisplay()– określ element układu podgląduSurfaceViewdla aplikacji. Użyj tego samego obiektu, który został określony w przypadku Connect Preview.
Uwaga: te metody konfiguracji
MediaRecordermusisz wywołać w tej kolejności. W przeciwnym razie w aplikacji wystąpią błędy i nagrywanie się nie powiedzie. - Przygotowanie MediaRecorder – przygotuj
MediaRecorderz podanymi ustawieniami konfiguracji, wywołującMediaRecorder.prepare(). - Uruchom MediaRecorder – rozpocznij nagrywanie filmu, wywołując
MediaRecorder.start().
- Unlock the Camera – odblokowuje aparat, aby umożliwić korzystanie z niego przez
- Zatrzymywanie nagrywania filmu – aby zakończyć nagrywanie filmu, wywołaj te metody w podanej kolejności:
- Zatrzymaj MediaRecorder – zatrzymaj nagrywanie filmu, wywołując
MediaRecorder.stop(). - Resetowanie MediaRecorder – opcjonalnie możesz usunąć ustawienia konfiguracji z rejestratora, wywołując
MediaRecorder.reset(). - Zwolnij MediaRecorder – zwolnij
MediaRecorder, wywołującMediaRecorder.release(). - Blokowanie kamery – zablokuj kamerę, aby przyszłe sesje
MediaRecordermogły z niej korzystać, wywołującCamera.lock(). Od Androida 4.0 (interfejs API na poziomie 14) to wywołanie nie jest wymagane, chyba że wywołanieMediaRecorder.prepare()się nie powiedzie.
- Zatrzymaj MediaRecorder – zatrzymaj nagrywanie filmu, wywołując
- Zatrzymywanie podglądu – gdy aktywność przestanie korzystać z aparatu, zatrzymaj podgląd za pomocą metody
Camera.stopPreview(). - Zwolnij aparat – zwolnij aparat, aby inne aplikacje mogły go używać, wywołując
Camera.release().
Uwaga: możesz używać MediaRecorder bez wcześniejszego tworzenia podglądu z kamery i pominąć kilka pierwszych kroków tego procesu. Użytkownicy zwykle wolą jednak zobaczyć podgląd przed rozpoczęciem nagrywania, dlatego nie omawiamy tutaj tego procesu.
Wskazówka: jeśli aplikacja jest zwykle używana do nagrywania filmów, przed rozpoczęciem podglądu ustaw setRecordingHint(boolean) na true. To ustawienie może pomóc skrócić czas potrzebny na rozpoczęcie nagrywania.
Konfigurowanie MediaRecorder
Jeśli do nagrywania filmów używasz klasy MediaRecorder, musisz wykonać czynności konfiguracyjne w określonej kolejności, a następnie wywołać metodę MediaRecorder.prepare(), aby sprawdzić i wdrożyć konfigurację. Poniższy przykładowy kod pokazuje, jak prawidłowo skonfigurować i przygotować klasę MediaRecorder do nagrywania filmów.
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; }
W przypadku wersji Androida starszych niż 2.2 (poziom interfejsu API 8) musisz ustawić parametry formatu wyjściowego i formatów kodowania bezpośrednio, zamiast używać CamcorderProfile. To podejście zostało przedstawione w tym kodzie:
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);
Poniższe parametry nagrywania filmów dla MediaRecorder mają ustawienia domyślne, ale możesz je dostosować do swojej aplikacji:
setVideoEncodingBitRate()setVideoSize()setVideoFrameRate()setAudioEncodingBitRate()setAudioChannels()setAudioSamplingRate()
Uruchamianie i zatrzymywanie MediaRecorder
Podczas rozpoczynania i zatrzymywania nagrywania filmu za pomocą klasy MediaRecorder musisz przestrzegać określonej kolejności, jak opisano poniżej.
- Odblokuj aparat za pomocą
Camera.unlock() - Skonfiguruj
MediaRecorderzgodnie z powyższym przykładem kodu. - Rozpocznij nagrywanie za pomocą
MediaRecorder.start() - Nagrywanie filmu
- Zatrzymaj nagrywanie za pomocą
MediaRecorder.stop() - Zwolnij nagrywarkę multimediów za pomocą
MediaRecorder.release() - Zablokuj kamerę za pomocą
Camera.lock()
Poniższy przykładowy kod pokazuje, jak skonfigurować przycisk, aby prawidłowo rozpoczynać i zatrzymywać nagrywanie filmu za pomocą aparatu i klasy MediaRecorder.
Uwaga: podczas nagrywania filmu nie zwalniaj aparatu, bo podgląd zostanie zatrzymany.
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 } } } } );
Uwaga: w powyższym przykładzie metoda prepareVideoRecorder() odnosi się do przykładowego kodu pokazanego w sekcji Konfigurowanie MediaRecorder. Ta metoda blokuje kamerę, konfiguruje i przygotowuje instancję MediaRecorder.
Zwalnianie aparatu
Aparaty to zasób współdzielony przez aplikacje na urządzeniu. Aplikacja może korzystać z aparatu po uzyskaniu instancji Camera. Musisz zachować szczególną ostrożność, aby zwolnić obiekt aparatu, gdy aplikacja przestanie go używać i gdy zostanie wstrzymana (Activity.onPause()). Jeśli aplikacja nie zwolni prawidłowo aparatu, wszystkie kolejne próby uzyskania do niego dostępu, w tym przez Twoją aplikację, zakończą się niepowodzeniem i mogą spowodować zamknięcie Twojej lub innych aplikacji.
Aby zwolnić instancję obiektu Camera, użyj metody Camera.release(), jak pokazano w poniższym przykładowym kodzie.
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; } } }
Uwaga: jeśli aplikacja nie zwolni prawidłowo aparatu, wszystkie kolejne próby uzyskania do niego dostępu, w tym przez Twoją aplikację, zakończą się niepowodzeniem i mogą spowodować zamknięcie Twojej lub innych aplikacji.
Zapisywanie plików multimedialnych
Pliki multimedialne utworzone przez użytkowników, takie jak zdjęcia i filmy, powinny być zapisywane w katalogu pamięci zewnętrznej urządzenia (na karcie SD), aby oszczędzać miejsce w systemie i umożliwić użytkownikom dostęp do tych plików bez urządzenia. Pliki multimedialne można zapisywać w wielu różnych katalogach na urządzeniu, ale jako deweloper musisz wziąć pod uwagę tylko 2 standardowe lokalizacje:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) – ta metoda zwraca standardową, udostępnioną i zalecaną lokalizację do zapisywania zdjęć i filmów. Ten katalog jest udostępniony (publiczny), więc inne aplikacje mogą łatwo wykrywać, odczytywać, zmieniać i usuwać zapisane w nim pliki. Jeśli użytkownik odinstaluje aplikację, pliki multimedialne zapisane w tej lokalizacji nie zostaną usunięte. Aby uniknąć zakłócania działania istniejących zdjęć i filmów użytkowników, utwórz w tym katalogu podkatalog na pliki multimedialne aplikacji, jak pokazano w przykładowym kodzie poniżej. Ta metoda jest dostępna w Androidzie 2.2 (poziom interfejsu API 8). Informacje o odpowiednikach wywołań we wcześniejszych wersjach interfejsu API znajdziesz w artykule Zapisywanie udostępnionych plików.Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) – ta metoda zwraca standardową lokalizację do zapisywania zdjęć i filmów powiązanych z aplikacją. Jeśli aplikacja zostanie odinstalowana, wszystkie pliki zapisane w tej lokalizacji zostaną usunięte. W tej lokalizacji nie są egzekwowane zabezpieczenia plików, więc inne aplikacje mogą je odczytywać, zmieniać i usuwać.
Poniższy przykładowy kod pokazuje, jak utworzyć lokalizację File lub Uri dla pliku multimedialnego, którego można użyć podczas wywoływania aparatu urządzenia za pomocą Intent lub w ramach tworzenia aplikacji aparatu.
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; }
Uwaga: Environment.getExternalStoragePublicDirectory() jest dostępny na Androidzie 2.2 (poziom API 8) lub nowszym. Jeśli kierujesz reklamy na urządzenia ze starszymi wersjami Androida, użyj Environment.getExternalStorageDirectory(). Więcej informacji znajdziesz w artykule Zapisywanie udostępnionych plików.
Aby identyfikator URI obsługiwał profile służbowe, najpierw
przekonwertuj identyfikator URI pliku na identyfikator URI treści. Następnie dodaj identyfikator URI treści do EXTRA_OUTPUT elementu Intent.
Więcej informacji o zapisywaniu plików na urządzeniu z Androidem znajdziesz w artykule Przechowywanie danych.
Funkcje aparatu
Android obsługuje szeroką gamę funkcji aparatu, którymi można sterować za pomocą aplikacji aparatu, takich jak format obrazu, tryb lampy błyskowej, ustawienia ostrości i wiele innych. W tej sekcji wymieniono typowe funkcje aparatu i krótko omówiono, jak z nich korzystać. Dostęp do większości funkcji aparatu i ich ustawień można uzyskać za pomocą obiektu Camera.Parameters. Istnieje jednak kilka ważnych funkcji, które wymagają czegoś więcej niż prostych ustawień w Camera.Parameters. Te funkcje są opisane w tych sekcjach:
Ogólne informacje o korzystaniu z funkcji sterowanych za pomocą Camera.Parameters znajdziesz w sekcji Korzystanie z funkcji aparatu. Więcej informacji o korzystaniu z funkcji kontrolowanych przez obiekt parametrów kamery znajdziesz w dokumentacji API, do której prowadzą linki na liście funkcji poniżej.
Tabela 1. Typowe funkcje aparatu posortowane według poziomu interfejsu API Androida, na którym zostały wprowadzone.
| Funkcja | Poziom API | Opis |
|---|---|---|
| Wykrywanie twarzy | 14 | Identyfikowanie twarzy na zdjęciu i wykorzystywanie ich do ustawiania ostrości, pomiaru i balansu bieli |
| Obszary pomiaru | 14 | Określ co najmniej 1 obszar na obrazie, aby obliczyć balans bieli |
| Najważniejsze obszary | 14 | Ustawianie co najmniej 1 obszaru na obrazie, na którym ma być ustawiana ostrość |
White Balance Lock |
14 | Zatrzymywanie i rozpoczynanie automatycznego dostosowywania balansu bieli |
Exposure Lock |
14 | Zatrzymywanie i rozpoczynanie automatycznego dostosowywania ekspozycji |
Video Snapshot |
14 | Robienie zdjęcia podczas nagrywania filmu (przechwytywanie klatek) |
| Film poklatkowy | 11 | Nagrywanie klatek z ustawionymi opóźnieniami w celu nagrania filmu w trybie poklatkowym |
Multiple Cameras |
9 | obsługę więcej niż 1 aparatu na urządzeniu, w tym przedniego i tylnego; |
Focus Distance |
9 | Podaje odległości między aparatem a obiektami, które wydają się być ostre. |
Zoom |
8 | Ustawianie powiększenia obrazu |
Exposure
Compensation |
8 | Zwiększanie lub zmniejszanie poziomu ekspozycji na światło |
GPS Data |
5 | dołączanie do obrazu danych o położeniu geograficznym lub ich pomijanie; |
White Balance |
5 | Ustaw tryb balansu bieli, który wpływa na wartości kolorów na zrobionym zdjęciu |
Focus Mode |
5 | Ustawianie sposobu ustawiania ostrości przez aparat na obiekcie, np. automatycznego, stałego, makro lub nieskończoności |
Scene Mode |
5 | Zastosuj gotowy tryb do określonych rodzajów fotografii, takich jak noc, plaża, śnieg czy sceny przy świecach. |
JPEG Quality |
5 | Ustaw poziom kompresji obrazu JPEG, który zwiększa lub zmniejsza jakość i rozmiar pliku wyjściowego obrazu. |
Flash Mode |
5 | Włączanie i wyłączanie lampy błyskowej lub używanie ustawienia automatycznego |
Color Effects |
5 | Zastosuj efekt kolorystyczny do zrobionego zdjęcia, np. czarno-biały, sepia lub negatyw. |
Anti-Banding |
5 | Zmniejsza efekt pasmowania w gradientach kolorów spowodowany kompresją JPEG |
Picture Format |
1 | Określ format pliku obrazu |
Picture Size |
1 | Określ wymiary zapisanego zdjęcia w pikselach. |
Uwaga: te funkcje nie są obsługiwane na wszystkich urządzeniach ze względu na różnice sprzętowe i implementację oprogramowania. Informacje o sprawdzaniu dostępności funkcji na urządzeniu, na którym działa aplikacja, znajdziesz w artykule Sprawdzanie dostępności funkcji.
Sprawdzanie dostępności funkcji
Pierwszą rzeczą, którą należy zrozumieć, gdy zaczynasz korzystać z funkcji aparatu na urządzeniach z Androidem, jest to, że nie wszystkie funkcje aparatu są obsługiwane na wszystkich urządzeniach. Ponadto urządzenia, które obsługują daną funkcję, mogą obsługiwać ją na różnych poziomach lub z różnymi opcjami. Dlatego podczas tworzenia aplikacji aparatu musisz zdecydować, jakie funkcje aparatu chcesz obsługiwać i na jakim poziomie. Po podjęciu tej decyzji należy zaplanować uwzględnienie w aplikacji aparatu kodu, który sprawdza, czy sprzęt urządzenia obsługuje te funkcje, i w razie braku obsługi odpowiednio reaguje.
Dostępność funkcji aparatu możesz sprawdzić, pobierając instancję obiektu parametrów aparatu i sprawdzając odpowiednie metody. Poniższy przykładowy kod pokazuje, jak uzyskać obiekt Camera.Parameters i sprawdzić, czy aparat obsługuje funkcję autofokusa:
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 }
W przypadku większości funkcji aparatu możesz użyć metody pokazanej powyżej. Obiekt Camera.Parameters udostępnia metodę getSupported...(), is...Supported() lub getMax...(), która pozwala określić, czy (i w jakim stopniu) funkcja jest obsługiwana.
Jeśli aplikacja wymaga określonych funkcji aparatu do prawidłowego działania, możesz je dodać do pliku manifestu aplikacji. Gdy zadeklarujesz korzystanie z określonych funkcji aparatu, takich jak lampa błyskowa i autofokus, Google Play uniemożliwi instalowanie aplikacji na urządzeniach, które nie obsługują tych funkcji. Listę funkcji aparatu, które można zadeklarować w pliku manifestu aplikacji, znajdziesz w dokumentacji funkcji w pliku manifestu.
Korzystanie z funkcji aparatu
Większość funkcji aparatu jest aktywowana i kontrolowana za pomocą obiektu Camera.Parameters. Aby uzyskać ten obiekt, najpierw pobierz instancję obiektu Camera, wywołaj metodę getParameters(), zmień zwrócony obiekt parametru, a następnie ustaw go z powrotem w obiekcie kamery, jak w tym przykładowym kodzie:
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);
Ta technika działa w przypadku prawie wszystkich funkcji aparatu, a większość parametrów można zmienić w dowolnym momencie po uzyskaniu instancji obiektu Camera. Zmiany parametrów są zwykle widoczne dla użytkownika od razu w podglądzie aparatu w aplikacji.
Po stronie oprogramowania zmiany parametrów mogą zacząć obowiązywać dopiero po kilku klatkach, gdy sprzęt aparatu przetworzy nowe instrukcje, a następnie wyśle zaktualizowane dane obrazu.
Ważne: niektórych funkcji aparatu nie można dowolnie zmieniać. W szczególności zmiana rozmiaru lub orientacji podglądu z kamery wymaga najpierw zatrzymania podglądu, zmiany jego rozmiaru, a następnie ponownego uruchomienia. Począwszy od Androida 4.0 (poziom interfejsu API 14), orientację podglądu można zmienić bez ponownego uruchamiania podglądu.
Inne funkcje aparatu wymagają więcej kodu, aby można było je wdrożyć. Są to m.in.:
- Obszary pomiaru i ostrości
- Wykrywanie twarzy
- Film poklatkowy
W sekcjach poniżej znajdziesz krótkie omówienie sposobu wdrażania tych funkcji.
Obszary pomiaru i ostrości
W niektórych sytuacjach automatyczne ustawianie ostrości i pomiar światła mogą nie dawać pożądanych rezultatów. Począwszy od Androida 4.0 (poziom interfejsu API 14), aplikacja aparatu może udostępniać dodatkowe elementy sterujące, które pozwalają aplikacji lub użytkownikom określać obszary obrazu, które mają być używane do określania ustawień ostrości lub poziomu światła, i przekazywać te wartości do sprzętu aparatu w celu wykorzystania ich podczas robienia zdjęć lub nagrywania filmów.
Obszary pomiaru i ostrości działają bardzo podobnie do innych funkcji aparatu, ponieważ sterujesz nimi za pomocą metod w obiekcie Camera.Parameters. Poniższy kod pokazuje, jak ustawić 2 obszary pomiaru światła dla instancji 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);
Obiekt Camera.Area zawiera 2 parametry danych: obiekt Rect do określania obszaru w polu widzenia aparatu oraz wartość wagi, która informuje aparat, jaki poziom ważności powinien mieć ten obszar podczas pomiaru światła lub obliczania ostrości.
Pole Rect w obiekcie Camera.Area opisuje prostokątny kształt zmapowany na siatce o wymiarach 2000 x 2000 jednostek. Współrzędne -1000, -1000 reprezentują lewy górny róg obrazu z kamery, a współrzędne 1000, 1000 – prawy dolny róg, jak pokazano na ilustracji poniżej.
Rysunek 1. Czerwone linie ilustrują układ współrzędnych do określania Camera.Area w podglądzie z kamery. Niebieskie pole pokazuje lokalizację i kształt obszaru kamery z wartościami Rect 333,333,667,667.
Granice tego układu współrzędnych zawsze odpowiadają zewnętrznej krawędzi obrazu widocznego w podglądzie aparatu i nie zmniejszają się ani nie zwiększają wraz z poziomem powiększenia. Podobnie obracanie podglądu obrazu za pomocą przycisku Camera.setDisplayOrientation() nie powoduje ponownego mapowania układu współrzędnych.
Wykrywanie twarzy
W przypadku zdjęć przedstawiających ludzi twarze są zwykle najważniejszą częścią zdjęcia i powinny być używane do określania ostrości i balansu bieli podczas robienia zdjęcia. Platforma Android 4.0 (interfejs API na poziomie 14) udostępnia interfejsy API do identyfikowania twarzy i obliczania ustawień obrazu za pomocą technologii rozpoznawania twarzy.
Uwaga: gdy funkcja wykrywania twarzy jest uruchomiona, setWhiteBalance(String), setFocusAreas(List<Camera.Area>) i setMeteringAreas(List<Camera.Area>) nie działają.
Aby korzystać z funkcji wykrywania twarzy w aplikacji aparatu, musisz wykonać kilka ogólnych czynności:
- Sprawdź, czy urządzenie obsługuje wykrywanie twarzy
- Tworzenie detektora wykrywania twarzy
- Dodawanie detektora wykrywania twarzy do obiektu aparatu
- Rozpocznij wykrywanie twarzy po podglądzie (i po każdym ponownym uruchomieniu podglądu)
Funkcja wykrywania twarzy nie jest obsługiwana na wszystkich urządzeniach. Możesz sprawdzić, czy ta funkcja jest obsługiwana, wywołując getMaxNumDetectedFaces(). Przykład takiego sprawdzenia znajdziesz w metodzie startFaceDetection() poniżej.
Aby otrzymywać powiadomienia i reagować na wykrycie twarzy, aplikacja aparatu musi ustawić detektor zdarzeń wykrywania twarzy. Aby to zrobić, musisz utworzyć klasę detektora, która implementuje interfejs Camera.FaceDetectionListener, jak pokazano w poniższym przykładowym kodzie.
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() ); } } }
Po utworzeniu tej klasy ustaw ją w obiekcie Camera aplikacji, jak pokazano w przykładowym kodzie poniżej:
Kotlin
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Java
camera.setFaceDetectionListener(new MyFaceDetectionListener());
Aplikacja musi uruchamiać funkcję wykrywania twarzy za każdym razem, gdy uruchamiasz (lub ponownie uruchamiasz) podgląd z aparatu. Utwórz metodę uruchamiania wykrywania twarzy, aby móc ją wywoływać w razie potrzeby, jak pokazano w przykładowym kodzie poniżej.
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(); } }
Wykrywanie twarzy musisz uruchamiać za każdym razem, gdy włączasz (lub ponownie włączasz) podgląd z kamery. Jeśli używasz klasy podglądu pokazanej w sekcji Tworzenie klasy podglądu, dodaj metodę startFaceDetection() do metod surfaceCreated() i surfaceChanged() w klasie podglądu, jak pokazano w przykładowym kodzie poniżej.
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()); } }
Uwaga: pamiętaj, aby wywołać tę metodę po wywołaniu startPreview(). Nie próbuj uruchamiać wykrywania twarzy w metodzie onCreate() głównej aktywności aplikacji aparatu, ponieważ na tym etapie wykonywania aplikacji podgląd nie jest dostępny.
Film poklatkowy
Tryb poklatkowy umożliwia użytkownikom tworzenie klipów wideo, które łączą zdjęcia zrobione w odstępie kilku sekund lub minut. Ta funkcja wykorzystuje MediaRecorder do nagrywania obrazów w trybie poklatkowym.
Aby nagrać film w trybie poklatkowym za pomocą MediaRecorder, musisz skonfigurować obiekt nagrywarki tak, jakbyś nagrywał zwykły film, ustawiając liczbę klatek na sekundę na niską wartość i używając jednego z ustawień jakości trybu poklatkowego, jak pokazano w poniższym przykładzie kodu.
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
Te ustawienia należy skonfigurować w ramach większej procedury konfiguracji dla MediaRecorder. Przykładowy kod pełnej konfiguracji znajdziesz w sekcji Konfigurowanie MediaRecorder. Po zakończeniu konfiguracji rozpocznij nagrywanie filmu tak, jakby był to zwykły klip wideo. Więcej informacji o konfigurowaniu i uruchamianiu MediaRecorder znajdziesz w artykule Nagrywanie filmów.
Przykłady Camera2Video i HdrViewfinder pokazują, jak korzystać z interfejsów API opisanych na tej stronie.
Pola kamery, które wymagają uprawnień
Aplikacje na Androida 10 (poziom API 29) lub nowszego muszą mieć uprawnienie CAMERA, aby mieć dostęp do wartości tych pól zwracanych przez metodę getCameraCharacteristics():
LENS_POSE_ROTATIONLENS_POSE_TRANSLATIONLENS_INTRINSIC_CALIBRATIONLENS_RADIAL_DISTORTIONLENS_POSE_REFERENCELENS_DISTORTIONLENS_INFO_HYPERFOCAL_DISTANCELENS_INFO_MINIMUM_FOCUS_DISTANCESENSOR_REFERENCE_ILLUMINANT1SENSOR_REFERENCE_ILLUMINANT2SENSOR_CALIBRATION_TRANSFORM1SENSOR_CALIBRATION_TRANSFORM2SENSOR_COLOR_TRANSFORM1SENSOR_COLOR_TRANSFORM2SENSOR_FORWARD_MATRIX1SENSOR_FORWARD_MATRIX2
Dodatkowy przykładowy kod
Aby pobrać przykładowe aplikacje, zapoznaj się z przykładową aplikacją Camera2Basic i oficjalną przykładową aplikacją CameraX.