在Android中使用OpenGL帧缓冲区时如何转换图像

在Android中使用OpenGL帧缓冲区时如何转换图像,android,opengl-es,bitmap,framebuffer,Android,Opengl Es,Bitmap,Framebuffer,我正在使用一个名为Cine.io的实时流媒体库将一帧从流媒体保存到Android的外部存储 图书馆本身使用谷歌的格拉菲卡资源 当我简单地设置一个ByteBuffer,然后用GLReadPixel读取它时,图像被正确保存,但它被反转,因为GL图像的坐标与BMP坐标相反 为了解决这个问题,我认为最有效的解决方案是使用OpenGL帧缓冲区渲染传入帧,使用正交矩阵翻转它,然后使用GLReadPixel读取它以将其保存到磁盘 这是我相信能够实现这一目标的准则: int width = getWidt

我正在使用一个名为Cine.io的实时流媒体库将一帧从流媒体保存到Android的外部存储

图书馆本身使用谷歌的格拉菲卡资源

当我简单地设置一个ByteBuffer,然后用GLReadPixel读取它时,图像被正确保存,但它被反转,因为GL图像的坐标与BMP坐标相反

为了解决这个问题,我认为最有效的解决方案是使用OpenGL帧缓冲区渲染传入帧,使用正交矩阵翻转它,然后使用GLReadPixel读取它以将其保存到磁盘

这是我相信能够实现这一目标的准则:

   int width = getWidth();
    int height = getHeight();
    ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4);
    buf.order(ByteOrder.LITTLE_ENDIAN);


    int[] fboId = new int[1];
    int[] rendId = new int[1];
    float[] projMatrix = new float[16];

    GLES20.glGenFramebuffers(1, fboId, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]);

         GLES20.glGenRenderbuffers(1, rendId, 0);
    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, rendId[0]);
    GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,GLES20.GL_RGBA4, width, height);


    switch(GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)){
        case GLES20.GL_FRAMEBUFFER_COMPLETE:
            Log.i(TAG, "Is Complete");
            break;
        case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            Log.i(TAG, "Incomplete Attachment");
            break;
        case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            Log.i(TAG, "Missing Attachment");
            break;
        default: Log.i(TAG, "Something else is going on");

    }
    GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER,rendId[0] );
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]);
    GLES20.glViewport(0,0,width, height);
    android.opengl.Matrix.orthoM(projMatrix, 0, 0, width, height, 0, -1, 1);


  GLES20.glReadPixels(0, 0, width, height,
            GLES20.GL_RGBA4, GLES20.GL_UNSIGNED_BYTE, buf);

    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);




    GlUtil.checkGlError("glReadPixels");
    buf.rewind();
但是,该代码只生成一个空的图像文件(大小为3.6kb)。此外,变量“buff”的块在调用GLreadpixels方法后仅由0组成

最后,如果我将BindFramebuffer设置为0(默认绑定),并将其放置在GLReadPixels调用之前,那么图像确实会显示,但仍然是反转的-就像帧缓冲区命令从未与它交互一样

我怎样才能解决这个问题


PS:很多人都在试图回答下面这个问题之前更复杂的版本,但问题的症结仍然存在。

你总是可以手动翻转缓冲区。我还没有使用过java的
ByteBuffer
,因此下面的代码可能不起作用,但它主要只是一个示例

//num channels being the amount of channels per pixel, 4 representing r, g, b, a
int num_channels = 4;
//allocate buffer size
ByteBuffer new_buf = ByteBuffer.allocateDirect(width * height * num_channels);
buf.order(ByteOrder.LITTLE_ENDIAN);

//calculate row size of image
int row_size = width * num_channels
//loop through the contents of the buffer and flip it
for (int y = 0; y < height; ++y) {
    for (int x = 0; x < row_size; ++x) {
        //put a row of bytes starting from the end of the buffer into the start of the new buffer
        new_buf.put(buf.get(((height - (y + 1)) - x) * row_size));
    }
}

这将在渲染时翻转纹理。尝试使用不同的值进行实验和混搭,以获得对它的体验。

肯定经历了帧缓冲区的歌舞,因此我可以访问选项2。我的问题是如何在Android中找到匹配方法。我会的。我认为您为选项2提供的代码是针对GL v1.0的。因为我在Android中使用GL2.0,所以在找到匹配的代码以将转换绑定到帧缓冲区时遇到了一些问题。哦,对了。对不起,我对openGL还是很陌生,但我想我仍然可以尝试帮助。所以,我有点困惑,你是从默认帧缓冲区(0)读取像素并保存到磁盘上?为什么需要在上面创建的帧缓冲区?您不应该绑定到上面创建的帧缓冲区id吗?我要做的是在渲染时绑定到上面创建的帧缓冲区,以便将其渲染到帧缓冲区(它不会显示在屏幕上)。在渲染时,应用矩阵变换,然后,您可以从该帧缓冲区读取像素。您是否也可以显示渲染代码,以便我可以看到您正在做什么来尝试帮助?谢谢:)刚刚用新代码更新了问题。希望大家能帮上忙——我已经做了几个小时了,但还是不能让它工作。顺便说一句,你是对的,我错误地读取了默认的帧缓冲区,这让我相信帧缓冲区正在渲染,而事实并非如此。
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f);