Wenn in Ihrer App das ursprüngliche Camera
verwendet wird
Klasse ("Camera1"), die seit der Einführung von
Android 5.0 (API-Level 21),
empfehlen wir die Aktualisierung auf eine moderne Android-Kamera-API. Android-Angebote
CameraX (eine standardisierte, robuste Jetpack-Kamera
API) und Camera2 (eine Low-Level-Framework-API). Für die
In den allermeisten Fällen empfehlen wir die Migration deiner App zu CameraX. Aus folgenden Gründen:
- Nutzerfreundlichkeit:CameraX übernimmt die Details auf niedriger Ebene, sodass Sie weniger darauf konzentrieren, ein Kameraerlebnis von Grund auf neu zu entwickeln, Ihre App hervorzuheben.
- CameraX sorgt für Fragmentierung:CameraX reduziert langfristige Wartungskosten und gerätespezifischer Code für eine bessere User Experience für Nutzende zu machen. Weitere Informationen hierzu finden Sie in der Bessere Gerätekompatibilität mit CameraX Blogpost.
- Erweiterte Funktionen:CameraX wurde sorgfältig entwickelt, um Funktionen, die sich einfach in Ihre App integrieren lassen. Zum Beispiel können Sie ganz einfach Bokeh-Funktion, Gesichtsretusche, HDR (High Dynamic Range) und Helligkeit bei schlechten Lichtverhältnissen Nachtaufnahmemodus für deine Fotos mit CameraX-Erweiterungen:
- Aktualisierbarkeit:Android veröffentlicht neue Funktionen und Fehlerkorrekturen für CameraX im Laufe des Jahres. Durch die Migration zu CameraX erhält deine App die aktuelle Android-Version Kameratechnologie bei jeder neuen CameraX-Version, nicht nur auf der jährliche Veröffentlichungen der Android-Version.
In diesem Handbuch werden gängige Szenarien für Kameraanwendungen beschrieben. Jedes umfasst eine Camera1-Implementierung und eine CameraX-Implementierung für vergleichen.
Bei der Migration benötigen Sie manchmal zusätzliche Flexibilität,
mit einer vorhandenen Codebasis. Der gesamte CameraX-Code in diesem Handbuch enthält ein
CameraController
ist ideal, wenn ihr CameraX auf einfache Weise nutzen möchtet.
CameraProvider
Implementierung – ideal, wenn Sie mehr Flexibilität benötigen. Um Ihnen bei der Entscheidung zu helfen,
das richtige für Sie ist, finden Sie hier die jeweiligen Vorteile:
Kamera-Controller |
Kameraanbieter |
Wenig Einrichtungscode erforderlich | Mehr Kontrolle |
Wenn CameraX einen größeren Einrichtungsvorgang ausführen kann, Funktionen wie Tippen zum Fokussieren und Zoomen durch Auseinander- und Zusammenziehen funktionieren automatisch |
Da der App-Entwickler die Einrichtung übernimmt,
zum Anpassen der Konfiguration, z. B. zum Aktivieren der Ausgabebildrotation
oder das Ausgabebildformat in ImageAnalysis festlegen
|
Wenn PreviewView für die Kameravorschau erforderlich ist,
CameraX für eine nahtlose End-to-End-Integration wie in unserem ML-Kit.
Integration, die die Ergebniskoordinaten des ML-Modells (z. B. Gesicht) zuordnen kann.
Begrenzungsrahmen) direkt auf die Vorschaukoordinaten
|
Die Verwendung einer benutzerdefinierten Oberfläche für die Kameravorschau ermöglicht mehr Flexibilität bieten, indem Sie z. B. Ihren vorhandenen Oberflächencode verwenden, kann eine Eingabe für andere Teile Ihrer App sein. |
Wenn Sie bei der Migration nicht weiterkommen, kontaktieren Sie uns auf der CameraX-Diskussionsgruppe
Vor der Migration
Nutzung von CameraX und Camera1 vergleichen
Der Code kann zwar anders aussehen, aber die zugrunde liegenden Konzepte in Camera1 und
CameraX sind sich sehr ähnlich. KameraX
bündelt gängige Kamerafunktionen für Anwendungsfälle,
Viele Aufgaben, die dem Entwickler in der App „Kamera1“ überlassen waren,
automatisch von CameraX verarbeitet. Es gibt vier
UseCase
s in CameraX, die Sie
verschiedene Kameraaufgaben verwenden: Preview
,
ImageCapture
,
VideoCapture
und
ImageAnalysis
.
Ein Beispiel dafür, wie CameraX für Entwickler Low-Level-Details verarbeitet, ist die
ViewPort
, das gemeinsam genutzt wird
aktive UseCase
s. Dadurch wird sichergestellt, dass alle UseCase
-Elemente genau die gleichen Pixel sehen.
In Kamera1 musst du diese Details selbst verwalten. Aufgrund der Unterschiede
in den Seitenverhältnissen auf den verschiedenen Geräten Kamera-Sensoren und -Bildschirme, kann es schwierig sein,
dass die Vorschau mit den aufgenommenen Fotos und Videos übereinstimmt.
Ein weiteres Beispiel: CameraX verarbeitet Lifecycle
-Callbacks automatisch auf der
Lifecycle
-Instanz übergeben, wenn Sie sie übergeben. Das bedeutet, dass CameraX die Daten
die Verbindung zur Kamera während der gesamten
Android-Aktivitätslebenszyklus
einschließlich der folgenden Fälle: Schließen der Kamera, wenn Ihre App in den
Hintergrund; Kameravorschau entfernen, wenn der Bildschirm keine weiteren
Anzeige und die Kameravorschau anhalten, wenn eine andere Aktivität
Vorrang vor einem eingehenden Videoanruf haben.
CameraX übernimmt die Drehung und Skalierung, ohne dass zusätzlicher Code erforderlich ist.
Ihrerseits. Bei einem Activity
mit einer nicht gesperrten Ausrichtung
Die Einrichtung von UseCase
wird jedes Mal abgeschlossen, wenn das Gerät gedreht wird, während das System zerstört wird
und erstellt den Activity
neu, wenn sich die Ausrichtung ändert. Daraus ergibt sich die
UseCases
: Legt die Zieldrehung so fest, dass sie der Ausrichtung des Displays entspricht, indem
immer wieder Standardeinstellungen festlegen.
Weitere Informationen zu Drehungen in KameraX
Werfen wir einen kurzen Blick auf die Kamera von CameraX, bevor wir ins Detail gehen.
UseCase
und wie eine Kamera1-App funktionieren würde. (Die CameraX-Konzepte finden Sie
blue und Camera1
Konzepte sind in
green)
KameraX |
|||
CameraController / CameraProvider-Konfiguration | |||
↓ | ↓ | ↓ | ↓ |
Vorschau | Bilderfassung | Videoaufzeichnung | Bildanalyse |
⁞ | ⁞ | ⁞ | ⁞ |
Surface-Vorschau verwalten und auf Kamera einrichten | PictureCallback einrichten und „takePicture()“ auf der Kamera aufrufen | Kamera- und MediaRecorder-Konfiguration in bestimmter Reihenfolge verwalten | Benutzerdefinierter Analysecode, der auf der Oberfläche der Vorabversion basiert |
↑ | ↑ | ↑ | ↑ |
Gerätespezifischer Code | |||
↑ | |||
Verwaltung der Geräterotation und -skalierung | |||
↑ | |||
Verwaltung von Kamerasitzungen (Kameraauswahl, Verwaltung des Lebenszyklus) | |||
Kamera1 |
Kompatibilität und Leistung in CameraX
CameraX unterstützt Geräte mit Android 5.0 (API-Level 21) und höher. Dieses machen mehr als 98% aller vorhandenen Android-Geräte aus. CameraX kann automatisch Unterschiede zwischen den Geräten, sodass weniger gerätespezifische Code in Ihrer App. Außerdem testen wir über 150 physische Geräte auf allen Android-Geräten, Versionen seit 5.0 finden Sie in unserem CameraX Test Lab. Ich können Sie sich die vollständige Liste Geräten, die sich derzeit im Test Lab befinden.
CameraX nutzt ein Executor
, um
für den Kamera-Stack. Sie können
Eigenen Executor auf CameraX festlegen
ob Ihre Anwendung bestimmte Threading-Anforderungen hat. Ist die Richtlinie nicht konfiguriert, erstellt CameraX
und verwendet eine optimierte standardmäßige Executor
. Viele der Plattform-APIs auf
welche CameraX-Technologie entwickelt wurde, müssen die Interprozesskommunikation (IPC) mit
Hardware, die manchmal Hunderte von Millisekunden
dauert, um zu reagieren. In diesem Fall
KameraX ruft diese APIs nur aus Hintergrundthreads auf. Dadurch wird sichergestellt,
Hauptthread nicht blockiert ist und die Benutzeroberfläche flexibel bleibt.
Weitere Informationen zu Threads
Wenn der Zielmarkt für Ihre App Low-End-Geräte sind, bietet CameraX eine
die Einrichtungszeit mit einem
Kamerabegrenzung. Da die
Das Herstellen einer Verbindung zu Hardwarekomponenten kann eine nicht unerhebliche Menge an
insbesondere auf Low-End-Geräten, kannst du den Satz an Kameras festlegen,
Anforderungen. CameraX stellt nur während der Einrichtung eine Verbindung zu diesen Kameras her. Wenn beispielsweise
die Anwendung nur rückseitige Kameras verwendet, kann diese Konfiguration
mit DEFAULT_BACK_CAMERA
und CameraX vermeidet eine Initialisierung der Frontkamera.
um die Latenz zu verringern.
Konzepte der Android-Entwicklung
In diesem Leitfaden wird davon ausgegangen, dass Sie mit der Android-Entwicklung vertraut sind. Jenseits der sollten Sie einige Konzepte kennen, direkt in den Code einzusteigen:
- View Binding generiert eine Bindungsklasse für
XML-Layoutdateien, sodass Sie
Auf Ihre Ansichten in Aktivitäten verweisen,
Dies geschieht in den folgenden Code-Snippets. Es gibt einige
Unterschiede zwischen Ansichtsbindung und
findViewById()
(frühere Methode zum Referenzieren von Ansichten). Im folgenden Code sollten Sie jedoch in der Lage sein, ersetzen Sie die Bindungszeilen der Ansicht durch einen ähnlichenfindViewById()
-Aufruf. - Asynchrone Koroutinen sind ein Gleichzeitigkeitsdesign.
In Kotlin 1.3 hinzugefügtes Muster, das zur Verarbeitung von CameraX-Methoden verwendet werden kann, die
ListenableFuture
zurückgeben. Mit dem Jetpack ist das jetzt noch einfacher Gleichzeitige Bibliothek ab Version 1.1.0. So fügen Sie Ihrer Anwendung eine asynchrone Koroutine hinzu: <ph type="x-smartling-placeholder">- </ph>
implementation("androidx.concurrent:concurrent-futures-ktx:1.1.0")
hinzufügen in Ihre Gradle-Datei ein.- Fügen Sie einen beliebigen CameraX-Code, der ein
ListenableFuture
zurückgibt, in einlaunch
blockieren oder Unterbrechungsfunktion. - Hinzufügen eines
await()
Aufruf des Funktionsaufrufs, der eineListenableFuture
zurückgibt. - Detaillierte Informationen zur Funktionsweise von Koroutinen finden Sie in den Anleitung zum Starten einer gemeinsamen Routine
Häufige Szenarien migrieren
In diesem Abschnitt wird erläutert, wie du häufige Szenarien von Kamera1 zu CameraX migrieren kannst.
Jedes Szenario umfasst eine Camera1-Implementierung, eine CameraX-CameraProvider
und eine CameraController
-Implementierung von CameraX.
Kamera auswählen
Zunächst sollten Sie in Ihrer Kamera-App Kameras auswählen.
Kamera1
In Kamera1 können Sie entweder
Camera.open()
ohne Parameter
um die erste Kamera auf der Rückseite zu öffnen. Alternativ können Sie eine ganzzahlige ID für die
Kamera, die Sie öffnen möchten. So könnte das aussehen:
// Camera1: select a camera from id. // Note: opening the camera is a non-trivial task, and it shouldn't be // called from the main thread, unlike CameraX calls, which can be // on the main thread since CameraX kicks off background threads // internally as needed. private fun safeCameraOpen(id: Int): Boolean { return try { releaseCameraAndPreview() camera = Camera.open(id) true } catch (e: Exception) { Log.e(TAG, "failed to open camera", e) false } } private fun releaseCameraAndPreview() { preview?.setCamera(null) camera?.release() camera = null }
CameraX: CameraController
In CameraX wird die Kameraauswahl von der Klasse CameraSelector
übernommen. KameraX
erleichtert den Einsatz der Standardkamera. Sie können angeben,
die Standard-Frontkamera oder die Standard-Rückkamera. Außerdem
Mit dem Objekt CameraControl
von CameraX kannst du
die Zoomstufe für Ihre App festlegen. Wenn
Ihre App auf einem Gerät ausgeführt wird,
logischen Kameras und wechselt dann
in das richtige Objektiv.
Hier ist der CameraX-Code für die Verwendung der Standard-Rückkamera mit einem
CameraController
:
// CameraX: select a camera with CameraController var cameraController = LifecycleCameraController(baseContext) val selector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK).build() cameraController.cameraSelector = selector
CameraX: CameraProvider
Hier ein Beispiel für die Auswahl der Standard-Frontkamera mit CameraProvider
(entweder die Front- oder Rückkamera kann mit CameraController
oder
CameraProvider
):
// CameraX: select a camera with CameraProvider. // Use await() within a suspend function to get CameraProvider instance. // For more details on await(), see the "Android development concepts" // section above. private suspend fun startCamera() { val cameraProvider = ProcessCameraProvider.getInstance(this).await() // Set up UseCases (more on UseCases in later scenarios) var useCases:Array= ... // Set the cameraSelector to use the default front-facing (selfie) // camera. val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA try { // Unbind UseCases before rebinding. cameraProvider.unbindAll() // Bind UseCases to camera. This function returns a camera // object which can be used to perform operations like zoom, // flash, and focus. var camera = cameraProvider.bindToLifecycle( this, cameraSelector, useCases) } catch(exc: Exception) { Log.e(TAG, "UseCase binding failed", exc) } }) ... // Call startCamera in the setup flow of your app, such as in onViewCreated. override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) ... lifecycleScope.launch { startCamera() } }
Wenn Sie steuern möchten, welche Kamera ausgewählt wird, können Sie das auch in
CameraX, wenn Sie CameraProvider
über einen Anruf
getAvailableCameraInfos()
,
Damit erhalten Sie ein CameraInfo
-Objekt, mit dem Sie bestimmte Kameraeigenschaften wie
isFocusMeteringSupported()
Anschließend können Sie ihn in ein CameraSelector
konvertieren, um es wie oben zu verwenden.
mit der Methode CameraInfo.getCameraSelector()
.
Weitere Informationen zu den einzelnen Kameras erhalten Sie über das
Camera2CameraInfo
. Anruf
getCameraCharacteristic()
mit einem Schlüssel für die gewünschten Kameradaten. Prüfen Sie die
CameraCharacteristics
Klasse, um eine Liste aller Schlüssel zu erhalten, die Sie abfragen können.
Hier ist ein Beispiel mit einer benutzerdefinierten checkFocalLength()
-Funktion, die Sie
Definieren Sie sich selbst:
// CameraX: get a cameraSelector for first camera that matches the criteria // defined in checkFocalLength(). val cameraInfo = cameraProvider.getAvailableCameraInfos() .first { cameraInfo -> val focalLengths = Camera2CameraInfo.from(cameraInfo) .getCameraCharacteristic( CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS ) return checkFocalLength(focalLengths) } val cameraSelector = cameraInfo.getCameraSelector()
Vorschau wird angezeigt
Bei den meisten Kamera-Apps muss der Kamerafeed an manchen Punkt. Mit Camera1 musst du die Lebenszyklus-Callbacks richtig verwalten müssen Sie auch die Rotation und Skalierung für die Vorschau festlegen.
Außerdem müssen Sie in Kamera1 festlegen, ob Sie ein
TextureView
oder
SurfaceView
als Vorschauoberfläche aus.
Beide Optionen haben Vor- und Nachteile. In beiden Fällen müssen Sie für Kamera1
die Drehung und Skalierung
richtig zu handhaben. PreviewView
von CameraX auf der anderen
liegen zugrunde liegende Implementierungen für TextureView
und SurfaceView
.
CameraX entscheidet anhand von Faktoren wie
vom Gerätetyp und von der Android-Version,
auf der die App ausgeführt wird. Wenn entweder
Implementierung kompatibel ist, können Sie Ihre Präferenzen
PreviewView.ImplementationMode
Die Option COMPATIBLE
verwendet ein TextureView
für die Vorschau und das
Für den PERFORMANCE
-Wert wird nach Möglichkeit SurfaceView
verwendet.
Kamera1
Wenn Sie eine Vorschau sehen möchten, müssen Sie Ihren eigenen Preview
-Kurs mit einem
Implementierung der
android.view.SurfaceHolder.Callback
über die Bilddaten von der Kamerahardware an den
. Bevor Sie die Live-Bildvorschau starten können, muss der Preview
-Klasse muss an das Camera
-Objekt übergeben werden.
// Camera1: set up a camera preview. class Preview( context: Context, private val camera: Camera ) : SurfaceView(context), SurfaceHolder.Callback { private val holder: SurfaceHolder = holder.apply { addCallback(this@Preview) 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. camera.apply { try { setPreviewDisplay(holder) startPreview() } catch (e: IOException) { Log.d(TAG, "error setting camera preview", e) } } } override fun surfaceDestroyed(holder: SurfaceHolder) { // 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 (holder.surface == null) { return // The preview surface does not exist. } // Stop preview before making changes. try { camera.stopPreview() } catch (e: Exception) { // Tried to stop a non-existent preview; nothing to do. } // Set preview size and make any resize, rotate or // reformatting changes here. // Start preview with new settings. camera.apply { try { setPreviewDisplay(holder) startPreview() } catch (e: Exception) { Log.d(TAG, "error starting camera preview", e) } } } } class CameraActivity : AppCompatActivity() { private lateinit var viewBinding: ActivityMainBinding private var camera: Camera? = null private var preview: Preview? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewBinding = ActivityMainBinding.inflate(layoutInflater) setContentView(viewBinding.root) // Create an instance of Camera. camera = getCameraInstance() preview = camera?.let { // Create the Preview view. Preview(this, it) } // Set the Preview view as the content of the activity. val cameraPreview: FrameLayout = viewBinding.cameraPreview cameraPreview.addView(preview) } }
CameraX: CameraController
In CameraX müssen Sie als Entwickler viel weniger verwalten. Wenn Sie eine
CameraController
eingeben, müssen Sie auch PreviewView
verwenden. Das bedeutet, dass der
Preview
UseCase
wird impliziert, wodurch die Einrichtung wesentlich weniger aufwendig ist:
// CameraX: set up a camera preview with a CameraController. class MainActivity : AppCompatActivity() { private lateinit var viewBinding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewBinding = ActivityMainBinding.inflate(layoutInflater) setContentView(viewBinding.root) // Create the CameraController and set it on the previewView. var cameraController = LifecycleCameraController(baseContext) cameraController.bindToLifecycle(this) val previewView: PreviewView = viewBinding.cameraPreview previewView.controller = cameraController } }
CameraX: CameraProvider
Mit CameraProvider
von CameraX brauchst du PreviewView
nicht, aber es
die Einrichtung der Vorschau über Kamera1 immer noch erheblich vereinfacht. Zu Demonstrationszwecken
wird in diesem Beispiel ein PreviewView
verwendet. Sie können aber auch ein benutzerdefiniertes
SurfaceProvider
, um an setSurfaceProvider()
zu übergeben, wenn Sie eine komplexere Abfrage haben
Anforderungen.
Hier wird der UseCase
von Preview
nicht wie bei CameraController
impliziert,
Sie müssen es also einrichten:
// CameraX: set up a camera preview with a CameraProvider. // Use await() within a suspend function to get CameraProvider instance. // For more details on await(), see the "Android development concepts" // section above. private suspend fun startCamera() { val cameraProvider = ProcessCameraProvider.getInstance(this).await() // Create Preview UseCase. val preview = Preview.Builder() .build() .also { it.setSurfaceProvider( viewBinding.viewFinder.surfaceProvider ) } // Select default back camera. val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA try { // Unbind UseCases before rebinding. cameraProvider.unbindAll() // Bind UseCases to camera. This function returns a camera // object which can be used to perform operations like zoom, // flash, and focus. var camera = cameraProvider.bindToLifecycle( this, cameraSelector, useCases) } catch(exc: Exception) { Log.e(TAG, "UseCase binding failed", exc) } }) ... // Call startCamera() in the setup flow of your app, such as in onViewCreated. override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) ... lifecycleScope.launch { startCamera() } }
Zum Fokussieren tippen
Wenn die Kameravorschau auf dem Bildschirm angezeigt wird, wenn Nutzende auf die Vorschau tippen.
Kamera1
Um den Tap-to-Fokus in Kamera1 zu implementieren, müssen Sie den optimalen Fokus berechnen
Area
, um anzugeben, worauf sich Camera
konzentrieren soll. Dieses Gerät (Area
) ist
an setFocusAreas()
übergeben. Außerdem müssen Sie auf dem Display einen kompatiblen Fokusmodus einstellen,
Camera
Der Fokusbereich wird nur angewendet, wenn der aktuelle Fokusmodus
FOCUS_MODE_AUTO
, FOCUS_MODE_MACRO
, FOCUS_MODE_CONTINUOUS_VIDEO
oder
FOCUS_MODE_CONTINUOUS_PICTURE
.
Jedes Area
ist ein Rechteck mit einer angegebenen Gewichtung. Die Gewichtung ist ein Wert zwischen
1 und 1.000. Sie wird verwendet, um den Fokus Areas
zu priorisieren, wenn mehrere festgelegt sind. Dieses
Beispiel verwendet nur ein Area
, daher spielt der Gewichtungswert keine Rolle. Koordinaten von
Rechtecks von -1.000 bis 1.000. Der obere linke Punkt ist (-1000, -1000).
Der untere rechte Punkt ist (1.000, 1.000). Die Richtung ist relativ zum Sensor
d. h., was der Sensor sieht. Die Richtung wird vom
Drehung oder Spiegelung von Camera.setDisplayOrientation()
. Sie müssen also
Koordinaten des Touch-Ereignisses in Sensorkoordinaten konvertieren.
// Camera1: implement tap-to-focus. class TapToFocusHandler : Camera.AutoFocusCallback { private fun handleFocus(event: MotionEvent) { val camera = camera ?: return val parameters = try { camera.getParameters() } catch (e: RuntimeException) { return } // Cancel previous auto-focus function, if one was in progress. camera.cancelAutoFocus() // Create focus Area. val rect = calculateFocusAreaCoordinates(event.x, event.y) val weight = 1 // This value's not important since there's only 1 Area. val focusArea = Camera.Area(rect, weight) // Set the focus parameters. parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO) parameters.setFocusAreas(listOf(focusArea)) // Set the parameters back on the camera and initiate auto-focus. camera.setParameters(parameters) camera.autoFocus(this) } private fun calculateFocusAreaCoordinates(x: Int, y: Int) { // Define the size of the Area to be returned. This value // should be optimized for your app. val focusAreaSize = 100 // You must define functions to rotate and scale the x and y values to // be values between 0 and 1, where (0, 0) is the upper left-hand side // of the preview, and (1, 1) is the lower right-hand side. val normalizedX = (rotateAndScaleX(x) - 0.5) * 2000 val normalizedY = (rotateAndScaleY(y) - 0.5) * 2000 // Calculate the values for left, top, right, and bottom of the Rect to // be returned. If the Rect would extend beyond the allowed values of // (-1000, -1000, 1000, 1000), then crop the values to fit inside of // that boundary. val left = max(normalizedX - (focusAreaSize / 2), -1000) val top = max(normalizedY - (focusAreaSize / 2), -1000) val right = min(left + focusAreaSize, 1000) val bottom = min(top + focusAreaSize, 1000) return Rect(left, top, left + focusAreaSize, top + focusAreaSize) } override fun onAutoFocus(focused: Boolean, camera: Camera) { if (!focused) { Log.d(TAG, "tap-to-focus failed") } } }
CameraX: CameraController
CameraController
hört zur Verarbeitung auf Touch-Events von PreviewView
automatisch durch Tippen fokussieren. Du kannst den Touchpad-Fokus aktivieren oder deaktivieren:
setTapToFocusEnabled()
,
und prüfen Sie den Wert mit dem entsprechenden Getter
isTapToFocusEnabled()
Die
getTapToFocusState()
Methode gibt ein LiveData
-Objekt zurück.
zum Nachverfolgen von Änderungen des Fokusstatus auf CameraController
.
// CameraX: track the state of tap-to-focus over the Lifecycle of a PreviewView, // with handlers you can define for focused, not focused, and failed states. val tapToFocusStateObserver = Observer{ state -> when (state) { CameraController.TAP_TO_FOCUS_NOT_STARTED -> Log.d(TAG, "tap-to-focus init") CameraController.TAP_TO_FOCUS_STARTED -> Log.d(TAG, "tap-to-focus started") CameraController.TAP_TO_FOCUS_FOCUSED -> Log.d(TAG, "tap-to-focus finished (focus successful)") CameraController.TAP_TO_FOCUS_NOT_FOCUSED -> Log.d(TAG, "tap-to-focus finished (focused unsuccessful)") CameraController.TAP_TO_FOCUS_FAILED -> Log.d(TAG, "tap-to-focus failed") } } cameraController.getTapToFocusState().observe(this, tapToFocusStateObserver)
CameraX: CameraProvider
Bei Verwendung von CameraProvider
sind einige Einrichtungsschritte erforderlich, um den Fokus durch Tippen zu fokussieren
funktionieren. In diesem Beispiel wird davon ausgegangen, dass Sie PreviewView
verwenden. Falls nicht, müssen Sie
Passen Sie die Logik an, die auf Ihre benutzerdefinierte Surface
angewendet werden soll.
So verwendest du PreviewView
:
- Gestenerkennung einrichten, um Tippereignisse zu verarbeiten
- Erstellen Sie mit dem Tippereignis eine
MeteringPoint
mitMeteringPointFactory.createPoint()
. - Erstellen Sie mit der
MeteringPoint
eineFocusMeteringAction
. - Mit dem
CameraControl
-Objekt auf IhremCamera
(zurückgegeben vonbindToLifecycle()
), rufen SiestartFocusAndMetering()
auf und übergeben Sie dieFocusMeteringAction
- Optional: Antworten Sie auf die
FocusMeteringResult
. - Bewegungserkennung so einstellen, dass sie auf Touch-Ereignisse reagiert in
PreviewView.setOnTouchListener()
// CameraX: implement tap-to-focus with CameraProvider. // Define a gesture detector to respond to tap events and call // startFocusAndMetering on CameraControl. If you want to use a // coroutine with await() to check the result of focusing, see the // "Android development concepts" section above. val gestureDetector = GestureDetectorCompat(context, object : SimpleOnGestureListener() { override fun onSingleTapUp(e: MotionEvent): Boolean { val previewView = previewView ?: return val camera = camera ?: return val meteringPointFactory = previewView.meteringPointFactory val focusPoint = meteringPointFactory.createPoint(e.x, e.y) val meteringAction = FocusMeteringAction .Builder(meteringPoint).build() lifecycleScope.launch { val focusResult = camera.cameraControl .startFocusAndMetering(meteringAction).await() if (!result.isFocusSuccessful()) { Log.d(TAG, "tap-to-focus failed") } } } } ) ... // Set the gestureDetector in a touch listener on the PreviewView. previewView.setOnTouchListener { _, event -> // See pinch-to-zooom scenario for scaleGestureDetector definition. var didConsume = scaleGestureDetector.onTouchEvent(event) if (!scaleGestureDetector.isInProgress) { didConsume = gestureDetector.onTouchEvent(event) } didConsume }
Zum Zoomen auseinander- und zusammenziehen
Das Vergrößern und Verkleinern einer Vorschau ist eine weitere häufige direkte Bearbeitung Kameravorschau. Mit zunehmender Anzahl von Kameras auf den Geräten wird das Objektiv mit der besten Brennweite automatisch Ergebnis des Zoomens.
Kamera1
Es gibt zwei Möglichkeiten, mit Kamera 1 zu zoomen. Die Methode Camera.startSmoothZoom()
wird von der aktuellen Zoomstufe zur entsprechenden Zoomstufe gewechselt. Die
Die Camera.Parameters.setZoom()
-Methode springt direkt auf die Zoomstufe, die Sie übergeben.
. Bevor Sie eines verwenden, rufen Sie isSmoothZoomSupported()
auf oder
isZoomSupported()
, um sicherzustellen, dass die benötigten Zoommethoden verwendet werden
sind auf deiner Kamera verfügbar.
Zum Implementieren des Zoomens durch Auseinander- und Zusammenziehen der Finger wird in diesem Beispiel setZoom()
verwendet, da die Touch-Geste
Listener auf der Vorschauoberfläche löst kontinuierlich Ereignisse aus, wenn das Pinch
wird die Zoomstufe jedes Mal sofort aktualisiert. Die
Die Klasse ZoomTouchListener
ist unten definiert und sollte als Callback festgelegt werden
Touch-Listener für die Vorschauoberfläche.
// Camera1: implement pinch-to-zoom. // Define a scale gesture detector to respond to pinch events and call // setZoom on Camera.Parameters. val scaleGestureDetector = ScaleGestureDetector(context, object : ScaleGestureDetector.OnScaleGestureListener { override fun onScale(detector: ScaleGestureDetector): Boolean { val camera = camera ?: return false val parameters = try { camera.parameters } catch (e: RuntimeException) { return false } // In case there is any focus happening, stop it. camera.cancelAutoFocus() // Set the zoom level on the Camera.Parameters, and set // the Parameters back onto the Camera. val currentZoom = parameters.zoom parameters.setZoom(detector.scaleFactor * currentZoom) camera.setParameters(parameters) return true } } ) // Define a View.OnTouchListener to attach to your preview view. class ZoomTouchListener : View.OnTouchListener { override fun onTouch(v: View, event: MotionEvent): Boolean = scaleGestureDetector.onTouchEvent(event) } // Set a ZoomTouchListener to handle touch events on your preview view // if zoom is supported by the current camera. if (camera.getParameters().isZoomSupported()) { view.setOnTouchListener(ZoomTouchListener()) }
CameraX: CameraController
Ähnlich wie beim Tippen zum Fokussieren erfasst CameraController
die Berührung von PreviewView
-Ereignisse zum automatischen Zoomen durch Auseinander- und Zusammenziehen der Finger. Sie können die Funktion
Zoomen durch Auseinander- und Zusammenziehen
setPinchToZoomEnabled()
,
und prüfen Sie den Wert mit dem entsprechenden Getter
isPinchToZoomEnabled()
Die
getZoomState()
-Methode gibt ein LiveData
-Objekt zum Verfolgen von Änderungen an der
ZoomState
im
CameraController
// CameraX: track the state of pinch-to-zoom over the Lifecycle of // a PreviewView, logging the linear zoom ratio. val pinchToZoomStateObserver = Observer{ state -> val zoomRatio = state.getZoomRatio() Log.d(TAG, "ptz-zoom-ratio $zoomRatio") } cameraController.getZoomState().observe(this, pinchToZoomStateObserver)
CameraX: CameraProvider
Damit du mit CameraProvider
durch Auseinander- und Zusammenziehen der Finger zoomen kannst, sind einige Einrichtungsschritte erforderlich. Wenn
keine PreviewView
verwenden, müssen Sie die Logik für Ihre
benutzerdefiniert Surface
.
So verwendest du PreviewView
:
- Richten Sie einen Gestenerkennung für Skalierung ein, um Pinch-Ereignisse zu verarbeiten.
- Rufen Sie die
ZoomState
aus demCamera.CameraInfo
-Objekt ab, wobei dieCamera
-Instanz zurückgegeben, wenn SiebindToLifecycle()
- Wenn
ZoomState
einenzoomRatio
-Wert hat, speichere diesen als aktuellen Zoom Seitenverhältnis. Wenn sich aufZoomState
keinzoomRatio
befindet, verwende die Standardeinstellung der Kamera. Zoomstufe (1,0). - Das Produkt des aktuellen Zoomverhältnisses mit dem
scaleFactor
berechnen, das neue Zoomverhältnis bestimmen und anCameraControl.setZoomRatio()
übergeben. - Bewegungserkennung so einstellen, dass sie auf Touch-Ereignisse reagiert in
PreviewView.setOnTouchListener()
// CameraX: implement pinch-to-zoom with CameraProvider. // Define a scale gesture detector to respond to pinch events and call // setZoomRatio on CameraControl. val scaleGestureDetector = ScaleGestureDetector(context, object : SimpleOnGestureListener() { override fun onScale(detector: ScaleGestureDetector): Boolean { val camera = camera ?: return val zoomState = camera.cameraInfo.zoomState val currentZoomRatio: Float = zoomState.value?.zoomRatio ?: 1f camera.cameraControl.setZoomRatio( detector.scaleFactor * currentZoomRatio ) } } ) ... // Set the scaleGestureDetector in a touch listener on the PreviewView. previewView.setOnTouchListener { _, event -> var didConsume = scaleGestureDetector.onTouchEvent(event) if (!scaleGestureDetector.isInProgress) { // See pinch-to-zooom scenario for gestureDetector definition. didConsume = gestureDetector.onTouchEvent(event) } didConsume }
Foto machen
In diesem Abschnitt erfahren Sie, wie die Fotoaufnahme ausgelöst wird, wenn der Timer abgelaufen ist oder ein anderes Ereignis Auswahl.
Kamera1
In Camera1 definieren Sie zunächst eine
Camera.PictureCallback
um die Bilddaten zu verwalten, wenn sie angefordert werden. Hier ist ein einfaches Beispiel
PictureCallback
für die Verarbeitung von JPEG-Bilddaten:
// Camera1: define a Camera.PictureCallback to handle JPEG data. private val picture = 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) } catch (e: IOException) { Log.d(TAG, "error accessing file", e) } }
Wenn Sie dann ein Bild aufnehmen möchten, rufen Sie die Methode takePicture()
auf.
auf Ihrer Camera
-Instanz. Diese takePicture()
-Methode hat drei verschiedene
-Parameter für unterschiedliche Datentypen. Der erste Parameter ist für ein
ShutterCallback
(in diesem Beispiel nicht definiert). Der zweite Parameter ist
für eine PictureCallback
zur Verarbeitung der (unkomprimierten) Kamera-Rohdaten. Die dritte
der in diesem Beispiel verwendet wird, da es sich um einen PictureCallback
-Parameter handelt,
JPEG-Bilddaten.
// Camera1: call takePicture on Camera instance, passing our PictureCallback. camera?.takePicture(null, null, picture)
CameraX: CameraController
Mit CameraController
von CameraX wird die Einfachheit von Kamera1 für Bilder beibehalten.
indem Sie eine eigene takePicture()
-Methode implementieren. Definieren Sie hier
um einen MediaStore
-Eintrag zu konfigurieren und ein Foto aufzunehmen, das dort gespeichert wird.
// CameraX: define a function that uses CameraController to take a photo. private val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" private fun takePhoto() { // Create time stamped name and MediaStore entry. val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US) .format(System.currentTimeMillis()) val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image") } } // Create output options object which contains file + metadata. val outputOptions = ImageCapture.OutputFileOptions .Builder(context.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) .build() // Set up image capture listener, which is triggered after photo has // been taken. cameraController.takePicture( outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback { override fun onError(e: ImageCaptureException) { Log.e(TAG, "photo capture failed", e) } override fun onImageSaved( output: ImageCapture.OutputFileResults ) { val msg = "Photo capture succeeded: ${output.savedUri}" Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() Log.d(TAG, msg) } } ) }
CameraX: CameraProvider
Das Aufnehmen von Fotos mit CameraProvider
funktioniert fast genauso wie mit
CameraController
, aber Sie müssen zuerst ein ImageCapture
erstellen und binden.
UseCase
, um ein Objekt zum Aufrufen von takePicture()
zu haben:
// CameraX: create and bind an ImageCapture UseCase. // Make a reference to the ImageCapture UseCase at a scope that can be accessed // throughout the camera logic in your app. private var imageCapture: ImageCapture? = null ... // Create an ImageCapture instance (can be added with other // UseCase definitions). imageCapture = ImageCapture.Builder().build() ... // Bind UseCases to camera (adding imageCapture along with preview here, but // preview is not required to use imageCapture). This function returns a camera // object which can be used to perform operations like zoom, flash, and focus. var camera = cameraProvider.bindToLifecycle( this, cameraSelector, preview, imageCapture)
Dann können Sie jederzeit, wenn Sie ein Foto machen möchten,
ImageCapture.takePicture()
CameraController
-Code in diesem Abschnitt ansehen
finden Sie ein vollständiges Beispiel für die takePhoto()
-Funktion.
// CameraX: define a function that uses CameraController to take a photo. private fun takePhoto() { // Get a stable reference of the modifiable ImageCapture UseCase. val imageCapture = imageCapture ?: return ... // Call takePicture on imageCapture instance. imageCapture.takePicture( ... ) }
Video aufzeichnen
Das Aufzeichnen eines Videos ist wesentlich komplizierter als die vorgestellten Szenarien. . Jeder Teil des Prozesses muss ordnungsgemäß eingerichtet werden, in eine bestimmte Reihenfolge bringen. Außerdem müssen Sie möglicherweise überprüfen, Geräteinkonsistenzen zu synchronisieren oder zu beheben.
Wie ihr seht, übernimmt KameraX wieder einen Großteil dieser Komplexität für euch.
Kamera1
Für Videoaufnahmen mit Kamera1 ist eine sorgfältige Verwaltung von Camera
und
MediaRecorder
und die Methoden müssen
in einer bestimmten
Reihenfolge aufgerufen werden. Sie müssen diese Reihenfolge für
damit Ihre Anwendung ordnungsgemäß funktioniert:
- Öffne die Kamera.
- Bereiten Sie eine Vorschau vor und starten Sie sie. Wenn in Ihrer App das aufgezeichnete Video angezeigt wird, was normalerweise der Fall ist).
- Entsperre die Kamera zur Verwendung durch
MediaRecorder
, indem duCamera.unlock()
aufrufst. - Konfigurieren Sie die Aufzeichnung, indem Sie in
MediaRecorder
die folgenden Methoden aufrufen: <ph type="x-smartling-placeholder">- </ph>
- Verbinden Sie Ihre
Camera
-Instanz mitsetCamera(camera)
. setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
anrufen.setVideoSource(MediaRecorder.VideoSource.CAMERA)
anrufen.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_1080P))
anrufen um die Qualität festzulegen. Weitere Informationen finden Sie unterCamcorderProfile
für alle die Qualitätsoptionen.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString())
anrufen.- Wenn Ihre App eine Vorschau des Videos hat, rufen Sie
setPreviewDisplay(preview?.holder?.surface)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
anrufen.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
anrufen.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)
anrufen.- Rufe
prepare()
auf, um die Konfiguration vonMediaRecorder
abzuschließen.
- Verbinden Sie Ihre
- Wenn du die Aufzeichnung starten möchtest, ruf
MediaRecorder.start()
an. - Rufen Sie diese Methoden auf, um die Aufzeichnung zu beenden. Gehen Sie dabei genau wie folgt vor:
<ph type="x-smartling-placeholder">
- </ph>
MediaRecorder.stop()
anrufen.- Entfernen Sie optional die aktuelle
MediaRecorder
-Konfiguration, indem Sie folgenden Befehl aufrufen:MediaRecorder.reset()
. MediaRecorder.release()
anrufen.- Sperre die Kamera, damit sie in zukünftigen
MediaRecorder
-Sitzungen wie folgt verwendet werden kann:Camera.lock()
wird angerufen.
- Rufen Sie
Camera.stopPreview()
auf, um die Vorschau zu beenden. - Um den
Camera
freizugeben, damit andere Prozesse ihn verwenden können, rufen SieCamera.release()
.
Hier sind alle diese Schritte kombiniert:
// Camera1: set up a MediaRecorder and a function to start and stop video // recording. // Make a reference to the MediaRecorder at a scope that can be accessed // throughout the camera logic in your app. private var mediaRecorder: MediaRecorder? = null private var isRecording = false ... private fun prepareMediaRecorder(): Boolean { mediaRecorder = MediaRecorder() // Unlock and set camera to MediaRecorder. camera?.unlock() mediaRecorder?.run { setCamera(camera) // Set the audio and video sources. setAudioSource(MediaRecorder.AudioSource.CAMCORDER) setVideoSource(MediaRecorder.VideoSource.CAMERA) // Set a CamcorderProfile (requires API Level 8 or higher). setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)) // Set the output file. setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()) // Set the preview output. setPreviewDisplay(preview?.holder?.surface) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) // Prepare configured MediaRecorder. return try { prepare() true } catch (e: IllegalStateException) { Log.d(TAG, "preparing MediaRecorder failed", e) releaseMediaRecorder() false } catch (e: IOException) { Log.d(TAG, "setting MediaRecorder file failed", e) releaseMediaRecorder() false } } return false } private fun releaseMediaRecorder() { mediaRecorder?.reset() mediaRecorder?.release() mediaRecorder = null camera?.lock() } private fun startStopVideo() { if (isRecording) { // Stop recording and release camera. mediaRecorder?.stop() releaseMediaRecorder() camera?.lock() isRecording = false // This is a good place to inform user that video recording has stopped. } else { // Initialize video camera. if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, now // you can start recording. mediaRecorder?.start() isRecording = true // This is a good place to inform the user that recording has // started. } else { // Prepare didn't work, release the camera. releaseMediaRecorder() // Inform user here. } } }
CameraX: CameraController
Mit CameraController
von KameraX kannst du ImageCapture
,
VideoCapture
und ImageAnalysis
UseCase
s unabhängig voneinander,
solange die Liste der Anwendungsfälle gleichzeitig verwendet werden kann.
Die UseCase
s für ImageCapture
und ImageAnalysis
sind standardmäßig aktiviert, was
Deshalb musste du nicht setEnabledUseCases()
anrufen, um ein Foto aufzunehmen.
Wenn du eine CameraController
für die Videoaufnahme verwenden möchtest, musst du zuerst
setEnabledUseCases()
, um VideoCapture
UseCase
zuzulassen.
// CameraX: Enable VideoCapture UseCase on CameraController. cameraController.setEnabledUseCases(VIDEO_CAPTURE);
Wenn Sie die Videoaufnahme starten möchten, können Sie den
CameraController.startRecording()
. Diese Funktion kann das aufgezeichnete Video in einem File
speichern, wie Sie
im Beispiel unten. Außerdem müssen Sie ein Executor
und einen Kurs bestehen.
die das
OnVideoSavedCallback
Erfolgs- und Fehler-Callbacks verarbeitet werden. Wenn die Aufzeichnung beendet werden soll, rufen Sie
CameraController.stopRecording()
Hinweis:Wenn Sie CameraX 1.3.0-alpha02 oder höher verwenden, sind zusätzliche
Parameter AudioConfig
über das du die Audioaufnahme für dein Video aktivieren oder deaktivieren kannst. Zum Aktivieren
für Audioaufnahmen benötigen, müssen Sie die Mikrofonberechtigungen haben.
Außerdem wird die Methode stopRecording()
in 1.3.0-alpha02 entfernt und
startRecording()
gibt ein Recording
-Objekt zurück, das zum Pausieren verwendet werden kann.
Fortsetzen und Beenden der Videoaufzeichnung.
// CameraX: implement video capture with CameraController. private val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" // Define a VideoSaveCallback class for handling success and error states. class VideoSaveCallback : OnVideoSavedCallback { override fun onVideoSaved(outputFileResults: OutputFileResults) { val msg = "Video capture succeeded: ${outputFileResults.savedUri}" Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() Log.d(TAG, msg) } override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) { Log.d(TAG, "error saving video: $message", cause) } } private fun startStopVideo() { if (cameraController.isRecording()) { // Stop the current recording session. cameraController.stopRecording() return } // Define the File options for saving the video. val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US) .format(System.currentTimeMillis()) val outputFileOptions = OutputFileOptions .Builder(File(this.filesDir, name)) .build() // Call startRecording on the CameraController. cameraController.startRecording( outputFileOptions, ContextCompat.getMainExecutor(this), VideoSaveCallback() ) }
CameraX: CameraProvider
Wenn du ein CameraProvider
verwendest, musst du eine VideoCapture
erstellen
UseCase
und übergeben Sie ein Recorder
-Objekt. Auf der Recorder.Builder
können Sie
die Videoqualität und optional
FallbackStrategy
,
wenn ein Gerät nicht die gewünschten Qualitätsanforderungen erfüllt. Dann
Binden Sie die Instanz VideoCapture
mit der anderen an CameraProvider
.
UseCase
Sek.
// CameraX: create and bind a VideoCapture UseCase with CameraProvider. // Make a reference to the VideoCapture UseCase and Recording at a // scope that can be accessed throughout the camera logic in your app. private lateinit var videoCapture: VideoCaptureprivate var recording: Recording? = null ... // Create a Recorder instance to set on a VideoCapture instance (can be // added with other UseCase definitions). val recorder = Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.FHD)) .build() videoCapture = VideoCapture.withOutput(recorder) ... // Bind UseCases to camera (adding videoCapture along with preview here, but // preview is not required to use videoCapture). This function returns a camera // object which can be used to perform operations like zoom, flash, and focus. var camera = cameraProvider.bindToLifecycle( this, cameraSelector, preview, videoCapture)
Jetzt kann über videoCapture.output
auf Recorder
zugegriffen werden.
Property. Recorder
kann Videoaufnahmen starten, die in einem File
gespeichert sind,
ParcelFileDescriptor
oder MediaStore
. In diesem Beispiel wird MediaStore
verwendet.
Unter Recorder
gibt es mehrere Methoden, um sie vorzubereiten. Anruf
prepareRecording()
zum Festlegen der MediaStore
-Ausgabeoptionen. Wenn Ihre App
Berechtigung, das Mikrofon des Geräts zu verwenden, musst du auch withAudioEnabled()
anrufen.
Rufen Sie dann start()
auf, um die Aufzeichnung zu starten. Dabei werden ein Kontext und ein
Consumer<VideoRecordEvent>
-Event-Listener zur Verarbeitung von Videoaufnahmeereignissen. Wenn
erfolgreich war, kann die zurückgegebene Recording
verwendet werden, um den
Aufzeichnung.
// CameraX: implement video capture with CameraProvider. private val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" private fun startStopVideo() { val videoCapture = this.videoCapture ?: return if (recording != null) { // Stop the current recording session. recording.stop() recording = null return } // Create and start a new recording session. val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US) .format(System.currentTimeMillis()) val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4") if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video") } } val mediaStoreOutputOptions = MediaStoreOutputOptions .Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI) .setContentValues(contentValues) .build() recording = videoCapture.output .prepareRecording(this, mediaStoreOutputOptions) .withAudioEnabled() .start(ContextCompat.getMainExecutor(this)) { recordEvent -> when(recordEvent) { is VideoRecordEvent.Start -> { viewBinding.videoCaptureButton.apply { text = getString(R.string.stop_capture) isEnabled = true } } is VideoRecordEvent.Finalize -> { if (!recordEvent.hasError()) { val msg = "Video capture succeeded: " + "${recordEvent.outputResults.outputUri}" Toast.makeText( baseContext, msg, Toast.LENGTH_SHORT ).show() Log.d(TAG, msg) } else { recording?.close() recording = null Log.e(TAG, "video capture ends with error", recordEvent.error) } viewBinding.videoCaptureButton.apply { text = getString(R.string.start_capture) isEnabled = true } } } } }
Weitere Informationen
Wir haben mehrere vollständige CameraX-Apps in unserer GitHub-Repository für Kamerabeispiele. Diese Beispiele zeigen, wie sich die Szenarien in diesem Leitfaden auf ein umfassendes Android-App
Wenn Sie zusätzliche Unterstützung bei der Migration zu CameraX benötigen oder Fragen haben Informationen zur Suite der Android Camera APIs erhalten Sie auf der Diskussion zu CameraX Gruppieren.