Le plus bas appareil photo au CPU à l'approche GPU sur Android


Answers

Question

Mon application doit effectuer un traitement sur les images de caméra en direct sur le processeur, avant de les restituer sur le GPU. Il y a aussi d'autres choses qui sont rendues sur le GPU qui dépend des résultats du traitement du CPU; par conséquent, il est important de garder tout synchronisé afin de ne pas restituer le cadre lui-même sur le GPU jusqu'à ce que les résultats du traitement du processeur pour cette trame soient également disponibles.

La question est quelle est la plus faible approche de frais généraux pour cela sur Android?

Le traitement du processeur dans mon cas a juste besoin d'une image en niveaux de gris, donc un format YUV où le plan Y est emballé est idéal (et a tendance à être une bonne correspondance avec le format natif des appareils photo). NV12, NV21 ou YUV entièrement planaire fourniraient tous un accès bas-idéal idéal à l'échelle de gris, ce qui serait préférable du côté CPU.

Dans l'API originale de l'appareil photo, setPreviewCallbackWithBuffer () était le seul moyen sensé d'obtenir des données sur le processeur pour le traitement. Cela avait le plan Y séparé donc était idéal pour le traitement du processeur. Obtenir ce cadre disponible à OpenGL pour le rendu dans un bas frais généraux était l'aspect le plus difficile. A la fin, j'ai écrit une routine de conversion de couleur NEON pour sortir RGB565 et utiliser simplement glTexSubImage2d pour que cela soit disponible sur le GPU. Cela a d'abord été implémenté dans le Nexus 1, où même un appel 320x240 glTexSubImage2d prenait 50ms de temps CPU (les pilotes pauvres essayant de faire des textures swizzling je présume - cela a été significativement amélioré dans une mise à jour du système plus tard).

En arrière dans la journée j'ai regardé dans des choses comme des prolongements d'eglImage, mais elles ne semblent pas être disponibles ou assez bien documentées pour des applications d'utilisateur. J'ai jeté un coup d'oeil dans les classes android GraphicsBuffer android mais je veux idéalement rester dans le monde des API publiques supportées.

L'API android.hardware.camera2 était prometteuse car elle permettait de joindre à la fois ImageReader et SurfaceTexture à une session de capture. Malheureusement, je ne vois aucun moyen de garantir le bon déroulement du pipeline séquentiel. Ne pas utiliser updateTexImage () tant que le processeur n'est pas assez simple, mais si une autre image est arrivée pendant ce traitement, updateTexImage () passera directement au dernier Cadre. Il semble également qu'avec plusieurs sorties, il y aura des copies indépendantes des images dans chacune des files d'attente que, idéalement, j'aimerais éviter.

Idéalement, c'est ce que je voudrais:

  1. Le pilote de la caméra remplit la mémoire avec le dernier cadre
  2. CPU obtient un pointeur vers les données en mémoire, peut lire les données Y sans qu'une copie soit faite
  3. L'UC traite les données et définit un indicateur dans mon code lorsque l'image est prête
  4. Lorsque vous commencez à rendre une image, vérifiez si une nouvelle image est prête
  5. Appelez une API pour lier la même mémoire qu'une texture GL
  6. Quand une nouvelle image est prête, relâchez le tampon contenant l'image précédente dans la piscine

Je ne vois pas de moyen de faire exactement ce style zéro copie avec l'API publique sur android, mais quel est le plus proche possible?

Une chose folle que j'ai essayé qui semble fonctionner, mais n'est pas documentée: L'API NDK ANativeWindow peut accepter le format de données NV12, même si la constante de format appropriée n'est pas une de celles dans les en-têtes publics. Cela permet à un SurfaceTexture d'être rempli avec des données NV12 par memcpy () pour éviter la conversion de couleur côté CPU et tout basculement qui se produit côté pilote dans glTexImage2d. Il s'agit toujours d'une copie supplémentaire des données, mais il semble que cela ne soit pas nécessaire et, comme il n'est pas documenté, il risque de ne pas fonctionner sur tous les appareils. Une caméra zéro copie séquentielle supportée -> ImageReader -> SurfaceTexture ou équivalent serait parfaite.