Hinweis:Diese Seite bezieht sich auf das Camera2-Paket. Sofern für Ihre App keine spezifischen Low-Level-Funktionen von Camera2 erforderlich sind, empfehlen wir die Verwendung von CameraX. Sowohl CameraX als auch Camera2 unterstützen Android 5.0 (API-Level 21) und höher.
Ein Android-Gerät kann mehrere Kameras haben. Jede Kamera ist ein
CameraDevice
,
und ein CameraDevice
kann mehr als einen Stream gleichzeitig ausgeben.
Ein Grund dafür ist, dass ein Stream,
die sequenzielle Kameraaufnahme
aus einem CameraDevice
, für eine bestimmte Aufgabe wie das Anzeigen von
im Sucher, während andere vielleicht für Fotos oder Videos verwendet werden.
Die Streams fungieren als parallele Pipelines, die Rohframes verarbeiten.
Bild für Bild heraus.
![](https://developer.android.google.cn/static/images/training/camera/camera2/capture-sessions-requests-1.png?authuser=8&hl=de)
Die parallele Verarbeitung deutet darauf hin, dass je nach die verfügbare Prozessorleistung von CPU, GPU oder einem anderen Prozessor. Wenn ein mit den eingehenden Frames nicht Schritt halten kann, sie verwirft sie.
Jede Pipeline hat ihr eigenes Ausgabeformat. Die eingehenden Rohdaten
automatisch in den entsprechenden
Ausgabeformat durch implizite Logik
die mit jeder Pipeline verknüpft sind. Das CameraDevice
, das im gesamten
Codebeispiele sind unspezifisch, daher müssen Sie zuerst eine Aufzählung
alle verfügbaren Kameras, bevor Sie fortfahren.
Sie können die CameraDevice
verwenden, um ein
CameraCaptureSession
,
die für CameraDevice
spezifisch ist. Ein CameraDevice
muss Folgendes erhalten:
Frame-Konfiguration für jeden Roh-Frame mithilfe von CameraCaptureSession
. Die
Konfiguration Kameraattribute wie Autofokus, Blende, Effekte,
und Präsenz. Aufgrund von Hardwareeinschränkungen kann nur eine Konfiguration
im Kamerasensor aktiv sind. Dieser wird als
active konfiguriert.
Anwendungsfälle für Streams erweitern und erweitern jedoch die bisherigen Möglichkeiten, CameraDevice
zu nutzen.
um Aufnahmen zu streamen. So können Sie den Kamerastream für Ihre
für einen bestimmten Anwendungsfall. Beispielsweise kann die Akkulaufzeit bei der Optimierung
Videoanrufen.
Ein CameraCaptureSession
beschreibt alle möglichen Pipelines, die an die
CameraDevice
. Wenn eine Sitzung erstellt wird, können Sie keine Pipelines hinzufügen oder entfernen.
CameraCaptureSession
verwaltet eine Warteschlange mit
CaptureRequest
e,
die zur aktiven Konfiguration werden.
Ein CaptureRequest
fügt der Warteschlange eine Konfiguration hinzu und wählt eine Konfiguration aus,
oder alle verfügbaren Pipelines zum Empfangen eines Frames vom
CameraDevice
. Während der Aufnahme können viele Aufnahmeanfragen gesendet werden
Sitzung. Jede Anfrage kann die aktive Konfiguration und die Ausgabedaten ändern.
Pipelines, die das Roh-Image empfangen.
Verwenden Sie Stream-Anwendungsfälle für eine bessere Leistung
Anwendungsfälle für Streams sind eine Möglichkeit, die Leistung von Camera2-Aufnahmen zu verbessern Sitzungen. Sie liefern dem Hardwaregerät mehr Informationen zum Abstimmen von Parametern, Das sorgt für ein besseres Kameraerlebnis bei bestimmten Aufgaben.
Dieses
ermöglicht es dem Kameragerät, die Kamerahardware- und -software-Pipelines zu optimieren
basierend auf Nutzerszenarien für jeden Stream. Weitere Informationen zur Streamnutzung
Weitere Informationen zu Anfragen finden Sie unter setStreamUseCase
.
Mithilfe von Stream-Anwendungsfällen können Sie festlegen, wie ein bestimmter Kamerastream in einem bestimmten
im Detail und über das Festlegen einer Vorlage
CameraDevice.createCaptureRequest()
So kann die Kamerahardware
wie Feinabstimmung, Sensormodus oder Kamerasensoreinstellungen,
bei bestimmten Anwendungsfällen
geeignete Kompromisse bei Qualität oder Latenz eingehen.
Anwendungsfälle für Streams:
DEFAULT
: Deckt das gesamte vorhandene Anwendungsverhalten ab. Das ist gleichbedeutend damit, Anwendungsfälle für Streams festlegen.PREVIEW
: Empfohlen für den Sucher oder die Bildanalyse in der App.STILL_CAPTURE
: Optimiert für Aufnahmen mit hoher Qualität und hoher Auflösung. wird voraussichtlich vorschauähnliche Frame-Rates haben.VIDEO_RECORD
: Optimiert für Videoaufnahmen in hoher Qualität, einschließlich hoher Qualität Bildstabilisierung, falls dies vom Gerät unterstützt und von der Anwendung aktiviert wird Diese Option kann Ausgabe-Frames mit einer erheblichen Verzögerung gegenüber Echtzeit erzeugen, um eine optimale Stabilisierung oder eine andere Verarbeitung zu ermöglichen.VIDEO_CALL
: Empfohlen für lang andauernde Kameras mit hohem Stromverbrauch. bedenklich.PREVIEW_VIDEO_STILL
: Empfohlen für Social-Media-Apps oder die Verwendung in einem einzelnen Stream Cases. Es ist ein Mehrzweck-Stream.VENDOR_START
: Wird für vom OEM definierte Anwendungsfälle verwendet.
CameraCaptureSession erstellen
Stellen Sie einen oder mehrere Ausgabezwischenspeicher bereit, um eine Kamerasitzung zu erstellen in die Ihre App Ausgabe-Frames schreiben kann. Jeder Zwischenspeicher stellt eine Pipeline dar. Du musst bevor Sie die Kamera verwenden, damit das Framework an die internen Pipelines des Geräts und weist Arbeitsspeicherpuffer für das Senden von Frames zu erforderlichen Ausgabeziele an.
Das folgende Code-Snippet zeigt, wie Sie eine Kamerasitzung mit zwei
für Ausgabepuffer, von denen einer zu einer
SurfaceView
und einem anderen in ein
ImageReader
Anwendungsfall PREVIEW
Stream wird previewSurface
und
Nutzung des Streams für STILL_CAPTURE
Mit Case to imReaderSurface
optimiert die Gerätehardware diese Streams sogar
weiter ausbauen.
Kotlin
// Retrieve the target surfaces, which might be coming from a number of places: // 1. SurfaceView, if you want to display the image directly to the user // 2. ImageReader, if you want to read each frame or perform frame-by-frame // analysis // 3. OpenGL Texture or TextureView, although discouraged for maintainability reasons // 4. RenderScript.Allocation, if you want to do parallel processing val surfaceView = findViewByIdS<urfaceView(>...) val imageReader = ImageReader.newInstance(...) // Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated() val previewSurface = surfaceView.holder.surface val imReaderSurface = imageReader.surface val targets = listOf(previewSurface, imReaderSurface) // Create a capture session using the predefined targets; this also involves // defining the session state callback to be notified of when the session is // ready // Setup Stream Use Case while setting up your Output Configuration. @RequiresApi(Build.VERSION_CODES.TIRAMISU) fun configureSession(device: CameraDevice, targets: ListS<urface)>{ val configs = mutableListOfO<utputConfiguration(>) val streamUseCase = CameraMetadata .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL targets.forEach { val config = OutputConfiguration(it) config.streamUseCase = streamUseCase.toLong() configs.add(config) } ... device.createCaptureSession(session) }
Java
// Retrieve the target surfaces, which might be coming from a number of places: // 1. SurfaceView, if you want to display the image directly to the user // 2. ImageReader, if you want to read each frame or perform frame-by-frame analysis // 3. RenderScript.Allocation, if you want to do parallel processing // 4. OpenGL Texture or TextureView, although discouraged for maintainability reasons Surface surfaceView = findViewByIdS<urfaceView(>...); ImageReader imageReader = ImageReader.newInstance(...); // Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated() Surface previewSurface = surfaceView.getHolder().getSurface(); Surface imageSurface = imageReader.getSurface(); ListS<urface >targets = Arrays.asList(previewSurface, imageSurface); // Create a capture session using the predefined targets; this also involves defining the // session state callback to be notified of when the session is ready private void configureSession(CameraDevice device, ListS<urface >targets){ ArrayListO<utputConfiguration >configs= new ArrayList() String streamUseCase= CameraMetadata .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL for(Surface s : targets){ OutputConfiguration config = new OutputConfiguration(s) config.setStreamUseCase(String.toLong(streamUseCase)) configs.add(config) } device.createCaptureSession(session) }
Du hast die aktive Konfiguration der Kamera noch nicht definiert. Wenn die Sitzung konfiguriert ist, können Sie Erfassungen erstellen und senden um dies zu tun.
Die Transformation, die auf Eingaben angewendet wird, wenn diese in ihren Zwischenspeicher geschrieben werden, ist
die vom jeweiligen Zieltyp bestimmt werden. Dieser muss ein
Surface
Das Android-Framework weiß,
ein Rohbild in der aktiven Konfiguration in ein Format konvertieren, das für
für jedes Ziel. Die Conversion wird durch das Pixelformat und die Größe des
insbesondere Surface
.
Das Framework versucht, sein Bestes zu geben, aber einige Surface
Konfigurationskombinationen funktionieren möglicherweise nicht, was zu Problemen wie der Sitzung
nicht erstellt wird, beim Absenden einer Anfrage ein Laufzeitfehler ausgegeben wird, oder
Leistungseinbußen. Das Framework garantiert bestimmte
Kombinationen von Geräte-, Oberflächen- und Anfrageparametern. Die Dokumentation für
createCaptureSession()
erhalten Sie weitere Informationen.
Einzelne Erfassungsanfragen
Die für jeden Frame verwendete Konfiguration ist in einem CaptureRequest
codiert, der
an die Kamera gesendet. Um eine Aufnahmeanfrage zu erstellen, können Sie eine der
vordefinierte
Vorlagen,
oder TEMPLATE_MANUAL
für die vollständige Kontrolle verwenden. Wenn Sie eine
müssen Sie einen oder mehrere Ausgabepuffer zur Verwendung mit
der Anfrage. Sie können nur Zwischenspeicher verwenden, die bereits für die Erfassung definiert wurden
Sitzung, die Sie verwenden möchten.
Bei Erfassungsanfragen wird ein
Builder-Muster
und geben Entwicklern die Möglichkeit, viele verschiedene
Optionen, darunter
automatische Belichtung
Autofokus
und
Blende.
Vergewissern Sie sich vor dem Festlegen eines Felds, dass die entsprechende Option für das
Gerät durch einen Anruf
CameraCharacteristics.getAvailableCaptureRequestKeys()
und ob der gewünschte Wert durch Aktivieren der entsprechenden Kamera unterstützt wird.
wie etwa die verfügbare Funktion für die automatische Belichtung
Modi.
So erstellen Sie mithilfe der Vorlage eine Erfassungsanfrage für ein SurfaceView
:
die ohne Änderungen für eine Vorschau vorgesehen sind,
CameraDevice.TEMPLATE_PREVIEW
:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) captureRequest.addTarget(previewSurface)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest.Builder captureRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequest.addTarget(previewSurface);
Wenn eine Erfassungsanfrage definiert ist, können Sie jetzt Weiterleitungen an die Kamerasitzung senden:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest = ... // from CameraDevice.createCaptureRequest() // The first null argument corresponds to the capture callback, which you // provide if you want to retrieve frame metadata or keep track of failed capture // requests that can indicate dropped frames; the second null argument // corresponds to the Handler used by the asynchronous callback, which falls // back to the current thread's looper if null session.capture(captureRequest.build(), null, null)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest captureRequest = ...; // from CameraDevice.createCaptureRequest() // The first null argument corresponds to the capture callback, which you // provide if you want to retrieve frame metadata or keep track of failed // capture // requests that can indicate dropped frames; the second null argument // corresponds to the Handler used by the asynchronous callback, which falls // back to the current thread's looper if null session.capture(captureRequest.build(), null, null);
Wenn ein Ausgabe-Frame in einen spezifischen Zwischenspeicher gestellt wird, erscheint eine Aufnahme
Callback
ausgelöst wird. In vielen Fällen werden zusätzliche Callbacks, wie z. B.
ImageReader.OnImageAvailableListener
,
wird ausgelöst, wenn der darin enthaltene Frame verarbeitet wird. Ort
können Sie Bilddaten
aus dem angegebenen Zwischenspeicher abrufen.
CaptureRequests wiederholen
Anfragen für eine einzelne Kamera sind einfach, aber für die Anzeige eines Vorschau oder Video, sind sie nicht sehr nützlich. In diesem Fall müssen Sie eine kontinuierlichen Stream von Frames, nicht nur von einem einzelnen. Das folgende Code-Snippet zeigt, wie Sie ein wiederholte Anfrage zum Meeting hinzufügen:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest = ... // from CameraDevice.createCaptureRequest() // This keeps sending the capture request as frequently as possible until // the // session is torn down or session.stopRepeating() is called // session.setRepeatingRequest(captureRequest.build(), null, null)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest captureRequest = ...; // from CameraDevice.createCaptureRequest() // This keeps sending the capture request as frequently as possible until the // session is torn down or session.stopRepeating() is called // session.setRepeatingRequest(captureRequest.build(), null, null);
Bei einer sich wiederholenden Aufnahmeanforderung nimmt die Kamera kontinuierlich Aufnahmen auf.
mit den Einstellungen in den angegebenen CaptureRequest
. Die Camera2 API
können Nutzer auch Videos mit der Kamera aufnehmen, indem sie
CaptureRequests
wird wiederholt, wie hier zu sehen
Kamera2-Beispiel
auf GitHub. Videos in Zeitlupe können auch gerendert werden, indem ein
Hochgeschwindigkeitsvideo (Zeitlupe) mit sich wiederholender Bilderfolge CaptureRequests
wie in der Beispiel-App in Zeitlupe von Kamera2 gezeigt.
auf GitHub.
CaptureRequests verschachteln
Um eine zweite Aufnahmeanfrage zu senden, während die wiederkehrende Erfassungsanfrage aktiv ist, etwa um einen Sucher anzuzeigen und Nutzern die Möglichkeit zu bieten, ein Foto aufzunehmen, müssen Sie sich die laufende wiederholte Anfrage anzuhalten. Sie führen stattdessen eine sich nicht wiederholende Aufnahme aus. -Anforderung, während die wiederkehrende Anfrage weiter ausgeführt wird.
Jeder verwendete Ausgabezwischenspeicher muss als Teil der Kamerasitzung konfiguriert werden wenn die Sitzung neu erstellt wird. Wiederkehrende Anfragen haben eine niedrigere Priorität als Einzel-Frame- oder Burst-Anfragen, mit denen folgendes Beispiel funktioniert:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback // Create the repeating request and dispatch it val repeatingRequest = session.device.createCaptureRequest( CameraDevice.TEMPLATE_PREVIEW) repeatingRequest.addTarget(previewSurface) session.setRepeatingRequest(repeatingRequest.build(), null, null) // Some time later... // Create the single request and dispatch it // NOTE: This can disrupt the ongoing repeating request momentarily val singleRequest = session.device.createCaptureRequest( CameraDevice.TEMPLATE_STILL_CAPTURE) singleRequest.addTarget(imReaderSurface) session.capture(singleRequest.build(), null, null)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback // Create the repeating request and dispatch it CaptureRequest.Builder repeatingRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); repeatingRequest.addTarget(previewSurface); session.setRepeatingRequest(repeatingRequest.build(), null, null); // Some time later... // Create the single request and dispatch it // NOTE: This can disrupt the ongoing repeating request momentarily CaptureRequest.Builder singleRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); singleRequest.addTarget(imReaderSurface); session.capture(singleRequest.build(), null, null);
Dieser Ansatz hat jedoch auch einen Nachteil: Sie wissen nicht genau, wann die einzelne Anfrage erfolgt. Wenn in der folgenden Abbildung A die sich wiederholende und B die Einzelframe-Erfassungsanfrage. -Sitzung verarbeitet die Anfragewarteschlange:
<ph type="x-smartling-placeholder">![](https://developer.android.google.cn/static/images/training/camera/camera2/capture-sessions-requests-2.png?authuser=8&hl=de)
Es gibt keine Garantien für die Latenz zwischen der letzten sich wiederholenden Anfrage von A, bevor Anfrage B aktiviert wird und A das nächste Mal verwendet wird kann es passieren, dass einige Frames übersprungen werden. Es gibt einige Dinge, können Sie dieses Problem beheben:
Fügen Sie die Ausgabeziele aus Anfrage A zu Anfrage B hinzu. Auf diese Weise B-Frame bereit ist, wird er in die Ausgabeziele von A kopiert. Dies ist beispielsweise wichtig, wenn Video-Snapshots erstellt werden, um die Framerate stabilisieren. Im obigen Code fügen Sie
singleRequest.addTarget(previewSurface)
, bevor Sie die Anfrage erstellen.Verwenden Sie eine Kombination aus Vorlagen, die sich für dieses spezielle Szenario eignen, wie z. B. ohne Verzögerung.