Platforma Androida obsługuje różne aparaty i ich funkcje dostępne na urządzeniach, co umożliwia robienie zdjęć i filmów w aplikacjach. W tym dokumencie omawiamy szybkie i proste podejście do robienia zdjęć i filmowania oraz zaawansowane podejście do tworzenia niestandardowych funkcji aparatu dla użytkowników.
Uwaga: ta strona zawiera opis klasy Camera
, która została wycofana. Zalecamy korzystanie z biblioteki Jetpack CameraX lub, w przypadku konkretnych zastosowań, z klasy camera2
. Zarówno CameraX, jak i Camera2 działają na Androidzie 5.0 (poziom interfejsu API 21) lub nowszym.
Zapoznaj się z tymi materiałami:
co należy wziąć pod uwagę
Zanim zezwolisz aplikacji na korzystanie z kamer na urządzeniach z Androidem, zastanów się, w jaki sposób 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 instalowana na urządzeniach bez aparatu? Jeśli tak, zadeklaruj wymagania dotyczące kamery w pliku manifestu.
- Szybkie zdjęcie lub niestandardowy aparat – jak aplikacja będzie używać aparatu? Czy interesuje Cię tylko robienie zdjęć lub nagrywanie filmów, czy aplikacja ma oferować nowy sposób korzystania z kamer? Aby szybko zrobić zdjęcie lub nagrać film, użyj istniejącej aplikacji do robienia zdjęć. Informacje o tworzeniu niestandardowej 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 kamerą? W Androidzie 9 (poziom interfejsu API 28) i nowszych aplikacje działające w tle nie mają dostępu do kamery. Dlatego aparat powinien być używany, gdy aplikacja jest na pierwszym planie lub gdy jest częścią usługi na pierwszym planie.
- Pamięć – czy obrazy lub filmy generowane przez Twoją aplikację mają być widoczne tylko dla niej, czy 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 zastosować te opcje, zapoznaj się z sekcją Zapisywanie plików multimedialnych.
Podstawy
Platforma Androida obsługuje robienie zdjęć i filmowanie za pomocą interfejsu API android.hardware.camera2
lub aparatu Intent
. Oto odpowiednie klasy:
android.hardware.camera2
- Ten pakiet jest podstawowym interfejsem API do sterowania aparatami w urządzeniach. Możesz go używać do robienia zdjęć lub nagrywania filmów podczas tworzenia aplikacji aparatu.
Camera
- Ta klasa to starszy interfejs API, który został wycofany i służy do sterowania aparatami w urządzeniach.
SurfaceView
- Ta klasa służy do wyświetlania użytkownikowi podglądu na żywo z kamery.
MediaRecorder
- Ta klasa służy do nagrywania filmów z kamery.
Intent
- Aby robić zdjęcia lub nagrywać filmy bez bezpośredniego korzystania z obiektu
Camera
, możesz użyć typu działania intencjiMediaStore.ACTION_IMAGE_CAPTURE
lubMediaStore.ACTION_VIDEO_CAPTURE
.
Deklaracje w pliku manifestu
Zanim zaczniesz tworzyć aplikację z użyciem interfejsu Camera API, sprawdź, czy w pliku manifestu znajdują się odpowiednie deklaracje umożliwiające korzystanie z aparatu i innych powiązanych funkcji.
- Uprawnienia dostępu do aparatu – aplikacja musi prosić o uprawnienia do korzystania z kamery urządzenia.
<uses-permission android:name="android.permission.CAMERA" />
Uwaga: jeśli używasz aparatu przez wywołanie istniejącej aplikacji do obsługi aparatu, Twoja aplikacja nie musi prosić o to uprawnienie.
- Funkcje aparatu – aplikacja musi również deklarować korzystanie z funkcji aparatu, na przykład:
<uses-feature android:name="android.hardware.camera" />
Listę funkcji aparatu znajdziesz w pliku manifestu w dokumentacji funkcji.
Dodanie funkcji aparatu do pliku manifestu powoduje, że Google Play uniemożliwia instalację aplikacji na urządzeniach, które nie mają aparatu lub nie obsługują określonych funkcji aparatu. Więcej informacji o filtrowaniu w Google Play na podstawie funkcji znajdziesz w artykule Filtrowanie w Google Play na podstawie funkcji.
Jeśli aplikacja może używać aparatu lub jego funkcji, ale nie wymaga tego, należy to określić w pliku manifestu, dodając atrybut
android:required
i przypisując mu wartośćfalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Uprawnienie dostępu do pamięci – aplikacja może zapisywać obrazy lub filmy na zewnętrznej pamięci urządzenia (karcie SD), jeśli jest przeznaczona na Androida 10 (poziom interfejsu API 29) lub niższą i określa w manifeście te informacje.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Uprawnienia do nagrywania dźwięku – aby nagrywać dźwięk podczas przechwytywania wideo, aplikacja musi poprosić o uprawnienia do przechwytywania dźwięku.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
Dostęp do lokalizacji – jeśli aplikacja taguje zdjęcia informacjami o lokalizacji GPS, 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 korzysta z usługi GPS na urządzeniu:<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 pozyskiwaniu lokalizacji użytkownika znajdziesz w artykule Strategie dotyczące lokalizacji.
Korzystanie z dotychczasowych 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 dodatkowego kodu jest użycie Intent
do wywołania istniejącej aplikacji aparatu na Androidzie.
Szczegóły znajdziesz w lekcji Proste fotografowanie i Proste nagrywanie filmów.
Tworzenie aplikacji aparatu
Niektórzy deweloperzy mogą wymagać interfejsu aparatu dostosowującego się do wyglądu aplikacji lub oferującego specjalne funkcje. Stworzenie własnego kodu do robienia zdjęć może zapewnić użytkownikom bardziej atrakcyjne wrażenia.
Uwaga: poniższy przewodnik dotyczy starszego, wycofanego interfejsu API Camera
. W przypadku nowych lub zaawansowanych aplikacji do obsługi aparatu zalecamy użycie nowszego interfejsu android.hardware.camera2
API.
Ogólne czynności związane z tworzeniem niestandardowego interfejsu aparatu w aplikacji:
- Wykrywanie kamery i dostęp do niej – utwórz kod, aby sprawdzić, czy i jakie kamery są dostępne, i poproś o dostęp.
- Tworzenie klasy podglądu – tworzy klasę podglądu kamery, która rozszerza klasę
SurfaceView
i implementuje interfejsSurfaceHolder
. Ta klasa wyświetla podgląd obrazu na żywo z kamery. - Utwórz układ podglądu – gdy masz już klasę podglądu kamery, utwórz układ widoku, który zawiera podgląd i wybrane przez Ciebie elementy interfejsu.
- Konfigurowanie odbiorników w przypadku funkcji rejestrowania – połącz odbiorniki z elementami sterującymi interfejsu, aby rozpocząć rejestrowanie obrazu lub filmu w odpowiedzi na działania użytkownika, np. naciśnięcie przycisku.
- Zapisywanie plików – skonfiguruj kod do przechwytywania zdjęć lub filmów i zapisywania wyników.
- Zwolnij kamerę – po użyciu kamery aplikacja musi ją prawidłowo zwolnić do użycia przez inne aplikacje.
Aparat to zasób współdzielony, którym należy zarządzać, aby aplikacja nie kolidowała z innymi aplikacjami, które również mogą z niego korzystać. W następnych sekcjach znajdziesz informacje o tym, jak wykrywać sprzęt kamery, jak prosić o dostęp do kamery, jak robić zdjęcia lub nagrywać filmy oraz jak zwalniać kamerę, gdy aplikacja jej nie używa.
Uwaga: gdy aplikacja skończy korzystać z obiektu Camera
, pamiętaj, aby go zwolnić, wywołując metodę Camera.release()
. Jeśli aplikacja nie zwolni prawidłowo kamery, wszystkie kolejne próby uzyskania dostępu do kamery, w tym te przez Twoją aplikację, zakończą się niepowodzeniem i mogą spowodować zamknięcie Twojej aplikacji lub innych aplikacji.
Wykrywanie aparatu
Jeśli aplikacja nie wymaga kamery, o czym nie informuje w deklaracji w pliku manifestu, sprawdź, czy kamera jest dostępna w czasie działania. Aby wykonać tę kontrolę, 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 aparat do robienia zdjęć i przedni aparat do rozmów wideo. Android 2.3 (interfejs API na poziomie 9) i nowsze umożliwia 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 kamerę, musisz poprosić o dostęp do niej, uzyskując wystąpienie klasy Camera
(chyba że używasz intencji dostępu do kamery).
Aby uzyskać dostęp do głównego aparatu, użyj metody Camera.open()
i zachowaj wszystkie wyjątki, jak pokazano w poniższym 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 podczas korzystania z Camera.open()
. Jeśli nie sprawdzisz wyjątków, a kamera jest używana lub nie istnieje, system wyłączy aplikację.
Na urządzeniach z Androidem 2.3 (poziom interfejsu API 9) lub nowszym możesz uzyskać dostęp do określonych kamer za pomocą Camera.open(int)
. Przykładowy kod powyżej uzyska dostęp do pierwszego tylnego aparatu na urządzeniu z większą liczbą aparatów.
Sprawdzanie funkcji aparatu
Po uzyskaniu dostępu do kamery możesz uzyskać więcej informacji o jej możliwościach, korzystając z metody Camera.getParameters()
i sprawdzając obsługiwane możliwości zwróconego obiektu Camera.Parameters
. Jeśli używasz poziomu interfejsu API 9 lub nowszego, możesz użyć parametru Camera.getCameraInfo()
, aby określić, czy aparat znajduje się z przodu czy z tyłu urządzenia, oraz orientację obrazu.
Tworzenie zajęć w wersji przedpremierowej
Aby użytkownicy mogli skutecznie robić zdjęcia lub nagrywać filmy, muszą widzieć to, co widzi aparat urządzenia. Klasa podglądu aparatu to SurfaceView
, która może wyświetlać dane obrazu na żywo pochodzące z aparatu, aby użytkownicy mogli ustawić kadr i zrobić zdjęcie lub nagrać film.
Poniższy 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 rejestrować zdarzenia wywołania zwrotnego dotyczące tworzenia i usuwania widoku, które są potrzebne do przypisania podglądu 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ć określony rozmiar podglądu aparatu, użyj metody surfaceChanged()
, jak opisano w komentarzach powyżej. Podczas ustawiania rozmiaru podglądu musisz użyć wartości z getSupportedPreviewSizes()
.
Nie ustawiaj dowolnych wartości w metodzie setPreviewSize()
.
Uwaga:
po wprowadzeniu funkcji
Multi-Window w Androidzie 7.0 (interfejs API na poziomie 24) i nowszych nie można już zakładać, że współczynnik kształtu podglądu jest taki sam jak w aplikacji, nawet po wywołaniu funkcji setDisplayOrientation()
.
W zależności od rozmiaru okna i formatu obrazu może być konieczne dopasowanie podglądu kamery do orientacji pionowej lub odwrotnie, korzystając z układu letterbox.
umieszczanie podglądu w układzie.
Klasa podglądu aparatu, taka jak w przykładzie w poprzedniej sekcji, musi być umieszczona w układzie aktywności wraz z innymi elementami interfejsu służącymi do robienia zdjęć lub nagrywania filmów. Z tego sekcji dowiesz się, jak utworzyć podstawowy układ i aktywność na potrzeby podglądu.
Poniższy kod układu zapewnia bardzo podstawowe widok, który można wykorzystać do wyświetlania podglądu aparatu. W tym przykładzie element FrameLayout
ma być kontenerem dla klasy podglądu aparatu. Ten typ układu jest używany, aby można było nakładać dodatkowe informacje lub elementy sterujące na obrazy 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ń domyślną orientacją podglądu aparatu jest orientacja pozioma. Ten przykładowy układ określa układ poziomy (w orientacji poziomej), a podany poniżej kod ustawia orientację aplikacji na poziomą. Aby uprościć renderowanie podglądu w aparacie, zmień orientację aktywności podglądu aplikacji na poziomą, dodając do pliku manifestu odpowiedni 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 kamery nie musi być w orientacji poziomej.
Od wersji 2.2 Androida (poziom API 8) możesz użyć metody setDisplayOrientation()
, aby ustawić obrót obrazu podglądu. Aby zmienić orientację podglądu, gdy użytkownik obróci telefon, w metodzie surfaceChanged()
klasy podglądu najpierw zatrzymaj podgląd za pomocą metody Camera.stopPreview()
, zmień orientację, a następnie uruchom podgląd ponownie za pomocą metody Camera.startPreview()
.
W aktywności dotyczącej widoku kamery dodaj klasę podglądu do elementu FrameLayout
pokazanego w przykładzie powyżej. Aktywność kamery musi też zapewniać, że kamera jest odblokowana, gdy jest wstrzymana lub wyłączona. Z tego przykładu dowiesz się, jak zmodyfikować działanie 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 artykule Dostęp do kamer.
Robienie zdjęć
Gdy utworzysz klasę podglądu i widok, w którym będzie ona wyświetlana, możesz zacząć robić zdjęcia za pomocą aplikacji. W kodzie aplikacji musisz skonfigurować detektory zdarzeń dla elementów sterujących interfejsem użytkownika, aby reagowały na działania użytkownika przez robienie zdjęć.
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 do pliku. Poniższy kod pokazuje podstawowe wdrożenie interfejsu Camera.PictureCallback
do zapisywania obrazu otrzymanego z kamery.
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łanie przechwycenia obrazu przez wywołanie metody 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: element mPicture
w tym przykładzie odnosi się do kodu przykładowego powyżej.
Uwaga: gdy aplikacja skończy korzystać z obiektu Camera
, pamiętaj, aby go zwolnić, wywołując metodę Camera.release()
. Informacje o tym, jak odblokować kamerę, znajdziesz w artykule Odblokowywanie kamery.
Nagrywanie filmów
Nagrywanie wideo za pomocą platformy Android wymaga ostrożnego zarządzania obiektem Camera
i koordynacji z klasą MediaRecorder
. Podczas nagrywania filmów za pomocą Camera
musisz zarządzać połączeniami Camera.lock()
i Camera.unlock()
, aby zezwolić MediaRecorder
na dostęp do aparatu. Dotyczy to również połączeń Camera.open()
i Camera.release()
.
Uwaga: od Androida 4.0 (interfejs API 14) wywołania Camera.lock()
i Camera.unlock()
są zarządzane automatycznie.
W odróżnieniu od robienia zdjęć za pomocą aparatu urządzenia nagrywanie filmów wymaga bardzo szczególnej kolejności czynności. Aby przygotować i zapisać film z aplikacją, musisz wykonać określone czynności w określonej kolejności.
- Otwórz aparat – użyj funkcji
Camera.open()
, aby uzyskać instancję obiektu aparatu. - Połącz podgląd – aby przygotować podgląd obrazu z kamery na żywo, połącz
SurfaceView
z kamerą za pomocąCamera.setPreviewDisplay()
. - Rozpocznij podgląd – wybierz
Camera.startPreview()
, aby wyświetlić obraz z kamery na żywo. - Rozpocznij nagrywanie filmu – aby nagrać film, musisz wykonać te czynności w kolejności:
- Odblokuj kamerę – odblokuj kamerę na potrzeby
MediaRecorder
, dzwoniąc na numerCamera.unlock()
. - Konfigurowanie MediaRecorder – wywołaj te metody
MediaRecorder
w podanej kolejności. Więcej informacji znajdziesz w dokumentacjiMediaRecorder
.setCamera()
– ustaw kamerę, która będzie używana do nagrywania filmów, korzystając z bieżącej instancji aplikacjiCamera
.setAudioSource()
– ustaw źródło dźwięku, używając opcjiMediaRecorder.AudioSource.CAMCORDER
.setVideoSource()
– ustaw źródło filmu, używającMediaRecorder.VideoSource.CAMERA
.- Ustaw format i kodowanie wyjściowe filmu. W przypadku Androida 2.2 (poziom interfejsu API 8) lub nowszego użyj metody
MediaRecorder.setProfile
i pobierz instancję profilu za pomocąCamcorderProfile.get()
. W wersjach Androida starszych niż 2.2 musisz ustawić format wyjściowy wideo 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żywając opcjigetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()
z przykładowej metody w sekcji Zapisywanie plików multimedialnych.setPreviewDisplay()
– określ element układu podgląduSurfaceView
w aplikacji. Użyj tego samego obiektu, który został podany w sekcji Podłącz podgląd.
Uwaga: musisz wywoływać te metody konfiguracji
MediaRecorder
w tej kolejności. W przeciwnym razie aplikacja napotka błędy i nagranie nie zostanie utworzone. - Przygotuj MediaRecorder – przygotuj
MediaRecorder
z podanych ustawień konfiguracji, wywołując funkcjęMediaRecorder.prepare()
. - Rozpocznij MediaRecorder – wywołaj
MediaRecorder.start()
, aby rozpocząć nagrywanie filmu.
- Odblokuj kamerę – odblokuj kamerę na potrzeby
- Zatrzymanie nagrywania filmu – aby zakończyć nagrywanie filmu, wykonaj te czynności w podanej kolejności:
- Zatrzymaj MediaRecorder – zatrzymaj nagrywanie filmu, wywołując funkcję
MediaRecorder.stop()
. - Zresetuj MediaRecorder – opcjonalnie usuń ustawienia konfiguracji z nagrywarki, wywołując funkcję
MediaRecorder.reset()
. - Zwolnij MediaRecorder – zwalniaj
MediaRecorder
, wywołując funkcjęMediaRecorder.release()
. - Zablokuj kamerę – zablokuj kamerę, aby w przyszłości
MediaRecorder
sesje mogły z niej korzystać przez wywołanieCamera.lock()
. Począwszy od Androida 4.0 (poziom interfejsu API 14) wywołanie to nie jest wymagane, chyba że wywołanieMediaRecorder.prepare()
zakończy się niepowodzeniem.
- Zatrzymaj MediaRecorder – zatrzymaj nagrywanie filmu, wywołując funkcję
- Zatrzymanie podglądu – gdy skończysz korzystać z kamery, zatrzymaj podgląd, klikając
Camera.stopPreview()
. - Zwolnij kamerę – zwolnij kamerę, aby inne aplikacje mogły z niej korzystać, wywołując funkcję
Camera.release()
.
Uwaga: możesz użyć MediaRecorder
bez wcześniejszego utworzenia podglądu w aparacie i pominąć kilka pierwszych kroków tego procesu. Jednak użytkownicy zazwyczaj wolą zobaczyć podgląd przed rozpoczęciem nagrywania, więc nie omawiamy 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 skrócić czas potrzebny do rozpoczęcia nagrywania.
Konfigurowanie MediaRecorder
Jeśli używasz klasy MediaRecorder
do nagrywania filmów, 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 2.2 (poziom interfejsu API 8) i starszych musisz ustawić format wyjściowy oraz formaty kodowania bezpośrednio w parametrach zamiast używać CamcorderProfile
. To podejście jest pokazane 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);
Parametry nagrywania wideo w przypadku MediaRecorder
są podane w ustawieniach domyślnych, ale możesz dostosować je do swoich potrzeb:
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 kamerę za pomocą
Camera.unlock()
- Skonfiguruj
MediaRecorder
zgodnie z przykładem kodu powyżej. - Rozpocznij nagrywanie za pomocą
MediaRecorder.start()
- Nagraj film
- Zatrzymanie nagrywania za pomocą
MediaRecorder.stop()
- Puść rejestrator mediów, jeśli
MediaRecorder.release()
- Zablokuj kamerę za pomocą
Camera.lock()
Poniższy przykładowy kod pokazuje, jak podłączyć przycisk, aby prawidłowo uruchamiać i zatrzymywać nagrywanie wideo za pomocą aparatu i klasy MediaRecorder
.
Uwaga: podczas nagrywania filmu nie zwalniaj przycisku migawki, ponieważ spowoduje to zatrzymanie podglądu.
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 przedstawionego w artykule Konfigurowanie MediaRecorder. Ta metoda zajmuje się blokowaniem kamery, konfigurowaniem i przygotowywaniem instancji MediaRecorder
.
Zwolnienie kamery
Aparaty to zasoby udostępniane przez aplikacje na urządzeniu. Aplikacja może używać aparatu po uzyskaniu instancji Camera
. Musisz jednak pamiętać, aby zwalniać obiekt aparatu, gdy aplikacja przestanie go używać, oraz gdy zostanie wstrzymana (Activity.onPause()
). Jeśli aplikacja nie zwolni prawidłowo aparatu, wszystkie kolejne próby uzyskania dostępu do aparatu, w tym te przez Twoją aplikację, będą się nieudanie kończyć 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 prawidłowo kamery, wszystkie kolejne próby uzyskania dostępu do kamery, w tym te przez Twoją aplikację, będą nieudane i mogą spowodować zamknięcie Twojej aplikacji lub innych aplikacji.
Zapisywanie plików multimedialnych
Pliki multimedialne tworzone przez użytkowników, takie jak zdjęcia i filmy, powinny być zapisywane w katalogu zewnętrznej pamięci urządzenia (karta SD), aby oszczędzać miejsce w systemie i umożliwiać użytkownikom dostęp do tych plików bez konieczności korzystania z urządzenia. Istnieje wiele możliwych lokalizacji katalogów, w których można zapisywać pliki multimedialne na urządzeniu. Jako deweloper powinieneś jednak 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 znajdować, czytać, zmieniać i usuwać pliki zapisane w tej lokalizacji. Jeśli użytkownik odinstaluje aplikację, pliki multimedialne zapisane w tej lokalizacji nie zostaną usunięte. Aby nie zakłócać dotychczasowych zdjęć i filmów użytkowników, w tym katalogu utwórz 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). Aby uzyskać informacje o odpowiednich wywołaniach w wcześniejszych wersjach interfejsu API, zapoznaj się z artykułem Zapisywanie udostępnionych plików.Context.getExternalFilesDir
(Environment.DIRECTORY_PICTURES
) – ta metoda zwraca standardowe miejsce do zapisywania zdjęć i filmów powiązanych z Twoją aplikacją. Jeśli aplikacja zostanie odinstalowana, wszystkie pliki zapisane w tej lokalizacji zostaną usunięte. Bezpieczeństwo plików w tym miejscu nie jest wymuszane, więc inne aplikacje mogą je odczytywać, zmieniać i usuwać.
Przykładowy kod poniżej pokazuje, jak utworzyć lokalizację File
lub Uri
dla pliku multimedialnego, który może być używany podczas wywoływania aparatu urządzenia za pomocą Intent
lub w ramach tworzenia aplikacji do obsługi 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: funkcja Environment.getExternalStoragePublicDirectory()
jest dostępna w Androidzie 2.2 (poziom API 8 lub wyższy). Jeśli kierujesz reklamy na urządzenia z wcześniejszymi wersjami Androida, użyj zamiast tego Environment.getExternalStorageDirectory()
. Więcej informacji znajdziesz w artykule Zapisywanie udostępnionych plików.
Aby identyfikator URI obsługiwał profile służbowe, najpierw
przekształć identyfikator URI pliku w identyfikator URI treści. Następnie dodaj identyfikator URI treści do EXTRA_OUTPUT
Intent
.
Więcej informacji o zapisywaniu plików na urządzeniu z Androidem znajdziesz w artykule Przechowywanie danych.
Funkcje aparatu
Android obsługuje wiele funkcji aparatu, którymi możesz sterować w aplikacji aparatu,
takich jak format obrazu, tryb lampy błyskowej czy ustawienia ostrości. W tej sekcji znajdziesz listę typowych funkcji aparatu i krótkie omówienie ich działania. Większość funkcji aparatu można uzyskać i ustawić za pomocą obiektu Camera.Parameters
. Jednak niektóre ważne funkcje wymagają więcej niż tylko prostych ustawień w Camera.Parameters
. Te funkcje są opisane w tych sekcjach:
Ogólne informacje o używaniu funkcji sterowanych za pomocą Camera.Parameters
znajdziesz w sekcji Korzystanie z funkcji aparatu. Aby dowiedzieć się więcej o używaniu funkcji sterowanych za pomocą obiektu camera_parameters, kliknij linki do dokumentacji na temat interfejsu API podane na liście funkcji poniżej.
Funkcja | Poziom interfejsu API | Opis |
---|---|---|
Wykrywanie twarzy | 14 | rozpoznawać twarze na zdjęciach i wykorzystywać je do ustawiania ostrości, pomiaru ekspozycji i balansu bieli; |
Obszary pomiarowe | 14 | Określ co najmniej 1 obszar obrazu do obliczenia balansu bieli |
Obszary specjalizacji | 14 | Wybierz co najmniej 1 obszar na obrazie, który ma być ostry |
White Balance Lock |
14 | Zatrzymywanie lub uruchamianie automatycznych dostosowań balansu bieli |
Exposure Lock |
14 | Zatrzymywanie lub uruchamianie automatycznych korekt ekspozycji |
Video Snapshot |
14 | Robienie zdjęcia podczas nagrywania filmu (uchwyt klatki) |
Film poklatkowy | 11 | Nagrywanie klatek z ustawionymi opóźnieniami w celu nagrania filmu poklatkowego |
Multiple Cameras |
9 | Obsługa więcej niż 1 kamery na urządzeniu, w tym przedniej i tylnej |
Focus Distance |
9 | Raporty dotyczące odległości między kamerą a obiektami, które wydają się być w fokusie |
Zoom |
8 | Ustawianie powiększenia obrazu |
Exposure
Compensation |
8 | Zwiększanie lub zmniejszanie poziomu ekspozycji na światło |
GPS Data |
5 | Uwzględnianie lub pomijanie danych o lokalizacji geograficznej w obrazie |
White Balance |
5 | Ustaw tryb balansu bieli, który wpływa na wartości kolorów na zrobionym zdjęciu. |
Focus Mode |
5 | Ustaw sposób ustawiania ostrości przez aparat, np. automatyczny, stały, makro lub nieskończoność. |
Scene Mode |
5 | Użyj wstępnie ustawionego trybu do określonych sytuacji, takich jak noc, plaża, śnieg lub sceny z świecami. |
JPEG Quality |
5 | Ustaw poziom kompresji obrazu JPEG, aby zwiększyć lub zmniejszyć jakość i rozmiar pliku wyjściowego obrazu. |
Flash Mode |
5 | Włączanie i wyłączanie lampy błyskowej lub korzystanie z ustawienia automatycznego |
Color Effects |
5 | Zastosowanie efektu kolorystycznego do zrobionego zdjęcia, np. czarno-białego, sepii lub negatywu. |
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 zapisywanego obrazu w pikselach. |
Uwaga: te funkcje nie są obsługiwane na wszystkich urządzeniach ze względu na różnice w sprzęcie i implementacji 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
Zanim zaczniesz korzystać z funkcji aparatu na urządzeniach z Androidem, musisz wiedzieć, ż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 w ramach procesu decyzyjnego podczas tworzenia aplikacji do obsługi aparatu należy zdecydować, jakie funkcje aparatu chcesz obsługiwać i na jakim poziomie. Po podjęciu decyzji należy uwzględnić w aplikacji aparatu kod, który sprawdza, czy sprzęt urządzenia obsługuje te funkcje, i łagodnie przerywa działanie, jeśli dana funkcja jest niedostępna.
Aby sprawdzić dostępność funkcji aparatu, pobierz instancję obiektu camera.parameters i sprawdź odpowiednie metody. Ten 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 korzystać z opisanej powyżej techniki. Obiekt Camera.Parameters
udostępnia metody getSupported...()
, is...Supported()
lub getMax...()
, które pozwalają określić, czy dana funkcja jest obsługiwana (i w jakim zakresie).
Jeśli aplikacja do prawidłowego działania wymaga pewnych funkcji aparatu, możesz je wymagać, dodając je do pliku manifestu aplikacji. Gdy zadeklarujesz użycie określonych funkcji aparatu, takich jak lampa błyskowa i autofokus, Google Play zablokuje instalację 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 dotyczącej funkcji.
Korzystanie z funkcji aparatu
Większość funkcji aparatu jest aktywowana i sterowana za pomocą obiektu Camera.Parameters
. Aby uzyskać ten obiekt, najpierw pobierz instancję obiektu Camera
, wywołując metodę getParameters()
, zmień zwrócony obiekt parametru, a następnie ustaw go z powrotem w obiekcie camera, jak pokazano 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 metoda działa w przypadku niemal wszystkich funkcji aparatu, a po uzyskaniu wystąpienia obiektu Camera
większość parametrów można zmienić w dowolnym momencie. Zmiany parametrów są zwykle widoczne dla użytkownika natychmiast w podglądzie aparatu w aplikacji.
Zmiany parametrów mogą być wprowadzane przez kilka klatek, ponieważ sprzęt aparatu musi przetworzyć nowe instrukcje, a następnie wysłać zaktualizowane dane obrazu.
Ważne: niektórych funkcji aparatu nie można zmieniać dowolnie. W szczególności zmiana rozmiaru lub orientacji podglądu 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 do implementacji, w tym:
- pomiar i obszary ostrości,
- Wykrywanie twarzy
- Film poklatkowy
W następnych sekcjach znajdziesz krótki opis sposobu wdrażania tych funkcji.
pomiar i obszary ostrości,
W niektórych sytuacjach automatyczne ustawianie ostrości i wymiarowanie światła mogą nie przynieść oczekiwanych rezultatów. Począwszy od Androida 4.0 (poziom interfejsu API 14) aplikacja aparatu może udostępniać dodatkowe elementy sterujące, które umożliwiają aplikacji lub użytkownikom wskazywanie obszarów na obrazie, które mają być używane do określania ustawień ostrości lub poziomu światła, oraz przekazywanie tych wartości do sprzętu aparatu na potrzeby rejestrowania zdjęć lub filmów.
Obszary pomiaru i ostrzenia działają podobnie jak inne funkcje aparatu, ponieważ możesz je kontrolować za pomocą metod obiektu Camera.Parameters
. Poniższy kod pokazuje ustawienie 2 obszarów pomiarowych ś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
służący do określania obszaru w polu widzenia aparatu oraz wartość wagową, która informuje aparat, jaką wagę powinien mieć ten obszar w obliczeniach pomiaru światła lub ostrości.
Pole Rect
w obiekcie Camera.Area
opisuje prostokątny kształt mapowany na siatce o wymiarach 2000 x 2000 pikseli. Współrzędne -1000, -1000 odpowiadają lewemu górnemu rogowi obrazu z kamery, a współrzędne 1000, 1000 – prawy dolny róg obrazu z kamery, jak pokazano na ilustracji poniżej.
Granice tego układu współrzędnych zawsze odpowiadają zewnętrznej krawędzi obrazu widocznego w podglądzie aparatu i nie kurczą się ani nie rozszerzają wraz z poziomem powiększenia. Podobnie, obrócenie podglądu obrazu za pomocą Camera.setDisplayOrientation()
nie powoduje zmiany mapowania układu współrzędnych.
Wykrywanie twarzy
W przypadku zdjęć przedstawiających ludzi twarze są zwykle najważniejszą częścią obrazu i powinny być używane do określania ostrości oraz balansu bieli podczas fotografowania. Platforma Android 4.0 (poziom interfejsu API 14) udostępnia interfejsy API do rozpoznawania twarzy i obliczania ustawień zdjęć za pomocą technologii rozpoznawania twarzy.
Uwaga: gdy funkcja wykrywania twarzy jest włączona, opcje setWhiteBalance(String)
, setFocusAreas(List<Camera.Area>)
i setMeteringAreas(List<Camera.Area>)
nie mają żadnego wpływu.
Korzystanie z funkcji wykrywania twarzy w aplikacji aparatu wymaga wykonania kilku ogólnych czynności:
- Sprawdź, czy wykrywanie twarzy jest obsługiwane na urządzeniu
- Tworzenie odbiornika wykrywania twarzy
- Dodaj obiekt 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. Aby sprawdzić, czy ta funkcja jest obsługiwana, zadzwoń pod numer getMaxNumDetectedFaces()
. Przykład tego sprawdzania znajdziesz w przykładowej metodzie startFaceDetection()
poniżej.
Aby otrzymywać powiadomienia i reagować na wykrycie twarzy, aplikacja aparatu musi skonfigurować odbiornik zdarzeń wykrywania twarzy. Aby to zrobić, musisz utworzyć klasę listenera, która implementuje interfejs Camera.FaceDetectionListener
, jak pokazano w przykładowym kodzie poniżej.
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 aparatu. Utwórz metodę uruchamiającą wykrywanie twarzy, aby można było ją wywołać 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(); } }
Funkcję wykrywania twarzy musisz włączać za każdym razem, gdy uruchamiasz (lub ponownie uruchamiasz) podgląd aparatu. Jeśli używasz klasy podglądu opisanej w sekcji Tworzenie klasy podglądu, dodaj metodę startFaceDetection()
do obu 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: tę metodę należy wywołać po wywołaniu metody startPreview()
. Nie próbuj uruchamiać wykrywania twarzy w metodzie onCreate()
głównej aktywności aplikacji do obsługi aparatu, ponieważ w tym momencie w aplikacji nie jest dostępny podgląd.
Film poklatkowy
Film poklatkowy umożliwia tworzenie klipów wideo, które łączą zdjęcia zrobione w odstępie kilku sekund lub minut. Ta funkcja używa MediaRecorder
do nagrywania zdjęć na potrzeby sekwencji zdjęć poklatkowych.
Aby nagrać film poklatkowy za pomocą MediaRecorder
, musisz skonfigurować obiekt recorder tak, jak w przypadku zwykłego nagrywania filmu, ustawiając liczbę uchwycionych klatek na sekundę na niską wartość i korzystając z jednego z ustawień jakości filmu poklatkowego, jak pokazano w przykładzie kodu 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 muszą być wprowadzone w ramach szerszej procedury konfiguracji MediaRecorder
. Pełny przykład kodu konfiguracji znajdziesz w artykule Konfigurowanie MediaRecorder. Po zakończeniu konfiguracji rozpocznij nagrywanie filmu tak, jak w przypadku zwykłego klipu wideo. Więcej informacji o konfigurowaniu i uruchamianiu MediaRecorder
znajdziesz w artykule Nagrywanie filmów.
Przykłady korzystania z interfejsów API opisanych na tej stronie znajdziesz w interfejsach Camera2Video i HdrViewfinder.
Pola aparatu, które wymagają uprawnień
Aplikacje działające na Androidzie 10 (poziom interfejsu API 29) lub nowszym muszą mieć uprawnienie CAMERA
, aby uzyskać dostęp do wartości 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, zapoznaj się z przykładową aplikacją Camera2Basic i oficjalną aplikacją przykładową CameraX.