我根据连续捕获活动编写了一个演示。我想把视频的第一帧保存为jpeg文件,所以我使用了saveFrame()函数,这个函数已经由Grafika准备好了。该函数的源代码如下:https://github.com/google/grafika/blob/master/src/com/android/grafika/gles/EglSurfaceBase.java
但是我发现生成的jpeg图片是颠倒的。这不是我想要的。
是否有一种方法可以在保存帧之前旋转帧?
旋转位图不是一个优雅的解决方案,因为我们可能会遇到一些其他情况,如视频聊天。视频的每一帧被发送到远程对等体,然后远程人员将看到一个颠倒的视频。所以我们应该在编码前旋转每一帧
你不想让旋转框架,你想让翻转框架。
这种情况的存在是因为Bitmap认为(0,0)在左上角,而GLES认为(0,0)在左下角。glReadPixels()
从顶部开始填充缓冲区,Bitmap认为这是底部,所以你最终得到一个上下颠倒的图像。
你有两个选择:
- 用GLES倒过来画框架,然后按现在的样子抓取它。这就是ExtractMpegFramesTest代码所做的——注意
drawFrame()
函数接受invert
参数,并修改从SurfaceTexture获得的矩阵,如果它被设置。 - 按你现在的样子绘制和提取帧,然后在将它们转换为位图之前翻转缓冲区中的像素。这是一个简单的移动字节的问题。它会增加一些开销,但由于JPEG压缩,你已经有点慢了。(使用
System.arrayCopy()
复制整行可能比使用Java代码复制单个字节更好。)
我的实现如下,非常快,不到10ms。
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");
}