2

我正在尝试实时保存相机预览图像,我的目标是从放置在表面视图上的预览中保存至少 1fps。我被困在这个

mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
        private long timestamp=0;
        public synchronized void onPreviewFrame(byte[] data, Camera camera) {
            Log.v("CameraTest","Time Gap = "+(System.currentTimeMillis()-timestamp));
            timestamp=System.currentTimeMillis();
            try{
                FileOutputStream out;
                try {
                    Bitmap bmp=BitmapFactory.decodeByteArray(data,0,data.length);
                    out = new FileOutputStream("/mnt/sdcard/data/pippo.png");
                    bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
                } catch (FileNotFoundException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }           
                camera.addCallbackBuffer(data);
            }catch (Exception e) {
                Log.e("CameraTest", "addCallbackBuffer error");
                return;
            }
            return;
        }
    });

我想传入的字节数组

public synchronized void onPreviewFrame(byte[] data, Camera camera)

包含原始数据图像,因此我尝试将其转换为位图并保存在 sdcard 上。我的问题是:

  1. 这是为了实现我的目标而休耕的正确道路吗?
  2. 我在日志中收到此错误 SkImageDecoder::Factory 返回 null 我想它与位图转换有关,对吗?

欢迎任何建议。谢谢

在这里完整的代码:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

public class Demo extends Activity {
    SurfaceView mVideoCaptureView;
    private Camera mCamera;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mVideoCaptureView = (SurfaceView) findViewById(R.id.video_capture_surface);
        SurfaceHolder videoCaptureViewHolder = mVideoCaptureView.getHolder();
        videoCaptureViewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        videoCaptureViewHolder.addCallback(new Callback() {
            public void surfaceDestroyed(SurfaceHolder holder) {
            }

            public void surfaceCreated(SurfaceHolder holder) {
                startVideo();
            }

            public void surfaceChanged(SurfaceHolder holder, int format,
                    int width, int height) {
            }
        });
    }
    private void startVideo() {
        SurfaceHolder videoCaptureViewHolder = null;
        try {
            mCamera = Camera.open();
        } catch (RuntimeException e) {
            Log.e("CameraTest", "Camera Open filed");
            return;
        }
        mCamera.setErrorCallback(new ErrorCallback() {
            public void onError(int error, Camera camera) {
            }
        }); 
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewFrameRate(30);
        parameters.setPreviewFpsRange(15000,30000);
        List<int[]> supportedPreviewFps=parameters.getSupportedPreviewFpsRange();
        Iterator<int[]> supportedPreviewFpsIterator=supportedPreviewFps.iterator();
        while(supportedPreviewFpsIterator.hasNext()){
            int[] tmpRate=supportedPreviewFpsIterator.next();
            StringBuffer sb=new StringBuffer();
            sb.append("supportedPreviewRate: ");
            for(int i=tmpRate.length,j=0;j<i;j++){
                sb.append(tmpRate[j]+", ");
            }
            Log.v("CameraTest",sb.toString());
        }

        List<Size> supportedPreviewSizes=parameters.getSupportedPreviewSizes();
        Iterator<Size> supportedPreviewSizesIterator=supportedPreviewSizes.iterator();
        while(supportedPreviewSizesIterator.hasNext()){
            Size tmpSize=supportedPreviewSizesIterator.next();
            Log.v("CameraTest","supportedPreviewSize.width = "+tmpSize.width+"supportedPreviewSize.height = "+tmpSize.height);
        }

        mCamera.setParameters(parameters);
        if (null != mVideoCaptureView)
            videoCaptureViewHolder = mVideoCaptureView.getHolder();
        try {
            mCamera.setPreviewDisplay(videoCaptureViewHolder);
        } catch (Throwable t) {
        }

        Log.v("CameraTest","Camera PreviewFrameRate = "+mCamera.getParameters().getPreviewFrameRate());
        Size previewSize=mCamera.getParameters().getPreviewSize();
        int dataBufferSize=(int)(previewSize.height*previewSize.width*
                               (ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat())/8.0));

        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);

        mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
            private long timestamp=0;
            public synchronized void onPreviewFrame(byte[] data, Camera camera) {
                Log.v("CameraTest","Time Gap = "+(System.currentTimeMillis()-timestamp));
                timestamp=System.currentTimeMillis();
                try{
                    FileOutputStream out;
                    try {
                        Bitmap bmp=BitmapFactory.decodeByteArray(data,0,data.length);
                        out = new FileOutputStream("/mnt/sdcard/data/pippo.png");
                        bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
                    } catch (FileNotFoundException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }           
                    camera.addCallbackBuffer(data);
                }catch (Exception e) {
                    Log.e("CameraTest", "addCallbackBuffer error");
                    return;
                }
                return;
            }
        });
        try {
            mCamera.startPreview();
        } catch (Throwable e) {
            mCamera.release();
            mCamera = null;
            return;
        }
    }
    private void stopVideo() {
        if(null==mCamera)
            return;
        try {
            mCamera.stopPreview();
            mCamera.setPreviewDisplay(null);
            mCamera.setPreviewCallbackWithBuffer(null);
            mCamera.release();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        mCamera = null;
    }
    public void finish(){
        stopVideo();
        super.finish();
    };
}
4

1 回答 1

4

BitmapFactory 不知道如何解码来自相机的预览数据,因为它是一个原始像素数组,没有识别信息。这就是它抛出异常的原因。

您必须自己将数据转换/解释为 RGB 格式,并从中构造位图。默认情况下,相机提供NV21格式的预览数据。您可以在此处找到有关 NV21 的更多详细信息。要创建全彩 RGB 图像,您需要对两个色度通道进行上采样,然后将结果转换为 RGB。

如果您可以保存 JPEG,您也可以使用YuvImage类。

于 2012-09-15T22:50:57.240 回答