2016-03-30 30 views
0

Telefondaki kameradan ön izlemeyi bir GLSurfaceView numaralı telefondan gerçekleştiriyorum ve mümkün olan en kısa sürede kareleri kaydetmek istiyorum. Çerçeveleri sd kartına kaydettiğinizde, iki onFrameAvailable çağrı arasındaki süreden çok daha fazla zaman geçtiğinden, ekrandan pikselleri okuduktan sonra bunu başka bir iş parçacığında yapıyorum.Java, arabelleği okuma arabelleği ile senkronize etme

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(); 
    } 
} 

Benim sorunum iplik gerisinde başladığında, bazen bir çerçeve için hangi okuma başlar olur ki:

final int[] pixels = new int[intBuffer.capacity()]; 
intBuffer.rewind(); 
intBuffer.get(pixels); 
sonraki geri arama ateşlenir

ve intBuffer.clear() çalıştırılır, böylece dinlenme bozuldu. İş parçacığı, arabellek dolduğunda çalışacak ve iş parçacığı çalışırken arabelleğin temizlenmemesine neden olacak şekilde nasıl eşitlenir?

cevap

0

Klasik bir paylaşılan verilere eşdeğer gibi geliyor eşzamanlılık sorunu.

Böyle bir sorunu çözmenin en kolay yolu, verileri paylaşmayı durdurmaktır. arasında

... 
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 

Basit senkronizasyon okur ve programın IntBuffer olacak "sequentialize" kritik bölümlerine yazar ve daha düşük neden olabilir: Sen IntBuffer yedeklenmesini int dizinin bir kopyasını iplik işçiye gönderebilir yakalanan çerçevelerin aslına uygunluk (glReadPixels numaranızda çerçeve değişkeni olay dinleyicisi tetiklendiğinde, çalışan iş parçacığınız hala IntBuffer içeriğini okuyorsa) bulamazsınız. Ayrıca daha fazla hata eğilimli olacak, bu yüzden tavsiye etmem.

-1

Yalnızca QueueIntBuffer nesnelerini kullanarak sona erdim ve uygulamadan çıkmadan önce Queue boş olmasını bekliyorum. Temel olarak çağrıldığında işlevi çalıştırılıyor.

Bunu okuyanlar için, verilerinizi kuyruğa eklemeniz ve çıkmadan önce işlenmesini beklemeniz gerekebilir.

İlgili konular