onPreviewframe只调用一次

use*_*792 5 camera android 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Edd*_*ala 18

一旦你收到你添加一个预览缓冲addCallbackBuffer,你需要给它背对着镜头一旦你用它做(否则,你用它做之前,相机可能会覆盖您的数据).因此,一旦您在onPreviewFrame调用中使用了数据字节数组,请再次使用addCallbackBuffer将其返回给摄像机.

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

  • 谢谢你,你是对的,现在它有效.我对android文档很困惑,因为它说"这个方法的目的是通过允许预览帧内存重用来提高预览效率和帧速率.你必须在某个时候调用addCallbackBuffer(byte []) - 在调用它之前或之后方法 - 或者不会收到回调"所以我不明白为什么它没有说"这个方法之前和之后" (5认同)