2016-12-31 9 views
2

JOGL을 사용하여 openGL에 표시되는 비디오를 저장하고 싶습니다. 이렇게하려면 다음과 같이 프레임을 그림에 쓰고 일단 모든 프레임을 저장하면 ffmpeg를 사용합니다. 이것이 최선의 방법은 아니지만 tex2dimage 및 PBO를 사용하여 가속화하는 방법은 아직 명확하지 않습니다. 그 방향으로의 도움은 매우 유용 할 것입니다.glReadPixels가 예상보다 많은 데이터를 반환합니다.

어쨌든 내 문제는 OpenGL 클래스를 실행하면 작동하지만, 다른 클래스에서이 클래스를 호출하면 glReadPixels가 오류를 trhowing하는 것을 볼 수 있습니다. 그것은 항상 메모리가 버퍼 "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를 없애고 PNGJ에 기반한 JOGL PNG 인코더가 빠르며 메모리 풋 프린트가 AWT/동등한 스윙. – gouessej

+0

그런데 FFMPEG와 LibAV는 이미 미디어 플레이어 내부의 JOGL에서 사용됩니다. 어쩌면 소스 코드를보고 필요한 작성 방법을 폭로하는 방법을 알면 수많은 PNG 파일을 사용하지 않아도됩니다. – gouessej

답변

3

glPixelStore 설정 GL_PACK_ALIGNMENT의 기본값은 그것은 pixelsRGB의 각 행은 4의 배수 인 주소에서 시작해야 함을 의미 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

'포장'이 아니라 '포장'입니다. 팩은 OpenGL -> 사용자 용이며, 사용자 -> OpenGL 용으로 압축을 풉니 다. – pleluron

+0

UPS! 승인! 이제 작동합니다. 알파 채널을 추가하는 대신 glPixelStore를 선호한다고 생각합니다. 메모리 소비가 적습니다. 다시 한 번 감사드립니다! –