2013-01-06 10 views
6

Sto implementando l'interfaccia SurfaceTexture.OnFrameAvailableListener nella mia app in modo da poter utilizzare i frame video come trama OpenGL. Tutto è configurato come dovrebbe e funziona perfettamente tuttavia onFrameAvailable (SurfaceTexture surfaceTexture) smette di essere chiamato dopo pochi secondi, in modo efficace e apparentemente congelando il video in OpenGL in quanto nessun nuovo texturedata viene caricato tramite SurfaceTexture.updateTextImage.SurfaceTexture.OnFrameAvailableListener smette di essere chiamato

Sto impostando un flag su onFrameAvailable per eseguire la chiamata updateTextImage dal thread GL e solo quando necessario. Attualmente sto impostando il flag su true su ogni chiamata draw in modo che il video texturedata venga caricato ogni frame mentre il controllo onFrameAvailable viene saltato. In questo modo, tutto funziona come dovrebbe, ma sembra inefficiente in quanto non è necessario caricare nuovi texturedata se è sempre uguale (fotogramma del filmato).

AFAIK non ci sono perdite di memoria e logcat non mostra errori. Inoltre, il lettore multimediale è impostato su loop ma il problema si verifica prima che una singola esecuzione sia stata completata.

Che cosa potrebbe causare la non più chiamata onFrameAvailable dopo alcuni secondi?

+0

Hai risolto? –

risposta

10

Ho appena visto un problema simile e l'ho debugato. Io, come te, avevo una bandiera booleana che indicava che uno (o più!) Fotogrammi era pronto per essere usato.

Il problema si è verificato quando ho ricevuto due fotogrammi della telecamera tra una coppia di fotogrammi OpenGL (probabilmente perché il mio processo di ridisegno di OpenGL era troppo lento). Ciò significava che ho impostato la bandiera booleana due volte. Tuttavia, ho letto solo una volta questi dati del frame e sembra che updateTexImage abbia implementato una sorta di funzione di accodamento.

Sostituire il flag booleano con un contatore intero di telecamere in sospeso ha risolto il problema per me. Forse funzionerebbe anche per te?

(Ho il sospetto che sia più efficiente di chiamare updateTexImage su ogni frame. Almeno nel mio codice, è stato molto raro (1-2%) per i frame OpenGL richiedere abbastanza tempo da coprire due fotogrammi della telecamera.)

+2

Grazie per il tuo lavoro di debug di questo. Sembra che un numero finito di buffer sia assegnato per la decodifica e che un chiamato a onFrameAvailable() controlli un buffer e questo buffer venga ricontrollato nel pool disponibile chiamando updateTexImage(). Un fatto critico che non è nella documentazione! – bleater

+0

@bleater - il tuo commento sopra era l'indizio che avevo finalmente bisogno di capire il mio particolare problema. Stavo cercando di ignorare alcuni fotogrammi per produrre un effetto balbuzie e quando non disegnavo un fotogramma avrei smesso di ottenerne di nuovi. La tua risposta mi ha aiutato a capire perché. – spartygw

11

Ho avuto lo stesso identico problema su alcuni dispositivi. Ho trovato una soluzione e ho pensato di condividere. Fondamentalmente è quello che @ user2254894 ha suggerito tranne che dal momento che il contatore potrebbe essere cambiato da 2 thread differenti, quindi è una buona idea usare 2 diversi vars. Ecco alcuni esempi di codice:

private int    _updateTexImageCounter = 0; 
private int    _updateTexImageCompare = 0; 

e onFrameAvailable() è semplice.

@Override 
public void onFrameAvailable(SurfaceTexture surfaceTexture) 
{ 
    // increment every time a new frame is avail 
    _updateTexImageCounter++; 
} 

Poi, nel tuo aggiornamento GL si sarebbe fare qualcosa di simile alla seguente ...

public void update() 
{ 

    .... create texture... etc. 
    .. 
    // compare _updateTexImageCompare and _updateTexImageCounter 
    if(_surfaceTexture!=null && _updateTexImageCompare != _updateTexImageCounter) 
    { 
     // loop and call updateTexImage() for each time the onFrameAvailable() method was called below. 
     while(_updateTexImageCompare != _updateTexImageCounter) { 
      _surfaceTexture.updateTexImage(); 
      _surfaceTexture.getTransformMatrix(x); 

      _updateTexImageCompare++; // increment the compare value until it's the same as _updateTexImageCounter 
     } 
    } 


} 

Questo ha funzionato per me. Fammi sapere se c'è un modo migliore.

+1

Anche questo mi ha aiutato, grazie! – voytez

+2

Wow. Ciò risolveva un bug che è persino presente nel codice Android originale. (Cioè: CTS for MediaCodec) –

+2

@ LéonPelletier contento che abbia aiutato. –

Problemi correlati