2016-03-30 9 views
0

私はGLSurfaceViewでアンドロイドの電話カメラからプレビューをレンダリングし、利用可能になるとすぐにフレームを保存します。フレームをSDカードに保存するには、2つの呼び出しの間の時間よりもはるかに時間がかかるので、画面からピクセルを読み取った後、別のスレッドで処理しています。Javaはバッファ読み取りでスレッドを同期させます

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

私の問題は、スレッドが遅れて開始したとき、時々フレームのための読み取りが開始されるということが起こるということです。

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

は次のコールバックが発射されるとintBuffer.clear()が実行されるので、残りは腐敗する。 スレッドを同期させると、バッファがいっぱいになるたびに実行され、スレッドの実行中にバッファがクリアされないように注意してください。

答えて

0

古典的なヒットのような音共有データ並行性の問題。

このような問題を解決する最も簡単な方法は、データの共有をやめることです。あなたは、ワーカースレッドにIntBufferの裏int配列のコピーを送信することができます

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

IntBuffer「sequentialize」意志あなたのプログラムのクリティカルセクションと下をもたらす可能性への読み込みと書き込みの簡単な同期をグラブされたフレームの忠実度(ワーカースレッドがまだIntBufferの内容を読み取っている場合は、フレーム変更イベントリスナーがトリガーされた直後にglReadPixelsに電話をかけることはできません)。それはまた、エラーが発生しやすいので、私はそれをお勧めしません。

-1

QueueIntBufferオブジェクトを使用し、アプリケーションを終了する前にQueueが空であるのを待っていました。 が呼び出されたときに基本的に関数を実行します。

これを読んだ人は、データをキューに追加して終了する前にそのデータが処理されるまで待つことができます。

関連する問題