2016-03-30 8 views
0

Ich render die Vorschau von der Handy-Kamera in Android GLSurfaceView und möchte Frames speichern, sobald sie verfügbar sind. Da das Speichern der Frames auf der SD-Karte viel mehr Zeit in Anspruch nimmt als die Zeit zwischen zwei onFrameAvailable Calls, mache ich es in einem anderen Thread, nachdem ich die Pixel vom Bildschirm gelesen habe.Java synchronisieren Thread mit Puffer lesen

public void onDrawFrame(GL10 gl) { 
//Process the frame, display it on the screen and other stuff 

//Read pixels from the screen into my buffer 
     glReadPixels(0, 0, offscreenSize_.x, offscreenSize_.y, GL_RGBA, GL_UNSIGNED_BYTE, 
       intBuffer.clear()); 
    // At the moment this has a counter and happens every 150ms 
    if(saveImage) 
    { 
    Thread thread = new Thread() { 
      @Override 
      public void run() { 
       // Convert to an array for Bitmap.createBitmap(). 
       final int[] pixels = new int[intBuffer.capacity()]; 
       intBuffer.rewind(); 
       intBuffer.get(pixels); 

       try { 
        // Create/access a pictures subdirectory. 
        File directory = new File(
          Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), 
          "TangoFrames"); 
        if (!directory.mkdirs() && !directory.isDirectory()) { 
         Log.d("WRITE ERR", "Couldn't create directory"); 
         return; 
        } 

        // Get the current capture index to construct a unique filename. 
        SharedPreferences prefs = activity_.getPreferences(Context.MODE_PRIVATE); 
        int index = prefs.getInt("index", 0); 
        SharedPreferences.Editor prefsEditor = prefs.edit(); 
        prefsEditor.putInt("index", index + 1); 
        prefsEditor.apply(); 

        // Create the capture file. 
        File file = new File(directory, String.format("tango%05d.png", index)); 
        FileOutputStream fileOutputStream = new FileOutputStream(file); 

        // Bitmap conveniently provides file output. 
        Bitmap bitmap = Bitmap.createBitmap(pixels, offscreenSize_.x, offscreenSize_.y, Bitmap.Config.ARGB_8888); 
        bitmap.compress(Bitmap.CompressFormat.PNG, 90, fileOutputStream); 
        fileOutputStream.close(); 
        numberOfFrames++; 
       } 
       catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }; 
     thread.start(); 
    } 
} 

Mein Problem ist, dass, wenn der Faden hinter fallen beginnt, kommt es vor, dass für die für einen Rahmen der Lesung beginnt:

final int[] pixels = new int[intBuffer.capacity()]; 
intBuffer.rewind(); 
intBuffer.get(pixels); 

Der nächste Rückruf ausgelöst wird und intBuffer.clear() ausgeführt wird, so dass die Der Rest wird beschädigt. Wie kann ich den Thread so synchronisieren, dass er nur ausgeführt wird, wenn der Puffer voll ist, und darauf achten, dass der Puffer nicht gelöscht wird, während der Thread läuft?

Antwort

0

Klingt wie Sie treffen ein klassisches geteilte Daten Gleichzeitigkeitsproblem.

Der einfachste Weg, um ein solches Problem zu lösen, ist die Freigabe von Daten zu stoppen. Sie können eine Kopie des Träger int Array der IntBuffer den Arbeiter senden Thread:

... 
glReadPixels(0, 0, offscreenSize_.x, offscreenSize_.y, GL_RGBA, GL_UNSIGNED_BYTE, 
     intBuffer.clear()); 
final int[] bufferContents = intBuffer.array(); 
final int[] pixels = Arrays.copyOf(bufferContents , bufferContents .length); 
// reset buffer here 
if (saveImage) { 
    ... 
    // use pixels here 

Einfache Synchronisation der liest und schreibt auf die IntBuffer wird „sequentialisieren“ der kritischen Abschnitte des Programms und führt zu niedrigeren Treue der erfassten Frames (Sie können glReadPixels nicht sofort aufrufen, wenn Ihr Framewechsel-Ereignis-Listener ausgelöst wird, wenn Ihr Worker-Thread immer noch den Inhalt IntBuffer liest). Es wird auch fehleranfälliger sein, also würde ich es nicht empfehlen.

-1

landete ich ein Queue von IntBuffer Objekte nur bis verwenden und warten auf die Queue leer zu sein, bevor die Anwendung zu verlassen. Grundsätzlich läuft die Funktion wenn aufgerufen wird.

Also für diejenigen, die dies lesen, könnte es der Fall sein, dass Sie einfach Ihre Daten zu einer Warteschlange hinzufügen und warten können, bis sie vor dem Beenden verarbeitet werden.