为什么我总是得到一张由GLSurfaceView进行屏幕截图的全黑图片?

时间:2015-08-13 16:50:49

标签: android bitmap android-bitmap glsurfaceview egl

我使用GLSurfaceView作为视图来显示相机预览数据。我使用createBitmapFromGLSurface瞄准抓取像素并将其保存到Bitmap

但是,在将位图保存到文件后,我总是得到一张完整的黑色图片。我哪里错了?

以下是我的代码段。

@Override
public void onDrawFrame(GL10 gl) {
    if (mIsNeedCaptureFrame) {
        mIsNeedCaptureFrame = false;
        createBitmapFromGLSurface(width, height);
    }
}

private void createBitmapFromGLSurface(int w, int h) {
    ByteBuffer buf = ByteBuffer.allocateDirect(w * h * 4);
    buf.position(0);
    buf.order(ByteOrder.LITTLE_ENDIAN);
    GLES20.glReadPixels(0, 0, w, h,
            GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
    buf.rewind();

    Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    bmp.copyPixelsFromBuffer(buf);

    Log.i(TAG, "createBitmapFromGLSurface w:" + w + ",h:" + h);
    mFrameCapturedCallback.onFrameCaptured(bmp);
}

更新

public void captureFrame(FrameCapturedCallback callback) {
    mIsNeedCaptureFrame = true;
    mCallback = callback;
}

public void takeScreenshot() {
    final int width = mIncomingWidth;
    final int height = mIncomingHeight;
    EglCore eglCore = new EglCore(EGL14.eglGetCurrentContext(), EglCore.FLAG_RECORDABLE);
    OffscreenSurface surface = new OffscreenSurface(eglCore, width, height);
    surface.makeCurrent();
    Bitmap bitmap = surface.captureFrame();

    for (int x = 0, y = 0; x < 100; x++, y++) {
        Log.i(TAG, "getPixel:" + bitmap.getPixel(x, y));
    }
    surface.release();
    eglCore.release();
    mCallback.onFrameCaptured(bitmap);
}

@Override
public void onDrawFrame(GL10 gl) {

    mSurfaceTexture.updateTexImage();

    if (mIsNeedCaptureFrame) {
        mIsNeedCaptureFrame = false;
        takeScreenshot();
        return;
    }
    ....
 }

日志如下:

getPixel:0
getPixel:0
getPixel:0
getPixel:0
getPixel:0
getPixel:0
getPixel:0
getPixel:0
getPixel:0
getPixel:0
getPixel:0
...

1 个答案:

答案 0 :(得分:2)

这不起作用。

要了解原因,请记住SurfaceView Surface是具有生产者 - 消费者关系的缓冲区队列。显示摄像机预览数据时,Camera是生产者,系统合成器(SurfaceFlinger)是消费者。只有生产者可以向Surface发送数据 - 一次只能有一个生产者 - 只有消费者可以从Surface检查缓冲区。

如果您自己在Surface上绘图,那么您的应用程序将成为制作人,您将能够看到您绘制的内容,但仅限于onDrawFrame()。返回时,GLSurfaceView调用eglSwapBuffers(),您绘制的帧将被发送给消费者。 (从技术上讲,因为缓冲区在池中并被重用,所以可以读取onDrawFrame()之外的帧;但是你正在阅读的内容将是1-2帧之前的陈旧数据,而不是你刚刚画的那个。)

您在这里所做的是从EGLSurface读取数据,该数据从未被绘制过,并且未连接到SurfaceView。这就是它总是读黑的原因。相机不会“绘制”预览,它只需要一个YUV数据缓冲区并将其推入BufferQueue。

如果您想使用GLSurfaceView显示预览和捕捉帧,请参阅Grafika中的“show + capture camera”示例。您可以使用glReadPixels()替换MediaCodec代码(请参阅EglSurfaceBase.saveFrame(),其外观与您的内容非常相似)。