Platforma Android zapewnia obsługę różnych aparatów i funkcji aparatu dostępnych na urządzeniach, dzięki czemu możesz robić zdjęcia i nagrywać filmy w aplikacjach. W tym dokumencie omawiamy szybkie i proste sposoby robienia zdjęć i nagrywania filmów oraz zaawansowane metody tworzenia niestandardowych funkcji kamery.
Uwaga: na tej stronie opisaliśmy klasę Camera
, która została wycofana. Zalecamy użycie biblioteki CameraX Jetpack lub, w określonych przypadkach użycia, klasy camera2
. Zarówno aplikacja CameraX, jak i Aparat 2 działają na Androidzie 5.0 (poziom interfejsu API 21) i nowszych.
Zapoznaj się z tymi powiązanymi materiałami:
co należy wziąć pod uwagę
Zanim włączysz w swojej aplikacji korzystanie z kamer na urządzeniach z Androidem, zastanów się, jak będzie ona używać tej funkcji sprzętowej.
- Wymaganie dotyczące aparatu – czy korzystanie z kamery jest tak ważne w Twojej aplikacji, że nie chcesz, by aplikacja była instalowana na urządzeniu, które nie ma kamery? Jeśli tak, zadeklaruj w pliku manifestu wymóg dotyczący kamery.
- Szybkie zdjęcia lub niestandardowy aparat – do czego aplikacja będzie używać aparatu? Chcesz zrobić tylko szybkie zdjęcie lub klip wideo, czy Twoja aplikacja zapewni nowy sposób korzystania z kamer? Jeśli chcesz zrobić zdjęcie lub klip wideo, możesz użyć istniejących aplikacji aparatu. Informacje o opracowaniu spersonalizowanej funkcji aparatu znajdziesz w sekcji Tworzenie aplikacji aparatu.
- Wymagania dotyczące usług działających na pierwszym planie – kiedy aplikacja wchodzi w interakcję z aparatem? Na Androidzie 9 (poziom interfejsu API 28) i nowszych aplikacje działające w tle nie mają dostępu do aparatu. Dlatego używaj aparatu, gdy aplikacja działa na pierwszym planie lub w ramach usługi na pierwszym planie.
- Pamięć – czy obrazy lub filmy generowane przez aplikację są widoczne tylko dla niej lub udostępniane tak, by inne aplikacje, takie jak Galeria czy inne aplikacje multimedialne i społecznościowe, mogły z nich korzystać? Czy zdjęcia i filmy mają być dostępne nawet po odinstalowaniu aplikacji? Informacje o implementowaniu tych opcji znajdziesz w sekcji Zapisywanie plików multimedialnych.
Podstawy
Platforma Androida umożliwia rejestrowanie obrazów i filmów za pomocą interfejsu android.hardware.camera2
API lub aparatuIntent
. Oto odpowiednie zajęcia:
android.hardware.camera2
- Ten pakiet jest podstawowym interfejsem API do sterowania kamerami urządzeń. Można jej używać do robienia zdjęć i nagrywania filmów.
Camera
- Ta klasa to starsza, wycofana wersja interfejsu API do sterowania kamerami urządzeń.
SurfaceView
- Te zajęcia pozwalają wyświetlić użytkownikowi podgląd obrazu na żywo z kamery.
MediaRecorder
- Te zajęcia służą do nagrywania obrazu wideo z kamery.
Intent
- Do rejestrowania obrazów i filmów można używać typu działania intencji
MediaStore.ACTION_IMAGE_CAPTURE
lubMediaStore.ACTION_VIDEO_CAPTURE
bez bezpośredniego użycia obiektuCamera
.
Deklaracje w pliku manifestu
Przed rozpoczęciem programowania aplikacji przy użyciu interfejsu Camera API upewnij się, że plik manifestu zawiera odpowiednie deklaracje umożliwiające korzystanie ze sprzętu do obsługi aparatu i innych powiązanych funkcji.
- Uprawnienia dotyczące aparatu – aplikacja musi prosić o pozwolenie na korzystanie z aparatu urządzenia.
<uses-permission android:name="android.permission.CAMERA" />
Uwaga: jeśli używasz kamery poprzez wywoływanie istniejącej aplikacji, aplikacja nie musi prosić o te uprawnienia.
- Funkcje aparatu – aplikacja musi też deklarować korzystanie z funkcji aparatu, takich jak:
<uses-feature android:name="android.hardware.camera" />
Listę funkcji aparatu znajdziesz w pliku manifestu.
Dodanie funkcji aparatu do pliku manifestu powoduje, że Google Play uniemożliwia instalację Twojej aplikacji na urządzeniach, które nie mają kamery lub nie obsługują jej określonych przez Ciebie funkcji. Więcej informacji o filtrowaniu według funkcji w Google Play znajdziesz w artykule Google Play i filtrowanie oparte na funkcjach.
Jeśli Twoja aplikacja może używać kamery lub jej funkcji do prawidłowego działania, ale jej nie wymaga, określ to w pliku manifestu, dodając atrybut
android:required
i ustawiając dla niego wartośćfalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Uprawnienia do pamięci – aplikacja może zapisywać obrazy i filmy w zewnętrznej pamięci urządzenia (na karcie SD), jeśli jest kierowana na Androida 10 (poziom interfejsu API 29) lub starszego i określa w pliku manifestu te dane:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Uprawnienia do nagrywania dźwięku – aby nagrywać dźwięk za pomocą funkcji nagrywania filmów, aplikacja musi poprosić o pozwolenie na nagrywanie dźwięku.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
Uprawnienia do lokalizacji – jeśli aplikacja dodaje tagi do obrazów według danych GPS o lokalizacji, musisz poprosić o uprawnienie
ACCESS_FINE_LOCATION
. Pamiętaj, że jeśli Twoja aplikacja jest kierowana na Androida 5.0 (poziom interfejsu API 21) lub nowszego, musisz też zadeklarować, że aplikacja korzysta z GPS-a 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 aparatu
Szybkim sposobem na robienie zdjęć i nagrywanie filmów w aplikacji bez konieczności pisania dodatkowego kodu jest użycie klasy Intent
do wywołania istniejącej aplikacji aparatu na Androida.
Szczegółowe informacje znajdziesz w lekcjach szkoleniowych na temat prostego robienia zdjęć i nagrywania filmów.
Tworzenie aplikacji aparatu
Niektórzy deweloperzy mogą wymagać interfejsu aparatu dostosowanego do wyglądu aplikacji lub udostępniającego specjalne funkcje. Napisanie własnego kodu zwiększa atrakcyjność aplikacji dla użytkowników.
Uwaga: ten przewodnik dotyczy starszego, wycofanego interfejsu API Camera
. W przypadku nowych lub zaawansowanych aplikacji aparatów zalecany jest nowszy interfejs API android.hardware.camera2
.
Ogólne kroki w celu utworzenia niestandardowego interfejsu aparatu dla aplikacji są następujące:
- Wykrywanie kamery i uzyskiwanie do niej dostępu – utwórz kod, aby sprawdzić, czy kamery są dostępne, i poprosić o dostęp.
- Utwórz klasę podglądu – utwórz klasę podglądu aparatu, która rozszerza zakres
SurfaceView
i implementuje interfejsSurfaceHolder
. Podczas tych zajęć wyświetla się podgląd obrazów na żywo z kamery. - Utwórz układ podglądu – gdy masz już klasę podglądu aparatu, utwórz układ widoku, który obejmuje odpowiedni podgląd i elementy interfejsu użytkownika.
- Skonfiguruj detektory do przechwytywania – połącz detektory elementów interfejsu, aby rozpocząć nagrywanie obrazu lub filmu w odpowiedzi na działania użytkownika takie jak np. naciśnięcie przycisku.
- Przechwytywanie i zapisywanie plików – skonfiguruj kod do robienia zdjęć lub filmów oraz zapisywania wyników.
- Zwolnij aparat – po użyciu aparatu aplikacja musi prawidłowo go zwolnić, aby mogły zacząć z niego korzystać inne aplikacje.
Sprzęt do kamery to zasób współdzielony, którym należy ostrożnie zarządzać, aby aplikacja nie kolidowała z innymi aplikacjami, które również mogą z niego korzystać. W kolejnych sekcjach omówiono sposób wykrywania sprzętu fotograficznego, prośby o dostęp do aparatu, robienie zdjęć i nagrywania filmów oraz zwalnianie aparatu po zakończeniu pracy z aplikacją.
Uwaga: pamiętaj, aby zwolnić obiekt Camera
, wywołując Camera.release()
, gdy aplikacja przestanie go używać. Jeśli aplikacja nie zwolni aparatu poprawnie, wszystkie kolejne próby uzyskania do niej dostępu, w tym te przez Twoją własną aplikację, zakończą się niepowodzeniem i mogą spowodować wyłączenie aplikacji lub innych aplikacji.
Kamera wykrywająca
Jeśli Twoja aplikacja nie wymaga kamery za pomocą deklaracji w pliku manifestu, sprawdź, czy kamera jest dostępna w czasie działania. Aby to sprawdzić, użyj metody PackageManager.hasSystemFeature()
, jak pokazano w przykładowym kodzie poniżej:
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, np. tylny (do fotografowania) i przedni do rozmów wideo. Android 2.3 (poziom interfejsu API 9) i nowsze umożliwiają sprawdzenie liczby kamer dostępnych na urządzeniu za pomocą metody Camera.getNumberOfCameras()
.
Dostęp do kamer
Jeśli masz pewność, że urządzenie, na którym działa aplikacja, ma kamerę, musisz poprosić o dostęp do niej, uruchamiając wystąpienie Camera
(chyba że używasz zamiaru dostępu do kamery).
Aby uzyskać dostęp do aparatu głównego, użyj metody Camera.open()
. Pamiętaj, aby wykrywać wszystkie wyjątki, jak pokazano w tym kodzie:
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: zawsze sprawdzaj wyjątki, gdy używasz Camera.open()
. Brak sprawdzenia wyjątków oznaczających, że kamera jest używana lub nie istnieje, spowoduje wyłączenie aplikacji przez system.
Na urządzeniach z Androidem 2.3 (interfejs API na poziomie 9) lub nowszym możesz uzyskać dostęp do określonych aparatów za pomocą funkcji Camera.open(int)
. Powyższy przykładowy kod umożliwia dostęp do pierwszego, tylnego aparatu w urządzeniu z większą liczbą aparatów.
Sprawdzam funkcje aparatu
Po uzyskaniu dostępu do aparatu możesz uzyskać więcej informacji o jego możliwościach, korzystając z metody Camera.getParameters()
. Możesz też sprawdzić zwrócony obiekt Camera.Parameters
pod kątem obsługiwanych funkcji. Jeśli korzystasz z 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 czy określić orientację obrazu.
Tworzenie zajęć podglądu
Aby użytkownicy mogli skutecznie robić zdjęcia i nagrywać filmy, muszą widzieć to, co widzi aparat urządzenia. Klasa podglądu z aparatu to właściwość SurfaceView
, która może wyświetlać dane obrazu na żywo z aparatu, dzięki czemu użytkownicy mogą wykadrować i zrobić zdjęcie lub nagrać film.
Ten przykładowy kod pokazuje, jak utworzyć podstawową klasę podglądu aparatu, którą można uwzględnić w układzie View
. Ta klasa implementuje SurfaceHolder.Callback
, aby przechwytywać zdarzenia wywołania zwrotnego na potrzeby tworzenia i niszczenia widoku, które są potrzebne do przypisania danych wejściowych z podglądem 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 aparatu, użyj go w metodzie surfaceChanged()
zgodnie z opisem powyżej. Podczas ustawiania rozmiaru podglądu musisz użyć wartości z getSupportedPreviewSizes()
.
Nie ustawiaj dowolnych wartości w metodzie setPreviewSize()
.
Uwaga: od momentu wprowadzenia funkcji
wielu okien na Androidzie w wersji 7.0 (poziom interfejsu API 24) i nowszych nie możesz już zakładać, że format podglądu jest taki sam jak Twoja aktywność nawet po wywołaniu setDisplayOrientation()
.
W zależności od rozmiaru okna i formatu obrazu może być konieczne dopasowanie szerokiego podglądu aparatu do układu pionowego lub na odwrót, stosując układ letterbox.
Umieszczanie podglądu w układzie
Klasa podglądu z aparatu, np. przedstawiona w poprzedniej sekcji, musi być umieszczona w układzie aktywności razem z innymi elementami interfejsu użytkownika służącymi do robienia zdjęć lub nagrywania filmów. W tej sekcji dowiesz się, jak utworzyć podstawowy układ i działanie na potrzeby podglądu.
Ten kod układu zapewnia bardzo podstawowy widok, którego można używać do wyświetlania podglądu z kamery. W tym przykładzie element FrameLayout
ma być kontenerem klasy podglądu aparatu. Ten typ układu pozwala na nałożenie dodatkowych informacji o obrazie lub elementów sterujących na obraz z podglądu na żywo z kamery.
<?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ń podgląd z aparatu jest w orientacji poziomej. Ten przykładowy układ określa układ poziomy (poziomy), a poniższy kod ustala orientację aplikacji w orientacji poziomej. Aby ułatwić sobie renderowanie podglądu z aparatu, zmień orientację działania podglądu aplikacji na poziomą, dodając do pliku manifestu ten 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.
Od Androida 2.2 (poziom interfejsu API 8) możesz używać metody setDisplayOrientation()
do ustawiania obrotu obrazu podglądu. Aby zmienić orientację podglądu podczas zmiany orientacji telefonu przez użytkownika, w ramach metody surfaceChanged()
klasy podglądu najpierw zatrzymaj podgląd za pomocą Camera.stopPreview()
, zmień orientację, a następnie ponownie uruchom podgląd, używając opcji Camera.startPreview()
.
W aktywności związanej z widokiem kamery dodaj klasę podglądu do elementu FrameLayout
pokazanego w przykładzie powyżej. Działanie kamery musi też odpowiadać, czy kamera uwalnia ją w momencie wstrzymania lub wyłączenia. Poniższy przykład pokazuje, jak zmienić działanie kamery, aby dołączyć klasę podglądu widoczną w artykule 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 powyższym przykładzie odnosi się do metody pokazanej w artykule Dostęp do kamer.
Robienie zdjęć
Po utworzeniu klasy podglądu i układu widoku, w którym chcesz ją wyświetlać, możesz rozpocząć przechwytywanie obrazów w aplikacji. W kodzie aplikacji musisz skonfigurować detektory elementów interfejsu użytkownika, tak aby robiły zdjęcia i reagowały na działanie użytkownika.
Aby pobrać zdjęcie, użyj metody Camera.takePicture()
. Ta metoda wykorzystuje 3 parametry, które odbierają dane z kamery.
Aby odbierać dane w formacie JPEG, musisz zaimplementować interfejs Camera.PictureCallback
, który umożliwi odbieranie danych obrazu i zapisanie ich w pliku. Poniższy kod przedstawia podstawową implementację interfejsu Camera.PictureCallback
w celu zapisywania 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()); } } };
Aby aktywować przechwytywanie obrazu, wywołaj metodę Camera.takePicture()
. Poniższy przykładowy kod pokazuje, jak wywołać tę metodę z 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: użytkownik mPicture
w tym przykładzie odnosi się do przykładowego kodu powyżej.
Uwaga: pamiętaj, aby zwolnić obiekt Camera
, wywołując Camera.release()
, gdy aplikacja przestanie go używać. Informacje o tym, jak zwolnić aparat, znajdziesz w sekcji Zwalnianie aparatu.
Nagrywanie filmów
Nagrywanie filmów za pomocą platformy Android wymaga dokładnego zarządzania obiektem Camera
i koordynacji go z klasą MediaRecorder
. Jeśli chcesz nagrywać filmy za pomocą funkcji Camera
, musisz zarządzać połączeniami Camera.lock()
i Camera.unlock()
, aby zezwolić aplikacji MediaRecorder
na dostęp do sprzętu do obsługi kamery, oprócz połączeń Camera.open()
i Camera.release()
.
Uwaga: od Androida 4.0 (poziom interfejsu API 14) wywołania Camera.lock()
i Camera.unlock()
są zarządzane automatycznie.
W przeciwieństwie do robienia zdjęć aparatem urządzenia, nagrywanie wideo wymaga określonej kolejności rozmów. Aby przygotować się do nagrywania filmów i nagrywać je w aplikacji, musisz wykonać określoną kolejność wykonywania, jak opisano poniżej.
- Otwórz kamerę – za pomocą
Camera.open()
możesz pobrać instancję obiektu kamery. - Connect Preview (Podgląd połączenia) – przygotuj podgląd obrazu na żywo z aparatu, podłączając
SurfaceView
do aparatu za pomocąCamera.setPreviewDisplay()
. - Uruchom podgląd – zadzwoń pod numer
Camera.startPreview()
, aby rozpocząć wyświetlanie obrazów z kamery na żywo. - Rozpocznij nagrywanie filmu – aby nagrać film, musisz wykonać te czynności:
- Odblokuj kamerę –
MediaRecorder
może odblokować aparat, dzwoniąc pod numerCamera.unlock()
. - Skonfiguruj MediaRecorder – wywołaj metody
MediaRecorder
w tej kolejności. Więcej informacji znajdziesz w dokumentacji referencyjnejMediaRecorder
.setCamera()
– ustaw kamerę do nagrywania wideo. Użyj obecnego wystąpienia aplikacjiCamera
.setAudioSource()
– ustaw źródło dźwięku za pomocąMediaRecorder.AudioSource.CAMCORDER
.setVideoSource()
– ustaw źródło filmu za pomocąMediaRecorder.VideoSource.CAMERA
.- Ustaw format wyjściowy i kodowanie wideo. W przypadku Androida 2.2 (poziom interfejsu API 8) lub nowszego użyj metody
MediaRecorder.setProfile
, aby uzyskać instancję profilu za pomocąCamcorderProfile.get()
. W przypadku Androida starszych niż 2.2 ustaw format wyjściowy 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 filmu. Wartość domyślna toMediaRecorder.VideoEncoder.MPEG_4_SP
.
setOutputFile()
– ustaw plik wyjściowy. Użyj metodygetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()
z przykładowej metody w sekcji Zapisywanie plików multimedialnych.setPreviewDisplay()
– określa element układu podgląduSurfaceView
dla aplikacji. Użyj tego samego obiektu określonego dla Connect Preview (Podgląd połączenia).
Uwaga: metody konfiguracji
MediaRecorder
musisz wywoływać w tej kolejności. W przeciwnym razie aplikacja napotka błędy i nie uda się zarejestrować. - Przygotowanie MediaRecorder – przygotuj
MediaRecorder
z podanymi ustawieniami konfiguracji, wywołującMediaRecorder.prepare()
. - Uruchom MediaRecorder – rozpocznij nagrywanie filmu, dzwoniąc pod numer
MediaRecorder.start()
.
- Odblokuj kamerę –
- Zatrzymaj nagrywanie filmu – aby zakończyć nagrywanie filmu, wywołaj te metody:
- Zatrzymaj MediaRecorder – zatrzymaj nagrywanie filmu, dzwoniąc pod numer
MediaRecorder.stop()
. - Reset MediaRecorder (Zresetuj MediaRecorder) – opcjonalnie możesz usunąć ustawienia konfiguracji z nagrywarki, wywołując
MediaRecorder.reset()
. - Release MediaRecorder – zwolnij
MediaRecorder
, wywołującMediaRecorder.release()
. - Zablokuj kamerę – zablokuj kamerę, aby w przyszłych sesjach
MediaRecorder
mogła z niej korzystać, dzwoniąc pod numerCamera.lock()
. Od Androida 4.0 (poziom interfejsu API 14) to wywołanie nie jest wymagane, chyba że wywołanieMediaRecorder.prepare()
się nie powiedzie.
- Zatrzymaj MediaRecorder – zatrzymaj nagrywanie filmu, dzwoniąc pod numer
- Zatrzymywanie podglądu – gdy zakończy się korzystanie z kamery, zatrzymaj podgląd za pomocą polecenia
Camera.stopPreview()
. - Zwolnij aparat – puść aparat, by inne aplikacje mogły z niej korzystać, wywołując
Camera.release()
.
Uwaga: możesz użyć MediaRecorder
bez wcześniejszego tworzenia podglądu aparatu i pominąć pierwsze kroki tego procesu. Użytkownicy zwykle wolą jednak zobaczyć podgląd przed rozpoczęciem nagrywania, więc proces ten nie jest tu omawiany.
Wskazówka: jeśli Twoja aplikacja zwykle używa się do nagrywania filmów, przed uruchomieniem podglądu ustaw setRecordingHint(boolean)
na true
. To ustawienie może przyspieszyć rozpoczęcie nagrywania.
Konfigurowanie funkcji MediaRecorder
Jeśli do nagrywania filmu 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 wideo.
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 wersjach starszych niż 2.2 (poziom interfejsu API 8) należy bezpośrednio ustawiać parametry formatu wyjściowego i formatów kodowania, a nie używać właściwości CamcorderProfile
. To podejście przedstawia ten kod:
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);
Te parametry nagrywania wideo w funkcji MediaRecorder
są określone domyślnie, ale możesz je dostosować do swojej aplikacji:
setVideoEncodingBitRate()
setVideoSize()
setVideoFrameRate()
setAudioEncodingBitRate()
setAudioChannels()
setAudioSamplingRate()
Uruchamianie i zatrzymywanie MediaRecorder
Rozpoczynając i zatrzymując nagrywanie wideo za pomocą klasy MediaRecorder
, musisz przestrzegać określonej kolejności podanej poniżej.
- Odblokuj aparat, używając aplikacji
Camera.unlock()
- Skonfiguruj
MediaRecorder
w sposób pokazany w powyższym przykładzie kodu - Zacznij nagrywanie za pomocą aplikacji
MediaRecorder.start()
- Nagraj film
- Zatrzymaj nagrywanie za pomocą aplikacji
MediaRecorder.stop()
- Zwolnij nagrywanie multimediów, używając urządzenia
MediaRecorder.release()
- Zablokuj kamerę za pomocą:
Camera.lock()
Poniższy przykładowy kod pokazuje, jak podłączyć przycisk, aby prawidłowo rozpocząć i zatrzymać nagrywanie filmu za pomocą kamery i klasy MediaRecorder
.
Uwaga: podczas nagrywania filmu nie puszczaj kamery, bo w przeciwnym razie 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 artykule Konfigurowanie usługi MediaRecorder. Ta metoda umożliwia zablokowanie kamery oraz skonfigurowanie i przygotowanie instancji MediaRecorder
.
Zwalnianie aparatu
Aparaty to zasób, który jest udostępniany przez aplikacje na urządzeniu. Aplikacja może korzystać z kamery po otrzymaniu wystąpienia Camera
. Szczególnie należy zachować ostrożność, aby zwolnić obiekt kamery, gdy aplikacja przestanie jej używać oraz gdy aplikacja zostanie wstrzymana (Activity.onPause()
). Jeśli aplikacja nie zwolni kamery prawidłowo, wszystkie kolejne próby uzyskania dostępu do kamery, także przez własną aplikację, zakończą się niepowodzeniem i mogą spowodować wyłączenie aplikacji lub innych aplikacji.
Aby zwolnić wystąpienie obiektu Camera
, użyj metody Camera.release()
, jak pokazano w przykładowym kodzie poniżej.
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 kamery prawidłowo, wszystkie kolejne próby jej uzyskania, w tym te przez własną aplikację, zakończą się niepowodzeniem i mogą spowodować wyłączenie aplikacji lub innych aplikacji.
Zapisuję pliki multimedialne
Pliki multimedialne utworzone przez użytkowników, takie jak zdjęcia czy filmy, powinny być zapisywane w zewnętrznym katalogu pamięci masowej (na karcie SD), aby zaoszczędzić miejsce w systemie i umożliwić użytkownikom dostęp do nich bez urządzenia. Pliki multimedialne zapisane na urządzeniu można zapisywać na urządzeniu w różnych lokalizacjach, ale istnieją tylko 2 standardowe lokalizacje.
Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_PICTURES
) – ta metoda zwraca standardową, udostępnianą 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ć pliki zapisane w tej lokalizacji. Jeśli aplikacja zostanie odinstalowana przez użytkownika, 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 w przykładzie poniżej. Ta metoda jest dostępna w Androidzie 2.2 (poziom interfejsu API 8). W przypadku równoważnych wywołań we wcześniejszych wersjach interfejsu API przeczytaj artykuł Zapisywanie plików udostępnionych.Context.getExternalFilesDir
(Environment.DIRECTORY_PICTURES
) – ta metoda zwraca standardową lokalizację do zapisywania zdjęć i filmów powiązanych z Twoją aplikacją. Jeśli Twoja aplikacja zostanie odinstalowana, wszystkie pliki zapisane w tej lokalizacji zostaną usunięte. Zabezpieczenia nie są egzekwowane w przypadku plików w tej lokalizacji, a inne aplikacje mogą je odczytywać, zmieniać i usuwać.
Poniższy przykładowy kod pokazuje, jak utworzyć lokalizację File
lub Uri
na potrzeby pliku multimedialnego, której można używać podczas wywoływania kamery urządzenia za pomocą interfejsu Intent
lub w ramach tworzenia aplikacji Aparat.
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: interfejs Environment.getExternalStoragePublicDirectory()
jest dostępny na urządzeniach z Androidem 2.2 (interfejs API na poziomie 8) lub nowszym. Jeśli kierujesz reklamy na urządzenia z wcześniejszymi wersjami Androida, użyj parametru 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 szeroki zakres funkcji aparatu, którymi możesz sterować za pomocą aplikacji – takich jak format obrazu, tryb lampy błyskowej, ustawienia ostrości i wiele innych. W tej sekcji wymieniono popularne funkcje aparatu i pokrótce omówimy, jak z nich korzystać. Dostęp do większości funkcji kamery można uzyskać i skonfigurować za pomocą obiektu Camera.Parameters
. Jest jednak kilka ważnych funkcji, które wymagają nie tylko prostych ustawień w Camera.Parameters
. Te funkcje są omówione w następujących sekcjach:
Ogólne informacje o korzystaniu z funkcji kontrolowanych przez Camera.Parameters
znajdziesz w sekcji Korzystanie z funkcji kamery. Więcej informacji o korzystaniu z funkcji kontrolowanych przez obiekt parametrów kamery znajdziesz, klikając na poniższej liście linki do dokumentacji API.
Cecha | Poziom API | Opis |
---|---|---|
Wykrywanie twarzy | 14 | Identyfikuj ludzkie twarze na zdjęciu i używaj ich do regulacji ostrości, pomiaru i balansu bieli |
Obszary pomiaru | 14 | Określ co najmniej jeden obszar na obrazie do obliczenia balansu bieli |
Obszary specjalizacji | 14 | Ustawianie jednego lub większej liczby obszarów na obrazie, które mają być używane jako ostrość |
White Balance Lock |
14 | Włączanie i wyłączanie automatycznej korekty balansu bieli |
Exposure Lock |
14 | Wyłączanie i włączanie automatycznej korekty ekspozycji |
Video Snapshot |
14 | Robienie zdjęcia podczas nagrywania filmu (zbieranie klatek) |
Film poklatkowy | 11 | Nagrywaj klatki z określonymi opóźnieniami, aby nagrać film poklatkowy. |
Multiple Cameras |
9 | Obsługa więcej niż jednej kamery w urządzeniu, w tym aparatów przednich i tylnych |
Focus Distance |
9 | Zgłasza odległość między aparatem a ostrymi obiektami |
Zoom |
8 | Ustaw powiększenie obrazu |
Exposure
Compensation |
8 | Zwiększ lub zmniejsz poziom ekspozycji na światło |
GPS Data |
5 | Dołącz lub pomiń dane lokalizacji geograficznej |
White Balance |
5 | Ustaw tryb balansu bieli, który wpływa na wartości kolorów na robionym zdjęciu |
Focus Mode |
5 | Ustaw ostrość ostrości na obiekcie – automatycznie, na stałe, w trybie makro lub w nieskończoności. |
Scene Mode |
5 | Stosuj tryb gotowych ustawień w określonych sytuacjach, np. w nocy, na plaży, na śniegu czy przy świecach. |
JPEG Quality |
5 | Ustaw poziom kompresji obrazu JPEG, by zwiększyć lub zmniejszyć jakość i rozmiar wyjściowego pliku |
Flash Mode |
5 | Włączanie i wyłączanie lampy błyskowej oraz korzystanie z ustawień automatycznych |
Color Effects |
5 | Zastosuj efekt koloru do zdjęcia, np. czarno-biały, odcień sepii lub negatyw. |
Anti-Banding |
5 | Zmniejsza efekt pasma w gradientach kolorów dzięki kompresji JPEG |
Picture Format |
1 | Określ format pliku zdjęcia. |
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 pod względem sprzętu i implementacji oprogramowania. Informacje o sprawdzaniu dostępności funkcji na urządzeniu, na którym działa Twoja aplikacja, znajdziesz w sekcji Sprawdzanie dostępności funkcji.
Sprawdzam dostępność funkcji
Przed rozpoczęciem korzystania z funkcji aparatu na urządzeniu z Androidem należy pamiętać, że nie wszystkie funkcje aparatu są obsługiwane na każdym urządzeniu. Ponadto urządzenia, które obsługują określone funkcje, mogą obsługiwać je na różnych poziomach lub za pomocą innych opcji. Jednym z elementów procesu decyzyjnego podczas tworzenia aplikacji jest podjęcie decyzji, które funkcje kamery mają być obsługiwane i na jakim poziomie. Po podjęciu takiej decyzji umieść w aplikacji kod, który sprawdza, czy sprzęt obsługuje te funkcje, i nie działa w pełni, jeśli dana funkcja jest niedostępna.
Dostępność funkcji kamery możesz sprawdzać, pobierając wystąpienie obiektu parametrów kamery 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 kamery możesz używać opisanej powyżej metody. Obiekt Camera.Parameters
udostępnia metodę getSupported...()
, is...Supported()
lub getMax...()
pozwalającą określić, czy funkcja jest obsługiwana (i w jakim zakresie).
Jeśli Twoja aplikacja do prawidłowego działania wymaga określonych funkcji aparatu, możesz ich wymagać, dodając je do pliku manifestu. Jeśli deklarujesz korzystanie z określonych funkcji aparatu, takich jak lampa błyskowa i autofokus, Google Play ogranicza możliwość instalowania aplikacji na urządzeniach, które nie obsługują tych funkcji. Listę funkcji aparatu, które można zadeklarować w manifeście aplikacji, znajdziesz w dokumentacji pliku manifestu.
Korzystanie z funkcji aparatu
Większość funkcji kamery włącza się i steruje przy użyciu obiektu Camera.Parameters
. Obiekt uzyskuje się po pobraniu instancji obiektu Camera
, wywołaniu metody getParameters()
, zmianie zwróconego obiektu parametru, a następnie ustawieniu go z powrotem na obiekt kamery, jak w tym przykładzie:
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 metoda sprawdza się w przypadku niemal wszystkich funkcji kamery, 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 natychmiast w podglądzie aparatu w aplikacji.
Po stronie oprogramowania zmiany parametrów mogą być widoczne dopiero po kilku klatkach, gdy aparat aparatu przetwarza nowe instrukcje, a potem wysyła zaktualizowane dane zdjęcia.
Ważne: niektórych funkcji aparatu nie można zmieniać według własnego uznania. Szczególnie zmiana rozmiaru lub orientacji podglądu z aparatu wymaga najpierw zatrzymania podglądu, zmiany rozmiaru podglądu, a następnie ponownego uruchomienia podglądu. Od Androida 4.0 (poziom interfejsu API 14) orientację podglądu można zmienić bez ponownego uruchamiania podglądu.
Implementacja innych funkcji aparatu wymaga więcej kodu. Są to na przykład:
- Pomiary i obszary ostrości
- Wykrywanie twarzy
- Film poklatkowy
W kolejnych sekcjach znajdziesz krótkie omówienie wdrożenia tych funkcji.
Pomiary i obszary ostrości
W niektórych scenariuszach fotograficznych automatyczne ustawianie ostrości i miernik światła może nie dać oczekiwanych wynikó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 na potrzeby określania ustawień ostrości lub jasności i przekazywać te wartości do sprzętu aparatu do robienia zdjęć i nagrywania filmów.
Obszary pomiaru i ostrości działają bardzo podobnie do innych funkcji kamery, ponieważ możesz nimi sterować za pomocą metod dostępnych w obiekcie Camera.Parameters
. Ten kod pokazuje, jak ustawić 2 obszary pomiaru światła w 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
służący do określania obszaru w polu widzenia kamery oraz wartość wagi, która informuje kamerę, jak ważny jest ten obszar podczas obliczania oświetlenia lub pomiaru ostrości.
Pole Rect
w obiekcie Camera.Area
opisuje prostokątny kształt zmapowany na siatkę jednostek 2000 x 2000. Współrzędne -1000, -1000 oznaczają górny i lewy róg obrazu aparatu, a współrzędne 1000 i 1000 – dolny, prawy róg obrazu, tak jak na ilustracji poniżej.
Granice tego układu współrzędnych zawsze odpowiadają zewnętrznej krawędzi obrazu widocznego na podglądzie z aparatu i nie zmniejszają się ani nie rozszerzają wraz z poziomem powiększenia. I podobnie, obrót podglądu obrazu za pomocą funkcji Camera.setDisplayOrientation()
nie powoduje ponownego mapowania układu współrzędnych.
Wykrywanie twarzy
W przypadku zdjęć przedstawiających osoby twarz jest zwykle najważniejszą częścią zdjęcia i to właśnie ona służy do określania ostrości i balansu bieli. Platforma Androida 4.0 (poziom interfejsu API 14) udostępnia interfejsy API do rozpoznawania twarzy i określania ustawień zdjęcia przy użyciu technologii rozpoznawania twarzy.
Uwaga: gdy funkcja wykrywania twarzy jest włączona, funkcje setWhiteBalance(String)
, setFocusAreas(List<Camera.Area>)
i setMeteringAreas(List<Camera.Area>)
nie działają.
Korzystanie z funkcji wykrywania twarzy w aplikacji aparatu wymaga kilku ogólnych czynności:
- Sprawdź, czy urządzenie obsługuje wykrywanie twarzy
- Tworzenie detektora wykrywania twarzy
- Dodaj odbiornik wykrywania twarzy do obiektu aparatu
- Uruchamiaj wykrywanie twarzy po wyświetleniu podglądu (i po każdym ponownym uruchomieniu podglądu)
Funkcja wykrywania twarzy jest niedostępna na niektórych urządzeniach. Aby sprawdzić, czy ta funkcja jest obsługiwana, wywołaj getMaxNumDetectedFaces()
. Przykład kontroli znajdziesz poniżej w przykładowej metodzie startFaceDetection()
.
Aby otrzymywać powiadomienia i reagować na wykrywanie twarzy, aplikacja kamery musi ustawić odbiornik na zdarzenia wykrywania twarzy. Aby to zrobić, musisz utworzyć klasę detektora, która implementuje interfejs Camera.FaceDetectionListener
zgodnie z poniższym przykładowym kodem.
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 przy każdym uruchomieniu (lub ponownym uruchomieniu) podglądu aparatu. Utwórz metodę uruchamiania wykrywania twarzy, aby wywoływać ją zgodnie z potrzebami, 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 uruchamiasz (lub uruchamiasz) podgląd aparatu. Jeśli używasz klasy podglądu pokazanej w artykule 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 metody startPreview()
. Nie próbuj uruchamiać wykrywania twarzy za pomocą metody onCreate()
głównego działania aplikacji aparatu, ponieważ do tego momentu podczas uruchamiania aplikacji podgląd jest niedostępny.
Film poklatkowy
Filmy poklatkowe umożliwiają użytkownikom tworzenie klipów wideo łączących zdjęcia zrobione w odstępie kilku sekund lub minut. Ta funkcja używa metody MediaRecorder
do nagrywania obrazów na potrzeby sekwencji w trybie poklatkowym.
Aby nagrać film poklatkowy za pomocą MediaRecorder
, musisz skonfigurować obiekt nagrywania tak, jakby nagrywał zwykły film, ustawić małą liczbę klatek na sekundę i użyć jednego z ustawień jakości filmu poklatkowego, jak pokazano w przykładzie poniżej.
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 wprowadzić w ramach większej procedury konfiguracji MediaRecorder
. Pełny przykład kodu konfiguracji znajdziesz w artykule Konfigurowanie MediaRecorder. Po zakończeniu konfiguracji możesz rozpocząć nagrywanie wideo tak, jakby nagrywano zwykły klip wideo. Więcej informacji o konfigurowaniu i uruchamianiu MediaRecorder
znajdziesz w artykule o rejestrowaniu filmów.
Przykłady użycia interfejsów Camera2Video i HdrViewfinder dodatkowo pokazują wykorzystanie interfejsów API omówionych na tej stronie.
Pola dotyczące kamery, które wymagają uprawnień
Aplikacje na Androidzie 10 (poziom interfejsu API 29) lub nowszym muszą mieć uprawnienie CAMERA
, aby mieć dostęp do wartości tych pól zwracanych przez metodę getCameraCharacteristics()
:
LENS_POSE_ROTATION
LENS_POSE_TRANSLATION
LENS_INTRINSIC_CALIBRATION
LENS_RADIAL_DISTORTION
LENS_POSE_REFERENCE
LENS_DISTORTION
LENS_INFO_HYPERFOCAL_DISTANCE
LENS_INFO_MINIMUM_FOCUS_DISTANCE
SENSOR_REFERENCE_ILLUMINANT1
SENSOR_REFERENCE_ILLUMINANT2
SENSOR_CALIBRATION_TRANSFORM1
SENSOR_CALIBRATION_TRANSFORM2
SENSOR_COLOR_TRANSFORM1
SENSOR_COLOR_TRANSFORM2
SENSOR_FORWARD_MATRIX1
SENSOR_FORWARD_MATRIX2
Dodatkowy przykładowy kod
Aby pobrać przykładowe aplikacje, przeczytaj przykładową aplikację Camera2 Basic i w artykule Oficjalna przykładowa aplikacja CameraX.