我可以在onPreviewFrame回调中使用lockCanvas()吗?

时间:2013-04-17 22:03:42

标签: android camera surfaceview augmented-reality

在onPreviewFrame中使用lockCanvas()时,我正在使用IllegalArgumentException。

基本上我想要实现的是抓取框架,处理它,并将其直接绘制到SurfacePreview的表面。

这是我的onPreviewFrame代码

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    Canvas canvas = null;

    if (mHolder == null) {
        return;
    }

    int mImgFormat = mCamera.getParameters().getPreviewFormat();

    try {
        canvas = mHolder.lockCanvas();
        canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
        mHolder.unlockCanvasAndPost(canvas);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (canvas != null)
        {
            mHolder.unlockCanvasAndPost(canvas);
        }
    }
}

我已经在android中阅读了很多关于相机的文档和主题,我认为锁定框架的表面是不可能的,因为它超出了应用程序控件的范围。这是真的吗?

可能的解决方案之一是使用另一个视图绘制表面视图的顶部,但我想保持我的处理帧(将有一些精确的边缘检测和颜色校正,这可能是耗时的)与同步绘制预习。当相机将保持具有良好fps的吐痰帧时,我的计算将很难赶上,并且在最坏的情况下,绘制一个覆盖数十帧的覆盖。

我研究过openCV源代码,对我来说,看起来他们已经设法在CameraBridgeViewBase.java中做到了这一点:

protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
    Mat modified;

    if (mListener != null) {
        modified = mListener.onCameraFrame(frame);
    } else {
        modified = frame.rgba();
    }

    boolean bmpValid = true;
    if (modified != null) {
        try {
            Utils.matToBitmap(modified, mCacheBitmap);
        } catch(Exception e) {
            Log.e(TAG, "Mat type: " + modified);
            Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
            Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
            bmpValid = false;
        }
    }

    if (bmpValid && mCacheBitmap != null) {
        Canvas canvas = getHolder().lockCanvas();
        if (canvas != null) {
            canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
            canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null);
            if (mFpsMeter != null) {
                mFpsMeter.measure();
                mFpsMeter.draw(canvas, 20, 30);
            }
            getHolder().unlockCanvasAndPost(canvas);
        }
    }
}

我要么错过了一些东西,要么我太老了。)

另外,这是我在这里发表的第一篇文章,大家好啊:)

1 个答案:

答案 0 :(得分:1)

实际上,openCV的相机起了一个小技巧。在CameraBridgeViewBase.java和JavaCameraView.java文件中。我发现SurfaceTexture类(来自api 11)用于从相机接收帧。 SurfaceTexture的优点是你不需要总是在屏幕上绘制它(它可以包含在内存中)。然后,SurfaceView类负责从onPreviewFrame函数中绘制处理过的帧。请注意,此SurfaceView未绑定到相机。希望这可以提供帮助。