如何获得Android摄像头preVIEW数据? [英] How to get Android camera preview data?

查看:531
本文介绍了如何获得Android摄像头preVIEW数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的相机应用程序在屏幕上显示一个摄像头preVIEW,并处理它的背景。下面是相关code,冷凝尽可能(示如没有错误处理或字段声明):

My camera app displays a camera preview on the screen and also processes it in the background. Here is the relevant code, condensed as much as possible (e.g. no error handling or field declarations shown):

public final class CameraView extends SurfaceView implements
          SurfaceHolder.Callback, Runnable, PreviewCallback {

    public CameraView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

    void openCamera() {
        // Called from parent activity after setting content view to CameraView
        mCamera = Camera.open();
        mCamera.setPreviewCallbackWithBuffer(this);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        new Thread(this).start(); 

        // Set CameraView to the optimal camera preview size

        final Camera.Parameters params = mCamera.getParameters();
        final List<Camera.Size> sizes = params.getSupportedPreviewSizes();
        final int screenWidth = ((View) getParent()).getWidth();
        int minDiff = Integer.MAX_VALUE;
        Camera.Size bestSize = null;

        if (getResources().getConfiguration().orientation 
                == Configuration.ORIENTATION_LANDSCAPE) {
            // Find the camera preview width that best matches the
            // width of the surface.
            for (Camera.Size size : sizes) {
                final int diff = Math.abs(size.width - screenWidth);
                if (diff < minDiff) {
                    minDiff = diff;
                    bestSize = size;
                }
            }
        } else {
            // Find the camera preview HEIGHT that best matches the 
            // width of the surface, since the camera preview is rotated.
            mCamera.setDisplayOrientation(90);
            for (Camera.Size size : sizes) {
                final int diff = Math.abs(size.height - screenWidth);
                if (Math.abs(size.height - screenWidth) < minDiff) {
                    minDiff = diff;
                    bestSize = size;
                }
            }
        }

        final int previewWidth = bestSize.width;
        final int previewHeight = bestSize.height;

        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        layoutParams.height = previewHeight;
        layoutParams.width = previewWidth;
        setLayoutParams(layoutParams);

        params.setPreviewFormat(ImageFormat.NV21);
        mCamera.setParameters(params);

        int size = previewWidth * previewHeight * 
            ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
        mBuffer = new byte[size];
        mCamera.addCallbackBuffer(mBuffer);

        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();
    }

    public void onPreviewFrame(byte[] data, Camera camera) {
        CameraView.this.notify();
    }

    public void run() {
        mThreadRun = true;
        while (mThreadRun) {
            synchronized (this) {
                this.wait();
                processFrame(mBuffer); // convert to RGB and rotate - not shown
            }
            // Request a new frame from the camera by putting 
            // the buffer back into the queue
            mCamera.addCallbackBuffer(mBuffer);
        }

        mHolder.removeCallback(this);
        mCamera.stopPreview();
        mCamera.setPreviewCallback(null);
        mCamera.release();
        mCamera = null;
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        mThreadRun = false;
    }
}

在所有设备,摄像头preVIEW正常显示,而在大多数(仿真器,三星Galaxy S3等)存放在 mBuffer数据也是正确的(NV21到RGB转换,当然旋转,之后)。然而,大量的设备不提供正确的数据在previewFrame 。我敢肯定,该数据被转换会在收到后正确RGB,所以出现的问题是在提供给 mBuffer 的原始数据。我注意到这个错误报告有关的YV12(化名YUV420P)摄像头preVIEW格式,但我使用的是旧的默认,NV21(化名YUV420sp),必须按照<一个支撑href="http://static.googleusercontent.com/external_content/untrusted_dlcp/source.android.com/en//compatibility/4.2/android-4.2-cdd.pdf"相对=nofollow>兼容标准(见7.5.3.2,第29页底部)。

On all devices, the camera preview displays properly, and on most (emulator, Samsung Galaxy S3, etc.) the data stored in mBuffer is also correct (after NV21 to RGB conversion and rotation, of course). However, a number of devices do not supply the correct data in onPreviewFrame. I'm sure that the data is being converted to RGB correctly after it's received, so the problem appears to be in the raw data supplied to mBuffer. I've noticed this bug report relating to the YV12 (alias YUV420p) camera preview format, but I'm using the old default, NV21 (alias YUV420sp), which must be supported according to the compatibility standard (see 7.5.3.2, bottom of page 29).

例如,对于这一幕(如图所示在摄像头preVIEW对三星Galaxy Tab 2):

For example, for this scene (shown here in Camera Preview on the Samsung Galaxy Tab 2):

传递给 mBuffer 上的Tab 2的数据是这样的:

the data passed to mBuffer on the Tab 2 looks like:

和摩托罗拉Droid 4的样子:

and on the Motorola Droid 4 looks like:

什么是正确的方式来获得所有设备Android摄像头preVIEW数据?

编辑:作为 processFrame(),我用的OpenCV转换为RGB和旋转。请参见这个答案这个答案

for processFrame(), I used OpenCV to convert to RGB and rotate. See this answer and this answer.

推荐答案

唯一的问题是,我没有设置preVIEW宽度和高度:

The only problem was that I didn't set the preview width and height:

params.setPreviewSize(previewWidth, previewHeight);
mCamera.setParameters(params);

这意味着,高度和宽度予分配给数组(正比于previewWidth * previewHeight)往往比实际的数据的尺寸大很多被返回(成正比的默认的preVIEW宽度和preVIEW高度)。在一些手机中,默认是同样大小previewWidth和previewHeight,所以没有问题。

This meant that the height and width I allocated for the array (proportional to previewWidth * previewHeight) tended to be a lot larger than the size of the actual data being returned (proportional to the default preview width and preview height). On some phones, the default was the same size as previewWidth and previewHeight, so there was no issue.

这篇关于如何获得Android摄像头preVIEW数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆