onPreviewframe只调用一次

时间:2013-01-25 11:23:55

标签: android camera frame preview

我正在开发相机应用程序,你需要提取每帧预览的一些数据,所以我试图用onPreviewFrame来做,问题是我的代码onPreviewFrame只调用一次而调试我不得到错误所以我不知道该怎么做

这是我的代码

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private static final String TAG = "CameraPreview";
    private SurfaceHolder mHolder;
    private Camera mCamera;
    public byte[] buffer;//for previewcallback

    public CameraPreview(Context context, Camera camera) {
        super(context);
        Log.d("Function", "CameraPreview constructor iniciado");
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        Log.d("Function", "SurfaceCreated iniciado");
        try {
            mCamera.setPreviewDisplay(holder);

            buffer = previewBuffer();
            mCamera.addCallbackBuffer(buffer);
            mCamera.setPreviewCallbackWithBuffer(previewCallback);

            mCamera.startPreview();

        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        Log.d("Function", "SurfaceDestroyed iniciado");

    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        Log.d("Function", "surfaceChanged iniciado");
        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here


        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);

            buffer = previewBuffer();
            mCamera.addCallbackBuffer(buffer);
            mCamera.setPreviewCallbackWithBuffer(previewCallback);

            mCamera.startPreview();

        } catch (Exception e) {
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

    //Create the callback to access preview frames
    PreviewCallback previewCallback = new PreviewCallback() {

        public void onPreviewFrame(byte[] data, Camera camera) {
            // TODO Auto-generated method stub
            Log.d("Function", "onPreviewFrame iniciado");
            //Convert to jpg
            Size previewSize = camera.getParameters().getPreviewSize();
            Log.d("Function", "onPreviewFrame: preview size=" + previewSize.height + " " + previewSize.width);
            YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            yuvImage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 80, baos);
            byte jpgData[] = baos.toByteArray();
        }
    };

    //To create a buffer of the preview bytes size
    private byte[] previewBuffer() {
        Log.d("Function", "previewBuffer iniciado");
        int bufferSize;
        byte buffer[];
        int bitsPerPixel;

        Camera.Parameters mParams = mCamera.getParameters();
        Camera.Size mSize = mParams.getPreviewSize();
        Log.d("Function", "previewBuffer: preview size=" + mSize.height + " " + mSize.width);
        int mImageFormat = mParams.getPreviewFormat();

        if (mImageFormat == ImageFormat.YV12) {
            int yStride = (int) Math.ceil(mSize.width / 16.0) * 16;
            int uvStride = (int) Math.ceil((yStride / 2) / 16.0) * 16;
            int ySize = yStride * mSize.height;
            int uvSize = uvStride * mSize.height / 2;
            bufferSize = ySize + uvSize * 2;
            buffer = new byte[bufferSize];
            Log.d("Function", "previewBuffer: buffer size=" + Integer.toString(bufferSize));
            return buffer;
        }

        bitsPerPixel = ImageFormat.getBitsPerPixel(mImageFormat);
        bufferSize = (int) (mSize.height * mSize.width * ((bitsPerPixel / (float) 8)));
        buffer = new byte[bufferSize];
        Log.d("Function", "previewBuffer: buffer size=" + Integer.toString(bufferSize));
        return buffer;
    }
}

1 个答案:

答案 0 :(得分:17)

收到addCallbackBuffer添加的预览缓冲区后,您需要在完成后将其还原到相机(否则,相机可能会在您使用完之前覆盖您的数据) )。因此,一旦您在onPreviewFrame调用中使用了数据字节数组,请再次使用addCallbackBuffer将其返回给摄像机。

您可能还需要考虑在设置相机时添加两个或更多回调缓冲区。如果没有可供使用的空闲缓冲区,摄像机将丢弃帧,因此如果您在处理过程中偶尔出现故障或其他延迟,则自由使用一些缓冲区可以平滑帧速率。