2016-12-31 12 views
2

JOGLを使用してOpenGLで表示しているもののビデオを保存します。これを行うには、次のようにフレームを写真に書き込んでから、すべてのフレームを保存したらffmpegを使用します。私はこれが最善の方法ではないことを知っていますが、tex2dimageとPBOでどのように加速するかについてはまだあまり明確ではありません。その方向への助けはとても役に立ちます。glReadPixelsが予想よりも多くのデータを返します

とにかく私の問題は、OpenGLクラスを実行すると動作しますが、別のクラスからこのクラスを呼び出すと、glReadPixelsがエラーを表示していることがわかります。メモリがバッファ "pixelsRGB"に割り当てられているより多くのデータをバッファに返します。なぜ誰が知っていますか?

例:width = 1042;高さ= 998。割り当てられた= 3.119.748 glPixelsが返さ= 3.121.742

public void display(GLAutoDrawable drawable) { 
     //Draw things..... 

     //bla bla bla 
     t++; //This is a time variable for the animation (it says to me the frame). 

     //Save frame   
     int width = drawable.getSurfaceWidth(); 
     int height = drawable.getSurfaceHeight(); 
     ByteBuffer pixelsRGB = Buffers.newDirectByteBuffer(width * height * 3); 
     gl.glReadPixels(0, 0, width,height, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, pixelsRGB); 
     BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 

     int[] pixels = new int[width * height]; 

     int firstByte = width * height * 3; 
     int sourceIndex; 
     int targetIndex = 0; 
     int rowBytesNumber = width * 3; 

     for (int row = 0; row < height; row++) { 
      firstByte -= rowBytesNumber; 
      sourceIndex = firstByte; 
      for (int col = 0; col < width; col++) { 
       int iR = pixelsRGB.get(sourceIndex++); 
       int iG = pixelsRGB.get(sourceIndex++); 
       int iB = pixelsRGB.get(sourceIndex++); 

       pixels[targetIndex++] = 0xFF000000 
        | ((iR & 0x000000FF) << 16) 
        | ((iG & 0x000000FF) << 8) 
        | (iB & 0x000000FF); 
      } 

     } 

     bufferedImage.setRGB(0, 0, width, height, pixels, 0, width); 


     File a = new File(t+".png"); 
     ImageIO.write(bufferedImage, "PNG", a); 
} 

注:pleluronの答えでは、今では動作します。良いコードは次のとおり

public void display(GLAutoDrawable drawable) { 
     //Draw things..... 

     //bla bla bla 
     t++; //This is a time variable for the animation (it says to me the frame). 

     //Save frame   
     int width = drawable.getSurfaceWidth(); 
     int height = drawable.getSurfaceHeight(); 
     ByteBuffer pixelsRGB = Buffers.newDirectByteBuffer(width * height * 4); 
     gl.glReadPixels(0, 0, width,height, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, pixelsRGB); 
     BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 

     int[] pixels = new int[width * height]; 

     int firstByte = width * height * 4; 
     int sourceIndex; 
     int targetIndex = 0; 
     int rowBytesNumber = width * 4; 

     for (int row = 0; row < height; row++) { 
      firstByte -= rowBytesNumber; 
      sourceIndex = firstByte; 
      for (int col = 0; col < width; col++) { 
       int iR = pixelsRGB.get(sourceIndex++); 
       int iG = pixelsRGB.get(sourceIndex++); 
       int iB = pixelsRGB.get(sourceIndex++); 

       sourceIndex++; 

       pixels[targetIndex++] = 0xFF000000 
        | ((iR & 0x000000FF) << 16) 
        | ((iG & 0x000000FF) << 8) 
        | (iB & 0x000000FF); 
      } 

     } 

     bufferedImage.setRGB(0, 0, width, height, pixels, 0, width); 


     File a = new File(t+".png"); 
     ImageIO.write(bufferedImage, "PNG", a); 
} 
+0

com.jogamp.opengl.util.GLReadBufferUtilをcom.jogamp.opengl.util.texture.TextureIOで使用してください。正しく使用すると、すべての画像に対して同じバッファ(TextureDataオブジェクト内)を使用し続けることができ、AWTを取り除き、JNGL PNGエンコーダ(PNGJに基づいています)が高速で、AWT /スウィング相当物。 – gouessej

+0

ところで、FFMPEGとLibAVはすでにJOGLのフードの中でメディアプレーヤーの中で使われています。たぶん、ソースコードを見て、書き込むために必要なメソッドを公開する方法を知ることができます。多数のPNGファイルを使用する必要はありません。 – gouessej

答えて

3

glPixelStoreで設定GL_PACK_ALIGNMENTのデフォルト値は4である。これはpixelsRGBの各行が4の倍数のアドレス、あなたのバッファの幅(1042で開始する必要があることを意味します)timesピクセル(3)のバイト数は4の倍数ではありません。次の行が4の倍数で始まるように小さなパディングを追加すると、バッファの合計バイトサイズが予想よりも大きくなります。それを修正する

は、データをGPU上とBufferedImageの両方でそのように保存される可能性が最も高いので、あなたはまた、GL_RGBAでピクセルを読み、大きなバッファを使用することができます1にGL_PACK_ALIGNMENTを設定します。

編集:BufferedImageに便利な「setRGBA」がありません。

+0

gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT、1)を追加しようとしました。 pixelsRGB宣言の前に、それは再び失敗しました。とにかく、私はアルファ値を破壊しないようにしてみました。 –

+1

「解凍」ではなく「パック」です。 PackはOpenGL - > User用で、User - > OpenGL用に解凍します。 – pleluron

+0

UPS! OK!今それは動作します。私は、アルファチャンネルを追加するのではなく、glPixelStoreを好むと思います。メモリの消費量は少なくなります。再度、感謝します! –

関連する問題