Interfejs API aparatu

Platforma Androida zapewnia obsługę różnych aparatów i funkcji aparatu dostępnych urządzeń, dzięki czemu możesz robić zdjęcia i nagrywać filmy w aplikacjach. W tym dokumencie omówiono szybkie i proste podejście do robienia zdjęć i nagrywania filmów. z aparatem dostosowanym do potrzeb użytkowników.

Uwaga: ta strona zawiera opis klasy Camera, która została wycofana. Zalecamy użycie metody CameraX; z biblioteki Jetpack lub, w określonych przypadkach, camera2 zajęcia. Zarówno AparatX, jak i Aparat2 działają na Androidzie 5.0 (poziom interfejsu API 21) oraz wyżej.

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 kamery jest tak ważne Aplikacja, której nie chcesz instalować na urządzeniu bez aparat? Jeśli tak, musisz zadeklarować wymagania dotyczące aparatu na swoim pliku manifestu.
  • Szybkie zdjęcie lub niestandardowy aparat – jak aplikacja będzie używać aparatu? Czy chodzi Ci tylko o szybkie robienie zdjęć lub nagrywanie filmów, czy aplikacja ma oferować nowy sposób korzystania z aparatów? Aby szybko zrobić zdjęcie lub klip, zastanów się: Korzystanie z istniejących aplikacji aparatu. Informacje o tworzeniu niestandardowej funkcji aparatu znajdziesz w sekcji Tworzenie aplikacji aparatu.
  • Wymagania dotyczące usług działających na pierwszym planie – kiedy Twoja aplikacja wchodzi w interakcję z przez kamerę? Na Androidzie 9 (poziom interfejsu API 28) i nowszych aplikacje działające Tło nie może uzyskać dostępu do aparatu. Dlatego należy używać aparatu gdy aplikacja działa na pierwszym planie lub usługę działającą na pierwszym planie.
  • Pamięć wewnętrzna – czy obrazy lub filmy mają być generowane przez aplikację widoczne tylko dla aplikacji lub udostępniane, aby inne aplikacje, takie jak media i aplikacje społecznościowe mogą z nich korzystać? Czy chcesz, aby zdjęcia i filmy były dostępne nawet po odinstalowaniu aplikacji? Zapoznaj się z sekcją Zapisywanie plików multimedialnych, aby zobacz, jak wdrożyć te opcje.

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 wycofany interfejs API do sterowania kamerami urządzenia.
SurfaceView
Ta klasa służy do wyświetlania użytkownikowi podglądu na żywo z kamery.
MediaRecorder
Te zajęcia służą do nagrywania obrazu z kamery.
Intent
Działanie typu MediaStore.ACTION_IMAGE_CAPTURE lub MediaStore.ACTION_VIDEO_CAPTURE może być używane do robienia zdjęć i filmów bez bezpośredniego przy użyciu obiektu Camera.

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 wywołując istniejącą aplikację aparatu, aplikacja nie musi prosić o to uprawnienie.

  • Funkcje aparatu – w aplikacji musisz też zadeklarować korzystanie z funkcji aparatu, np.:
    <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 używaniu filtrowania na podstawie cech w Google Play znajdziesz w artykule na temat Play i filtrowanie oparte na funkcjach.

    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 do pamięci – aplikacja może zapisywać obrazy i filmy w pamięci zewnętrznej urządzenia (karty SD), jeśli jest ona kierowana na Androida 10 (poziom interfejsu API 29) lub i określa w pliku manifestu te elementy.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • Uprawnienia do nagrywania dźwięku – w przypadku nagrywania dźwięku z obrazem aplikacja musi prosić o uprawnienia do przechwytywania dźwięku.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
  • Pozwolenie na lokalizację – jeśli aplikacja taguje obrazy z informacjami o lokalizacji GPS, musisz wysłać prośbę o ACCESS_FINE_LOCATION uprawnienia. Pamiętaj, że jeśli aplikacja jest kierowana na Androida 5.0 (poziom interfejsu API 21) lub wyżej, musisz też zadeklarować, że aplikacja używa 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 pozyskiwaniu lokalizacji użytkownika znajdziesz w artykule Strategie dotyczące lokalizacji.

Korzystanie z dotychczasowych aplikacji do obsługi aparatu

Szybki sposób na robienie zdjęć i nagrywanie filmów w aplikacji bez konieczności pisania dużych ilości kodu to użycie Intent do wywołania istniejącej aplikacji aparatu na Androida. Szczegóły znajdziesz w lekcji Proste fotografowanieProste nagrywanie filmów.

Tworzę aplikację aparatu

Niektórzy deweloperzy mogą wymagać interfejsu użytkownika kamery dostosowanego do wyglądu aplikacji lub oferuje specjalne funkcje. Możesz napisać własny kod do robienia zdjęć, aby zapewnić użytkownikom bardziej atrakcyjne wrażenia.

Uwaga: ten przewodnik dotyczy starszych, wycofanych wersji Camera API. W przypadku nowych i zaawansowanych aplikacji związanych z aparatem nowszy interfejs API android.hardware.camera2 to .

Oto ogólne czynności, które należy wykonać, aby utworzyć niestandardowy interfejs 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 interfejs SurfaceHolder. Ten podczas lekcji wyświetli podgląd obrazów 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.
  • Przechwyć i zapisz pliki – skonfiguruj kod do robienia zdjęć lub filmy i zapisanie wyników.
  • Zwalnianie aparatu – po użyciu aparatu aplikacja musi: i umożliwić jej używanie w innych aplikacjach.

Kamera to zasób współdzielony, którym trzeba odpowiednio zarządzać, aby aplikacja działała. w taki sposób, aby nie kolidowały z innymi aplikacjami, które również mogą zechcieć 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 uruchomi poprawnie aparatu, kolejne próby dostępu do kamery, również te realizowane przez Twoją aplikację, zakończą się niepowodzeniem i mogą może spowodować wyłączenie aplikacji lub innych aplikacji.

Wykrywam aparat

Jeśli Twoja aplikacja nie wymaga użycia kamery przy użyciu deklaracji w pliku manifestu, powinien sprawdzić, 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(). Nie udało się sprawdzić wyjątków, jeśli kamera jest włączona lub jeśli nie istnieje, spowoduje to wyłączenie aplikacji przez system.

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). Podany powyżej przykładowy kod uzyska dostęp do pierwszego tylnego aparatu na urządzeniu z większą liczbą aparatów.

Sprawdzanie funkcji aparatu

Gdy już uzyskasz dostęp do kamery, możesz dowiedzieć się więcej o jej możliwościach w metody Camera.getParameters() i sprawdź zwrócił obiekt Camera.Parameters, aby uzyskać obsługiwane funkcje. W przypadku użycia funkcji Interfejs API na poziomie 9 lub wyższym: Camera.getCameraInfo() pozwala określić, czy kamera jest z przodu lub tylnej części urządzenia oraz orientację zdjęcia.

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 funkcję SurfaceHolder.Callback, aby przechwytywać zdarzenia wywołania zwrotnego do tworzenia i niszczenia widoku, które są potrzebne do przypisywania danych wejściowych podglądu z kamery.

Kotlin

/** A basic Camera preview class */
class CameraPreview(
        context: Context,
        private val mCamera: Camera
) : SurfaceView(context), SurfaceHolder.Callback {

    private val mHolder: SurfaceHolder = holder.apply {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        addCallback(this@CameraPreview)
        // deprecated setting, but required on Android versions prior to 3.0
        setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        mCamera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: IOException) {
                Log.d(TAG, "Error setting camera preview: ${e.message}")
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.surface == null) {
            // preview surface does not exist
            return
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview()
        } catch (e: Exception) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        mCamera.apply {
            try {
                setPreviewDisplay(mHolder)
                startPreview()
            } catch (e: Exception) {
                Log.d(TAG, "Error starting camera preview: ${e.message}")
            }
        }
    }
}

Java

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

Jeśli chcesz ustawić 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 działaniu, 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 ułatwić renderowanie podglądu z aparatu, należy zmienić ustaw orientację działania podglądu aplikacji na poziomą. W tym celu dodaj ten fragment pliku manifestu.

<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. Począwszy od Androida w wersji 2.2 (poziom interfejsu API 8) możesz używać metody setDisplayOrientation() do konfigurowania przez obrót obrazu podglądu. Aby zmienić orientację podglądu, gdy użytkownik zmieni orientację w ramach metody surfaceChanged() klasy podglądu najpierw zatrzymaj podgląd przy użyciu polecenia Camera.stopPreview(), a następnie zmień orientację, a następnie ponownie włącz podgląd, wybierając 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ż obejmować aby ją zwolnił, gdy jest wstrzymany lub wyłączony. Ten przykład pokazuje, aby zmodyfikować aktywność kamery i dołączyć klasę podglądu widoczną w sekcji Tworzenie 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 przedstawionej w sekcji Uzyskiwanie dostępu do aparatów.

Robię zdjęcia

Po utworzeniu klasy podglądu i układu widoku, w którym chcesz ją wyświetlać, możesz rozpocząć robienie obrazów za pomocą aplikacji. W kodzie aplikacji musisz skonfigurować detektory aby elementy sterujące interfejsu reagowały na działanie użytkownika poprzez zrobienie zdjęcia.

Aby pobrać zdjęcie, użyj metody Camera.takePicture(). Ta metoda wykorzystuje 3 parametry, które odbierają dane z kamery. Aby otrzymywać dane w formacie JPEG, musisz wdrożyć interfejs Camera.PictureCallback do odbierania danych obrazu i zapisać go 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());
        }
    }
};

Uruchom przechwytywanie obrazu, wywołując 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: do nazwy odnosi się użytkownik mPicture z poniższego przykładu. do powyższego przykładowego kodu.

Uwaga: pamiętaj, by zwolnić Camera przez wywołanie Camera.release(), gdy można za jej pomocą zakończyć korzystanie z aplikacji. Informacje na temat zwalniania aparatu znajdziesz w sekcji Zwalnianie aparatu.

Nagrywanie filmów

Nagrywanie filmów przy użyciu platformy Androida wymaga starannego zarządzania obiektem Camera i koordynacji z platformą MediaRecorder zajęcia. Podczas nagrywania filmów za pomocą Camera musisz zarządzać wywołaniami Camera.lock() i Camera.unlock(), aby zezwolić MediaRecorder na dostęp do aparatu. Dotyczy to również wywołań 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 filmów wymaga konkretnego połączenia. zamówienie. Aby przygotować i zapisać film z aplikacją, musisz wykonać określone czynności w określonej kolejności.

  1. Otwórz aparat – użyj funkcji Camera.open(), aby uzyskać instancję obiektu aparatu.
  2. Połącz podgląd – aby przygotować podgląd obrazu z kamery na żywo, połącz SurfaceView z kamerą za pomocą Camera.setPreviewDisplay().
  3. Rozpocznij podgląd – wybierz Camera.startPreview(), aby wyświetlić obraz z kamery na żywo.
  4. Rozpocznij nagrywanie filmu – poniższe czynności należy wykonać w zamówienie, aby nagrać film:
    1. Odblokuj kamerę – odblokuj kamerę na potrzeby MediaRecorder, wywołując Camera.unlock().
    2. Skonfiguruj MediaRecorder – wywołaj poniższe metody MediaRecorder w tej kolejności. Więcej informacji znajdziesz w dokumentacji MediaRecorder.
      1. setCamera() – ustaw kamerę, która będzie używana do nagrywania wideo. Użyj bieżącej instancji aplikacji. z Camera.
      2. setAudioSource() – ustaw wartość źródła dźwięku, użyj formatu MediaRecorder.AudioSource.CAMCORDER.
      3. setVideoSource() – ustaw źródła wideo, użyj MediaRecorder.VideoSource.CAMERA.
      4. 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:
        1. setOutputFormat() – ustaw format wyjściowy, określ ustawienie domyślne lub MediaRecorder.OutputFormat.MPEG_4.
        2. setAudioEncoder() – ustaw typ kodowania dźwięku, określ ustawienie domyślne lub MediaRecorder.AudioEncoder.AMR_NB.
        3. setVideoEncoder() – ustaw typ kodowania wideo, określ ustawienie domyślne lub MediaRecorder.VideoEncoder.MPEG_4_SP.
      5. setOutputFile() – Ustaw plik wyjściowy, użyj pola getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() z przykładu w sekcji Zapisywanie plików multimedialnych.
      6. setPreviewDisplay() – określ element układu podglądu SurfaceView dla Twojej aplikacji. Użyj tego samego obiektu, który został podany w podglądzie połączenia.

      Uwaga: te metody konfiguracji MediaRecorder musisz wywoływać w tej kolejności. W przeciwnym razie aplikacja napotka błędy, a nagrywanie się nie uda.

    3. Prepare MediaRecorder – przygotowywanie MediaRecorder z podanymi ustawieniami konfiguracji przez wywołanie metody MediaRecorder.prepare().
    4. Uruchom MediaRecorder – rozpocznij nagrywanie filmu, dzwoniąc pod numer MediaRecorder.start().
  5. Zatrzymanie nagrywania filmu – aby zakończyć nagrywanie filmu, wywołuj podane niżej metody w kolejności:
    1. Zatrzymaj MediaRecorder – zatrzymaj nagrywanie filmu, wywołując MediaRecorder.stop().
    2. Zresetuj MediaRecorder – opcjonalnie usuń ustawienia konfiguracji z nagrywarki, wywołując funkcję MediaRecorder.reset().
    3. Zwolnij MediaRecorder – zwalniaj MediaRecorder, wywołując funkcję MediaRecorder.release().
    4. Zablokuj kamerę – zablokuj kamerę, aby kolejne sesje MediaRecorder mogły z niej korzystać, wywołując funkcję Camera.lock(). Od Androida 4.0 (poziom interfejsu API 14) to wywołanie nie jest wymagane, chyba że MediaRecorder.prepare() nieudane połączenie.
  6. Zatrzymanie podglądu – gdy skończysz korzystać z kamery, zatrzymaj podgląd, klikając Camera.stopPreview().
  7. Zwolnij kamerę – zwolnij kamerę, aby inne aplikacje mogły z niej korzystać, wywołując funkcję Camera.release().

Uwaga: możesz użyć MediaRecorderbez 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 wartość setRecordingHint(boolean) na true. To ustawienie może skrócić czas potrzebny na rozpoczęcie 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;
}

Przed Androidem 2.2 (poziom interfejsu API 8) trzeba ustawiać format wyjściowy i formaty kodowania bezpośrednio, zamiast używać parametru CamcorderProfile. To podejście 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 je dostosować do swojej aplikacji:

Uruchamianie i zatrzymywanie MediaRecorder

Podczas uruchamiania i zatrzymywania nagrywania filmu za pomocą klasy MediaRecorder musisz przestrzegać określonej kolejności, jak opisano poniżej.

  1. Odblokuj aparat za pomocą aplikacji Camera.unlock()
  2. Skonfiguruj MediaRecorder zgodnie z przykładem kodu powyżej.
  3. Rozpocznij nagrywanie za pomocą MediaRecorder.start()
  4. Nagraj film
  5. Zatrzymaj nagrywanie za pomocą MediaRecorder.stop()
  6. Zwolnij nagrywarkę multimediów za pomocą funkcji MediaRecorder.release()
  7. Zablokuj aparat za pomocą funkcji Camera.lock()

Ten przykładowy kod pokazuje, jak podłączyć przycisk, aby prawidłowo uruchamiał i zatrzymał się nagrywanie filmów za pomocą kamery i klasy MediaRecorder.

Uwaga: podczas nagrywania filmu nie puść kamery. 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 tym przykładzie prepareVideoRecorder() odnosi się do przykładowego kodu widocznego w sekcji 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 uruchomić 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, ale jako deweloper powinieneś wziąć pod uwagę tylko 2 standardowe lokalizacje:

  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) – ta metoda zwraca standardową, udostępnioną i zalecaną metodę. miejsce na zapisywanie zdjęć i filmów. Ten katalog jest udostępniony (publiczny), więc inne aplikacje mogą łatwo wykrywać, 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ępne w Androidzie 2.2 (poziom interfejsu API 8). Informacje o równoważnych wywołaniach we wcześniejszych wersjach interfejsu API znajdziesz w sekcji 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. Zabezpieczenia nie są wymuszane dla plików w tej lokalizacji i innych aplikacji mogą je odczytywać, zmieniać oraz usuwać.

Przykładowy kod poniżej pokazuje, jak utworzyć lokalizację File lub Uri dla pliku multimedialnego, który można użyć podczas wywołania 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 zasady 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_OUTPUTIntent.

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 typowe z aparatem i krótkim omówieniem tego, jak z nich korzystać. Można korzystać z większości funkcji aparatu i ustawić je za pomocą obiektu do obsługi zdarzeń Camera.Parameters. Dostępnych jest jednak kilka ważnych funkcji, które wymagają czegoś więcej niż prostych ustawień w usłudze Camera.Parameters. Funkcje te są opisane w tych sekcjach:

Ogólne informacje o używaniu funkcji, które są kontrolowane przez Camera.Parameters, znajdziesz w sekcji Korzystanie z funkcji aparatu. Więcej informacji o używaniu funkcji kontrolowanych przez obiekt camera_parameters znajdziesz w dokumentacji na temat interfejsu API (linki do niej znajdziesz na liście funkcji poniżej).

Tabela 1. Wspólne funkcje aparatu posortowane według poziomu interfejsu API Androida, na którym zostały wprowadzone.

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 jeden obszar zdjęcia do obliczania 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 (zrzut klatki)
Film w trybie poklatkowym 11 Nagrywanie klatek z ustawionymi opóźnieniami w celu nagrania filmu poklatkowego
Multiple Cameras 9 Obsługa więcej niż 1 aparatu na urządzeniu, w tym przedniego i tylnego
Focus Distance 9 Raportuje 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 Stosowanie trybu gotowych ustawień w określonych sytuacjach, na przykład w nocy, na plaży czy w śniegu. lub scenami przy świecach
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 oraz używanie ustawień automatycznych
Color Effects 5 Zastosuj efekt kolorystyczny do zrobionego zdjęcia, taki jak czarno-biały, w odcieniu sepii lub negatyw.
Anti-Banding 5 Ogranicza efekt pasów w gradientach kolorów spowodowanych kompresją JPEG.
Picture Format 1 Określ format pliku zdjęcia
Picture Size 1 Określ wymiary zapisanego 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, warto wiedzieć, Nie wszystkie funkcje aparatu są obsługiwane na wszystkich urządzeniach. Ponadto urządzenia obsługujące określony mogą obsługiwać różne poziomy lub opcje. Dlatego też część procesu decyzyjnego przy opracowywaniu aplikacji do obsługi kamery jest wybór funkcji kamery, które chcesz 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. Poniższy przykładowy kod pokazuje, jak uzyskać Camera.Parameters obiekt i sprawdź, czy aparat obsługuje autofokus cecha:

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 metody. Obiekt Camera.Parameters udostępnia metodę getSupported...(), is...Supported() lub getMax...() do określenia, czy (i w jakim stopniu) cecha jest obsługiwane.

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 manifeście aplikacji, zobacz plik manifestu Funkcje Materiały referencyjne.

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 prawie wszystkich funkcji kamery, a większość parametrów można zmienić w dowolnym momencie czasu po uzyskaniu instancji obiektu Camera. Zmiany w są zwykle widoczne dla użytkownika bezpośrednio na podglądzie 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 zmiana rozmiaru lub orientacji podglądu z aparatu wymaga wcześniejszego zakończenia wyświetlić podgląd, zmienić jego rozmiar i ponownie uruchomić podgląd. Począwszy od Androida 4.0 (interfejs API 14) orientację podglądu można zmienić bez ponownego uruchamiania podglądu.

Wdrożenie innych funkcji aparatu wymaga dodatkowego kodu, takich jak:

  • pomiar i obszary ostrości,
  • Wykrywanie twarzy
  • Film poklatkowy

Poniżej znajdziesz krótki opis implementacji 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 opcje, które pozwalają aplikacji lub użytkownikom określić obszary na obrazie, które mają być używane ustawień ostrości i poziomu oświetlenia oraz przekazuj te wartości do sprzętu aparatu (obrazy i filmy).

Obszary do pomiaru i ustawiania ostrości działają bardzo podobnie do innych funkcji aparatu, ponieważ możesz kontrolować je za pomocą metod w obiekcie Camera.Parameters. Poniższy kod pokazuje ustawienie 2 obszarów pomiaru światła dla instancji Camera:

Kotlin

// Create an instance of Camera
camera = getCameraInstance()

// set Camera parameters
val params: Camera.Parameters? = camera?.parameters

params?.apply {
    if (maxNumMeteringAreas > 0) { // check that metering areas are supported
        meteringAreas = ArrayList<Camera.Area>().apply {
            val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image
            add(Camera.Area(areaRect1, 600)) // set weight to 60%
            val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image
            add(Camera.Area(areaRect2, 400)) // set weight to 40%
        }
    }
    camera?.parameters = this
}

Java

// Create an instance of Camera
camera = getCameraInstance();

// set Camera parameters
Camera.Parameters params = camera.getParameters();

if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
    List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
    params.setMeteringAreas(meteringAreas);
}

camera.setParameters(params);

Obiekt Camera.Area zawiera 2 parametry danych: obiekt Rect do określenia obszaru w polu widzenia kamery oraz wagę. która informuje kamerę, jak ważny jest ten obszar w pomiarze światła. lub obliczeń skupienia.

Pole Rect w obiekcie Camera.Areaopisuje 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.

Rysunek 1. Czerwone linie przedstawiają układ współrzędnych służący do określania Camera.Area w podglądzie z aparatu. Niebieski kwadrat wskazuje położenie i kształt obszaru kamery z wartościami Rect 333,333,667,667.

Granice tego układu współrzędnych zawsze odpowiadają zewnętrznej krawędzi obrazu widocznego w podglądzie aparatu i nie kurczą się ani nie rozszerzają wraz z poziomem powiększenia. Podobnie jest z obracaniem obrazu. zobacz podgląd w usłudze 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 rejestrowania obrazu. Android 4.0 (poziom API 14) udostępnia interfejsy API do rozpoznawania twarzy i obliczania ustawień zdjęcia za pomocą technologii rozpoznawania twarzy.

Uwaga: gdy funkcja wykrywania twarzy jest włączona, opcje setWhiteBalance(String), setFocusAreas(List<Camera.Area>)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
  • Utwórz detektor wykrywania twarzy
  • Dodaj detektor wykrywania twarzy do obiektu kamery
  • 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 tej weryfikacji znajdziesz w przykładowej metodzie startFaceDetection() poniżej.

Aby otrzymywać powiadomienia i reagować na wykrycie twarzy, aplikacja aparatu musi być ustawiona detektor zdarzeń związanych z wykrywaniem twarzy. Aby to zrobić, musisz utworzyć klasę detektora, która implementuje interfejs Camera.FaceDetectionListener zgodnie z tabelą przykładowy kod 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 tych zajęć możesz je ustawić w Camera – tak jak 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ę uruchamiania wykrywania twarzy, aby móc do niej dzwonić w razie potrzeby, tak jak pokazano na ilustracji 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 widocznej w artykule Tworzenie podglądu, dodaj startFaceDetection() do funkcji surfaceCreated() i surfaceChanged() w zajęciach w wersji testowej, jak widać 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, by wywołać tę metodę po wywołaniu startPreview(). Nie próbuj włączać wykrywania twarzy w metodzie onCreate() podczas głównej aktywności aparatu w aplikacji, ponieważ podgląd nie jest dostępny do tego momentu wykonywania aplikacji.

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 wykorzystuje MediaRecorder do rejestrowania obrazów przez jakiś czas sekwencja poklatkowa.

Aby nagrywać filmy w trybie poklatkowym za pomocą MediaRecorder, musisz skonfigurować obiektu nagrywarki tak jak przy normalnym filmie, ustaw liczbę przechwyconych klatek na sekundę na przy użyciu jednego z ustawień jakości w trybie poklatkowym, jak widać w poniższym przykładzie kodu.

Kotlin

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

Java

// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH));
...
// Step 5.5: Set the video capture rate to a low number
mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds

Te ustawienia należy wprowadzić w ramach większej procedury konfiguracji usługi 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 Informacje o konfigurowaniu i uruchamianiu usługi MediaRecorder zawiera artykuł Nagrywanie filmów.

Camera2Video, oraz HdrViewfinder Przykłady dokładniej pokazują wykorzystanie interfejsów API omówionych na tej stronie.

Pola dotyczące aparatu, które wymagają uprawnień

Aplikacje na Androidzie 10 (poziom interfejsu API 29) lub nowszym muszą mieć CAMERA, aby: uzyskać dostęp do wartości poniższych pól, getCameraCharacteristics() metoda zwraca:

  • 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, zobacz Przykład z Aparatu2Podstawowy oraz Oficjalna przykładowa aplikacja CameraX.