Lowest Overhead-Kamera auf CPU zu GPU-Ansatz auf Android

Meine Anwendung muss einige Verarbeitungsschritte an Live-Kamerabildern auf der CPU ausführen, bevor sie auf der GPU gerendert werden. Auf der GPU werden noch einige andere Elemente gerendert, die von den Ergebnissen der CPU-Verarbeitung abhängen. Daher ist es wichtig, dass alles synchronisiert bleibt, damit wir den Frame nicht selbst auf der GPU rendern, bis auch die Ergebnisse der CPU-Verarbeitung für diesen Frame verfügbar sind.

Die Frage ist, was ist der niedrigste Overhead-Ansatz für dieses auf Android?

Die CPU-Verarbeitung in meinem Fall benötigt nur ein Graustufenbild, daher ist ein YUV-Format, in das die Y-Ebene gepackt ist, ideal (und passt in der Regel auch gut zum nativen Format der Kamerageräte). NV12, NV21 oder vollständig planares YUV würden alle einen idealen Low-Overhead-Zugriff auf Graustufen bieten, sodass dies auf der CPU-Seite vorzuziehen wäre.

In der ursprünglichen Kamera-API war setPreviewCallbackWithBuffer () der einzig sinnvolle Weg, Daten zur Verarbeitung auf die CPU zu übertragen. Dies hatte die Y-Ebene getrennt, war also ideal für die CPU-Verarbeitung. Der schwierigere Aspekt bestand darin, OpenGL diesen Frame für das Rendering mit geringem Overhead zur Verfügung zu stellen. Am Ende habe ich eine NEON-Farbkonvertierungsroutine geschrieben, um RGB565 auszugeben, und benutze einfach glTexSubImage2d, um dies auf der GPU verfügbar zu machen. Dies wurde zum ersten Mal im Nexus 1-Zeitrahmen implementiert, in dem sogar ein glTexSubImage2d-Aufruf im Format 320x240 50 ms CPU-Zeit in Anspruch nahm (ich nehme an, schlechte Treiber, die versuchen, Textur-Swizzling durchzuführen - dies wurde in einem späteren System-Update erheblich verbessert).

Zurück an dem Tag habe ich mich mit Dingen wie eglImage-Erweiterungen befasst, aber sie scheinen für Benutzer-Apps nicht verfügbar oder ausreichend dokumentiert zu sein. Ich hatte einen kleinen Einblick in die internen GraphicsBuffer-Klassen von Android, möchte aber im Idealfall in der Welt der unterstützten öffentlichen APIs bleiben.

Die android.hardware.camera2-API versprach, einer Erfassungssitzung sowohl einen ImageReader als auch eine SurfaceTexture hinzufügen zu können. Leider kann ich hier keine Möglichkeit finden, die richtige sequentielle Pipeline sicherzustellen. Es ist einfach genug, den Aufruf von updateTexImage () zu unterbrechen, bis die CPU verarbeitet wurde. Wenn jedoch während dieser Verarbeitung ein anderer Frame eingetroffen ist, wird updateTexImage () direkt zum neuesten Frame springen Rahmen. Bei mehreren Ausgängen scheint es auch unabhängige Kopien der Frames in jeder der Warteschlangen zu geben, die ich idealerweise vermeiden möchte.

Ideally das ist, was ich möchte:

Camera-Treiber füllt den Speicher mit dem neuesten FrameCPU erhält Zeiger auf die Daten im Speicher, kann Y-Daten lesen, ohne dass eine Kopie erstellt wirdCPU verarbeitet Daten und setzt ein Flag in meinem Code, wenn der Frame fertig istWenn Sie mit dem Rendern eines Frames beginnen, prüfen Sie, ob ein neuer Frame bereit istufen Sie eine API auf, um denselben Speicher wie eine GL-Textur zu bindeWenn ein neuerer Frame bereit ist, geben Sie den Puffer, der den vorherigen Frame enthält, wieder in den Pool frei.

Ich kann keine Möglichkeit finden, genau diesen Zero-Copy-Stil mit der öffentlichen API auf Android zu erreichen, aber was ist am ehesten zu erreichen?

Eine verrückte Sache, die ich versucht habe, scheint zu funktionieren, ist aber nicht dokumentiert: Die ANativeWindow NDK-API kann Daten im NV12-Format akzeptieren, obwohl die entsprechende Formatkonstante nicht zu den in den öffentlichen Headern angegebenen gehört. Auf diese Weise kann eine SurfaceTexture von memcpy () mit NV12-Daten gefüllt werden, um eine CPU-seitige Farbkonvertierung und jegliches Schwirren auf der Treiberseite in glTexImage2d zu vermeiden. Dies ist immer noch eine zusätzliche Kopie der Daten, obwohl dies als unnötig erachtet wird, und auch dies funktioniert möglicherweise nicht auf allen Geräten, da sie nicht dokumentiert sind. Eine unterstützte sequenzielle Zero-Copy-Kamera -> ImageReader -> SurfaceTexture oder eine entsprechende Option wäre perfekt.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage