Java glReadPixels返回的数据比预期的多

Java glReadPixels返回的数据比预期的多,java,opengl,buffer,jogl,glreadpixels,Java,Opengl,Buffer,Jogl,Glreadpixels,我想用JOGL保存一个我正在用openGL显示的视频。要做到这一点,我将帧写入图片,如下所示,然后,保存所有帧后,我将使用ffmpeg。我知道这不是最好的方法,但我仍然不太清楚如何使用tex2dimage和PBOs加速。这方面的任何帮助都是非常有用的 无论如何,我的问题是,如果我运行opengl类,它可以工作,但是,如果我从另一个类调用这个类,那么我看到glReadPixels向我显示了一个错误。它返回到缓冲区的数据总是多于分配给我的缓冲区像素GB的内存。有人知道为什么吗 例如:宽度=1042;

我想用JOGL保存一个我正在用openGL显示的视频。要做到这一点,我将帧写入图片,如下所示,然后,保存所有帧后,我将使用ffmpeg。我知道这不是最好的方法,但我仍然不太清楚如何使用tex2dimage和PBOs加速。这方面的任何帮助都是非常有用的

无论如何,我的问题是,如果我运行opengl类,它可以工作,但是,如果我从另一个类调用这个类,那么我看到glReadPixels向我显示了一个错误。它返回到缓冲区的数据总是多于分配给我的缓冲区像素GB的内存。有人知道为什么吗

例如:宽度=1042;高度=998。已分配=3.119.748像素返回=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);
 }
注:普莱隆的回答现在起作用了。好的代码是:

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);
 }
使用glPixelStore设置的GL_PACK_对齐的默认值为4。这意味着pixelsRGB的每一行应该从4的倍数开始,而缓冲区1042倍于像素3字节数的宽度不是4的倍数。添加一点填充,使下一行以4的倍数开始,将使缓冲区的总字节大小大于预期值

若要修复此问题,请将“GL_PACK_ALIGNMENT”设置为1。您还可以使用GL_RGBA读取像素并使用更大的缓冲区,因为数据很可能以这种方式存储在GPU和BuffereImage中


编辑:BuffereImage没有方便的“setRGBA”,太糟糕了。

我试图添加gl.glPixelStoreigl.gl\u UNPACK\u对齐,1;在pixelsRGB声明之前,但再次失败。不管怎样,我试着不破坏alpha值,它正在工作!这是“打包”,不是“拆包”。打包是为了OpenGL->User,解包是为了User->OpenGL.UPS!好啊现在它起作用了。我想我更喜欢glPixelStore而不是添加alpha通道。它消耗的内存更少。再次感谢!是的,我认为BuffereImage可以直接拍摄RGBA图像。。。最好使用行打包,而不是将com.jogamp.opengl.util.GLReadBufferUtil与com.jogamp.opengl.util.texture.TextureIO一起使用。如果正确使用它,您可以在TextureData对象中为所有图像使用相同的缓冲区,您可以摆脱AWT,基于PNGJ的JOGL PNG编码器比AWT/Swing等效编码器速度更快,内存占用更少。顺便说一句,FFMPEG和LibAV已经在媒体播放器的JOGL中的引擎盖下使用。也许您可以查看源代码,了解如何公开所需的编写方法,这样可以避免使用大量PNG文件。