我正在使用依赖Google Grafika回购的直播API。我正在使用Grafika EGLSurfaceBase的saveFrame方法,允许用户在流媒体时捕捉他的视频静止图像。
https://github.com/google/grafika/blob/master/src/com/android/grafika/gles/EglSurfaceBase.java
实际拍摄的工作原理很明显,在某些相机方向上,图像被翻转。
我发现很多与从OpenGL纹理中获取的反转位图有关的问题 - 但大多数似乎都是指绘制的图像,并依赖于:
a)在OpenG中翻转纹理。但在我的情况下,我正在使用实时流API,因此翻转纹理来捕获图像实际上可能会在视频流上翻转图像捕获。
OR
b)在基于资源生成位图之后翻转位图。在我的情况下,我没有资源,我正在从bytebuffer创建位图,而不是重复它来翻转它。
以下是API的基本EGLSurfaceBase方法 - 我将把相机方向传递给它但我的问题是:
String filename = file.toString();
int width = getWidth();
int height = getHeight();
ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4);
buf.order(ByteOrder.LITTLE_ENDIAN);
GLES20.glReadPixels(0, 0, width, height,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
GlUtil.checkGlError("glReadPixels");
buf.rewind();
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(filename));
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bmp.copyPixelsFromBuffer(buf);
bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);
bmp.recycle();
} finally {
if (bos != null) bos.close();
}
Log.d(TAG, "Saved " + width + "x" + height + " frame as '" + filename + "'");
}
我首选的解决方案是找到一种在BMP.createbitmap(或同时)之前翻转图像的方法。例如,我可以使用矩阵通过glReadPixels翻转像素的读数吗?
另一个注意/想法:创建后翻转位图的成本可能是微不足道的,因为这依赖于用户交互,它不会经常发生,导致内存错误吗?
答案 0 :(得分:2)
使用读取像素时图像似乎总是翻转,因为openGL显示缓冲区中的第一个像素位于左下角。有两种方法可以获得正确的订单。
一种是将其绘制到缓冲区,可以在单独的缓冲区上完成,并且根本不会干扰当前的绘图管道。如果您想在单独的线程上执行此操作或者调整图像大小,这实际上可能是一个非常好的主意。这一切都可以在一次平局调用中完成。
另一种是手动翻转数据,这并不像看起来那么糟糕,因为你只需要翻转行(列会非常糟糕)。无论如何,你实际上可以在同一个缓冲区上执行此操作,您不需要缓冲区的副本。只需按顺序交换线条,例如:保存第一行,将其替换为最后一行,将最后一行替换为保存的行...然后继续第二行。
答案 1 :(得分:2)
您可以在glReadPixels之后反转ByteBuffer。它非常快,因为它只是内存复制。我的测试显示逆向操作不到10毫秒。
这是一个可以实现的实现:
private void reverseBuf(ByteBuffer buf, int width, int height)
{
long ts = System.currentTimeMillis();
int i = 0;
byte[] tmp = new byte[width * 4];
while (i++ < height / 2)
{
buf.get(tmp);
System.arraycopy(buf.array(), buf.limit() - buf.position(), buf.array(), buf.position() - width * 4, width * 4);
System.arraycopy(tmp, 0, buf.array(), buf.limit() - buf.position(), width * 4);
}
buf.rewind();
Log.d(TAG, "reverseBuf took " + (System.currentTimeMillis() - ts) + "ms");
}