9 votes

Utilisation de Pixel Buffer Objects (PBO's) sur Android

Sur Android, j'essaie d'effectuer un traitement OpenGL sur les images de la caméra, d'afficher ces images dans l'aperçu de la caméra, puis d'encoder les images dans un fichier vidéo. J'essaie de faire cela avec OpenGL, en utilisant GLSurfaceView et GLSurfaceView.Renderer et avec FFMPEG pour l'encodage vidéo.

J'ai réussi à traiter les images en utilisant un shader. Maintenant, je dois encoder les images traitées en vidéo. Le GLSurfaceView.Renderer fournit la méthode onDrawFrame(GL10 ..). C'est dans cette méthode que j'essaie de lire les images en utilisant simplement glReadPixels() et ensuite de placer les images dans une file d'attente pour les encoder en vidéo. A lui seul, glReadPixels() est beaucoup trop lent - mon taux de rafraîchissement est de l'ordre de quelques chiffres. J'essaie d'accélérer le processus en utilisant les Pixel Buffer Objects. Cela ne fonctionne pas. Après avoir branché le pbo, le taux de rafraîchissement est inchangé. C'est la première fois que j'utilise OpenGL et je ne sais pas par où commencer pour trouver le problème. Est-ce que je fais bien les choses ? Quelqu'un peut-il me donner des indications ? Merci d'avance.

public class MainRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {

.
.

    public void onDrawFrame ( GL10 gl10 ) {

        //Create a buffer to hold the image frame     
        ByteBuffer byte_buffer = ByteBuffer.allocateDirect(this.width * this.height * 4);
        byte_buffer.order(ByteOrder.nativeOrder());

        //Generate a pointer to the frame buffers
        IntBuffer image_buffers = IntBuffer.allocate(1); 
        GLES20.glGenBuffers(1, image_buffers);

        //Create the buffer
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, image_buffers.get(0));
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, byte_buffer.limit(), byte_buffer, GLES20.GL_STATIC_DRAW);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, image_buffers.get(0));

        //Read the pixel data into the buffer
        gl10.glReadPixels(0, 0, this.width, this.height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, byte_buffer);

        //encode the frame to video
        enQueueForEncoding(byte_buffer);

        //unbind the buffer
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    }

.
.

}

1voto

Trax Points 1860

Je n'ai jamais essayé quelque chose comme ça avant (opengl+video enconding) mais je peux vous dire que la lecture de la mémoire du périphérique est LENTE. Essayez le double buffering, cela peut aider puisque le GPU peut continuer à faire le rendu dans le second buffer pendant que le contrôleur DMA relit les données.

Chargez un profileur (vérifiez le vendeur du GPU de votre appareil), cela vous donnera peut-être une idée. Une autre chose qui peut aider est de définir le format interne de pbuffer à quelque chose d'autre, essayez des nombres plus bas et de laisser tomber un canal (alpha).

EDIT : Si vous en avez envie, vous pouvez encoder la vidéo au niveau du GPU, cela va booster, en termes de mémoire et de traitement, votre application.

1voto

Roman Points 128

Comme je m'en souviens glBufferData() ne mappe pas votre tampon interne sur la mémoire du GPU, il copie simplement les données de votre mémoire dans le tampon (initialisation).

Pour obtenir l'accès à la mémoire, qui est allouée par glBufferData() vous devez utiliser glMapBufferRange() . Cette fonction renvoie un objet Java Buffer que vous pouvez lire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X