java - glReadPixels 返回的数据比预期多

标签 java opengl buffer jogl glreadpixels

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

无论如何,我的问题是,如果我运行 opengl 类,它可以工作,但是,如果我从另一个类调用该类,那么我会看到 glReadPixels 向我抛出错误。它总是返回到缓冲区的数据多于分配给我的缓冲区“pixelsRGB”的内存。有谁知道为什么吗?

例如:宽度=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);
 }

注意:有了 pleuron 的答案,现在它可以工作了。好的代码是:

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_ALIGNMENT的默认值为4。这意味着pixelsRGB的每一行应该从一个地址开始4 的倍数,并且缓冲区的宽度 (1042) 乘以像素中的字节数 (3) 不是 4 的倍数。添加一点填充,使下一行以 4 的倍数开始,将使总数缓冲区的字节大小比您预期的要大。

要修复此问题,请将 GL_PACK_ALIGNMENT 设置为 1。您还可以使用 GL_RGBA 读取像素并使用更大的缓冲区,因为数据最有可能存储在在 GPU 上和 BufferedImage 中都可以使用。

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

关于java - glReadPixels 返回的数据比预期多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41404432/

相关文章:

math - 两个 4x4 矩阵相减 - 这可能吗?

opengl - 将 GLFW 窗口设置为不可调整大小

java - 需要一些帮助来使用 Frustum Culling 实现 VBO

c++ - char 数组存储太多字符? (c++)

java - 如何解决界面中似乎需要 setter 的情况?

java - PlayFramework 在 http 而不是 httpS 中返回绝对 url?

java - 使用 java6 从 Tomcat6 调用 JAX-WS RI 2.2 服务

java - 为什么需要使用java.util.TimerTask的purge()?

c++ - 通过校验和快速验证 1500 字节的内存

java - 如何将已制作的批处理文件写入 Java 中的特定目录?