2016-12-31 2 views
2

Я хочу сохранить видео того, что я показываю с помощью openGL, используя JOGL. Чтобы сделать это, я пишу свои кадры на рисунки следующим образом, а затем, как только я сохраню все кадры, я буду использовать ffmpeg. Я знаю, что это не лучший подход, но я до сих пор не очень ясно, как ускоряться с tex2dimage и PBOs. Любая помощь в этом направлении была бы очень полезной.glReadPixels возвращает больше данных, чем ожидалось

В любом случае, моя проблема в том, что если я запустил класс opengl, это будет работать, но если я вызову этот класс из другого класса, то вижу, что glReadPixels искажает мне ошибку. Он всегда возвращает больше данных в буфер, чем память была выделена для моего буфера «пикселейRGB». Кто-нибудь знает, почему?

В качестве примера: ширина = 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, кодер JOGL PNG (на основе PNGJ) работает быстрее и имеет меньший объем памяти, чем AWT/Качели. – gouessej

+0

Кстати, FFMPEG и LibAV уже используются под капотом в JOGL внутри медиаплеера. Возможно, вы можете посмотреть исходный код, чтобы узнать, как выложить необходимые методы для написания, это позволит вам использовать многочисленные файлы PNG. – gouessej

ответ

3

Значение по умолчанию GL_PACK_ALIGNMENT набор с glPixelStore равно 4. Это означает, что каждая строка должна начинаться pixelsRGB по адресу, который является кратным 4, а ширина вашего буфера (1042) раз количество байтов в пикселе (3) не кратно 4. Добавляя небольшое заполнение, поэтому следующая строка начинается с кратного 4, сделает общий размер байта вашего буфера больше, чем вы ожидали.

Чтобы исправить это, установите GL_PACK_ALIGNMENT 1. Вы могли бы также прочитать пиксели с GL_RGBA и использовать буфер большего размера, так как данные, скорее всего, будет храниться таким образом, как на GPU и в BufferedImage.

Редактировать: BufferedImage не имеет «setRGBA», что слишком плохо.

+0

Я попытался добавить gl.glPixelStorei (gl.GL_UNPACK_ALIGNMENT, 1); перед объявлением pixRGB, но он снова не удался. Во всяком случае, я старался не разрушать альфа-значение, и он работает! –

+1

Это «пакет», а не «распаковка». Pack для OpenGL -> Пользователь, распаковать для пользователя -> OpenGL. – pleluron

+0

ИБП! ОК! теперь это работает. Я думаю, что предпочитаю glPixelStore вместо добавления альфа-канала. Это меньше потребляет память. Еще раз спасибо! –