我使用名为Cine.io的实时流媒体库将流中的帧保存到Android的外部存储空间。
图书馆本身使用谷歌的Grafika资源。
当我只是设置一个ByteBufferand然后用GLReadPixel读取它时,图像被正确保存但由于GL图像具有BMP坐标的反向坐标而被反转。
为了解决这个问题,我认为最有效的解决方案是使用一个开放的GL帧缓冲区来渲染传入的帧,用正交矩阵翻转它,然后用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)。另外,在调用GLreadpixels方法之后,变量" buff" s块只包含0"
最后,如果我将BindFramebuffer设置为0(默认绑定)并将其放在GLReadPixels调用之前,那么图像确实会显示但仍然反转 - 它就像Framebuffer命令从未与它进行过交互一样。
我该如何解决这个问题?
PS:很多人都试图回答以下问题的前一个更复杂的版本 - 但它的症结仍然存在。答案 0 :(得分:0)
您可以随时手动翻转缓冲区。我还没有使用过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));
}
}
然而,这非常缓慢,并且在更新循环中绝对不理想。相反,在渲染代码中,您可以使用矩阵更改纹理在屏幕上的投影方式。尝试使用glOrtho
,如下所示:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f);
渲染时应该翻转纹理。尝试尝试并弄乱不同的值来感受它。