5

我正在开发一个相机应用程序,你需要提取每帧预览的一些数据,所以你尝试使用 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;
    }
}
4

1 回答 1

18

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

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

于 2013-01-25T19:26:48.523 回答