2015-09-07 1 views
4

J'ai rendu vidéo à travers le MediaCodec directement sur une surface qui a été prise d'un SurfaceView dans mon interface utilisateur. Cela fonctionne très bien.encodage Android en utilisant MediaCodec et une surface

Je tente maintenant d'utiliser MediaCodec comme un codeur. Comme un test, je veux rendre à la surface (comme ci-dessus) et faire un loopback à travers une instance différente de MediaCodec configuré comme un encodeur.

je vois la méthode createInputSurface() du codeur. Je pense que je veux que l'encodeur crée cette surface et que le décodeur MediaCodec l'utilise comme surface à dessiner. Tout d'abord, est-ce possible? Deuxièmement, je ne suis pas sûr comment créer un SurfaceView à partir de la surface que l'encodeur crée. J'ai seulement extrait une Surface d'un SurfaceView et je ne vois pas, à partir des docs, comment faire cela en sens inverse.

Répondre

7

surfaces sont du côté « producteur » d'un dispositif producteur-consommateur. D'une manière générale, l'API est centrée sur les consommateurs, qui créent les deux extrémités et vous remettent l'interface du producteur (la Surface). Par conséquent, pour un encodeur SurfaceView ou MediaCodec, vous créez l'objet et obtenez sa surface. Ensuite, vous leur envoyez des tampons de données graphiques, avec Canvas, OpenGL ES ou un décodeur MediaCodec.

Il est impossible de prendre la surface d'entrée de l'encodeur et de l'utiliser comme surface d'affichage SurfaceView - il s'agit de deux pipelines différents. Le consommateur de SurfaceView est dans le compositeur de système (SurfaceFlinger), c'est pourquoi vous devez attendre que le callback "surface créée" se déclenche. Le consommateur de l'encodeur MediaCodec est dans le processus mediaserver, bien que l'asynchronicité soit mieux dissimulée.

L'envoi de la sortie du décodeur MediaCodec vers un SurfaceView est simple, tout comme l'envoi de la sortie vers un encodeur MediaCodec. Comme vous l'avez supposé, il suffit de passer la surface d'entrée du codeur au décodeur. Là où la vie devient intéressante, c'est quand vous voulez faire ces deux choses en même temps. Le code sous-jacent Surface (appelé BufferQueue) devrait être capable (à partir de Lollipop) de multiplexer, mais je ne suis pas au courant d'une API dans Lollipop qui expose la capacité aux applications. Ce qui signifie que vous êtes coincé à faire les choses à la dure.

La difficulté consiste à créer un SurfaceTexture (a/k/a GLConsumer), qui est l'extrémité consommateur du tube. À partir de là, vous pouvez créer une Surface en utilisant le sole constructor. Vous remettez cela au décodeur MediaCodec. Maintenant, chaque image qui en sortira sera convertie en texture GLES par SurfaceTexture. Vous pouvez les afficher dans SurfaceView et dans la surface d'entrée de l'encodeur.

Vous pouvez trouver divers exemples dans Grafika, et une explication plus longue de la mécanique dans le graphics architecture doc.

+1

Je suis décodage d'un flux à un moment SurfaceView en utilisant MediaCodec. Cela fonctionne très bien. La partie sur l'utilisation de MediaCodec comme un codeur qui me rend confus est que j'ai besoin de demander au codec une surface (createSurface). Est-ce que je crée la surface en utilisant l'encodeur et donne cette référence de surface au décodeur à utiliser? Ou dois-je effectuer une copie entre les pixels de surface de décodage et celui que l'encodeur crée? –

+1

Oui ... pour envoyer la sortie d'un décodeur directement dans un encodeur, créez d'abord Surface du codeur avec 'createInputSurface()', puis remettez-le au décodeur lors de la configuration. La copie manuelle n'est pas requise. – fadden

+0

J'ai compris, merci! –