glReadPixels返回的数据超出预期

时间:2016-12-31 00:41:23

标签: java opengl buffer jogl glreadpixels

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

无论如何,我的问题是,如果我运行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);
 }

1 个答案:

答案 0 :(得分:3)

使用 glPixelStore 设置的 GL_PACK_ALIGNMENT 的默认值为4.这意味着 pixelsRGB 的每一行应从一个地址开始4的倍数,缓冲区的宽度(1042)乘以像素(3)中的字节数不是4的倍数。添加一点填充,以便下一行以4的倍数开始将使总数达到4缓冲区的字节大小大于预期。

&#xA;&#xA;

要修复它,请将 GL_PACK_ALIGNMENT 设置为1.您还可以使用<读取像素代码> GL_RGBA 并使用更大的缓冲区,因为数据最有可能以这种方式存储在GPU和 BufferedImage 中。

&#xA;&#xA ;

编辑: BufferedImage 没有方便的' setRGBA ',太糟糕了。

&#xA;