Android相机预览图像未在特定设备上显示

时间:2017-01-11 23:04:06

标签: android camera android-camera samsung-mobile

通常情况下,带有PreviewCallback的Android相机api会在拍摄照片后冻结相机,这可以用作拍摄图像的批准屏幕。我的问题是这不是像三星S6和S6边缘那样的手机行为。拍摄照片后,这两部手机将继续进行实时预览。

拍摄的照片仍然很好,可以用于以后使用,但预览不显示,我的应用程序的设置方式,我有一个检查和一个x标记,供用户批准他们刚刚拍摄的照片的。相反,他们有这个叠加检查和“x”和背景上的实时预览。这只发生在三星s6 / s6边缘。

知道在特定设备上会出现类似问题的原因吗?

用于预览和拍照的代码,其中包含一些日志记录:

class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    // SurfaceHolder
    private SurfaceHolder mHolder;

    // Our Camera.
    private Camera mCamera;

    // Parent Context.
    private Context mContext;

    // Camera Sizing (For rotation, orientation changes)
    private Camera.Size mPreviewSize;

    // List of supported preview sizes
    private List<Camera.Size> mSupportedPreviewSizes;
    private List<Camera.Size> mSupportPictureSizes;

    // Flash modes supported by this camera
    private List<String> mSupportedFlashModes;

    // View holding this camera.
    private View mCameraView;

    public CameraPreview(Context context, Camera camera, View cameraView) {
        super(context);

        Log.d(TAG, "CameraPreview: ");

        // Capture the context
        mCameraView = cameraView;
        mContext = context;
        setCamera(camera);

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

    /**
     * Begin the preview of the camera input.
     */
    public void startCameraPreview()
    {
        Log.d(TAG, "startCameraPreview: ");
        try{
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * Extract supported preview and flash modes from the camera.
     * @param camera
     */
    private void setCamera(Camera camera)
    {
        // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
        mCamera = camera;
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        mSupportPictureSizes = mCamera.getParameters().getSupportedPictureSizes();

        for(Camera.Size size : mSupportedPreviewSizes){
            Log.d(TAG, "supportedPreviewSizes width: " + size.width + " x " + size.height);
        }
        for(Camera.Size size : mSupportPictureSizes){
            Log.d(TAG, "mSupportPictureSizes width: " + size.width + " x " + size.height);
        }
        mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
        Camera.Parameters parameters = mCamera.getParameters();

        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

        // Set the camera to Auto Flash mode.
        if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);

        }

        mCamera.setParameters(parameters);
        requestLayout();
    }

    /**
     * The Surface has been created, now tell the camera where to draw the preview.
     * @param holder
     */
    public void surfaceCreated(SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated: ");
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Dispose of the camera preview.
     * @param holder
     */
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d(TAG, "surfaceDestroyed: ");
        if (mCamera != null){
            mCamera.stopPreview();
        }
    }

    /**
     * React to surface changed events
     * @param holder
     * @param format
     * @param w
     * @param h
     */
    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.

        if (mHolder.getSurface() == null){
            // preview surface does not exist
            Log.d(TAG, "surfaceChanged: preview surface does not exist");
            return;
        }
        Log.d(TAG, "surfaceChanged: start & stop preview");
        // 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);
            mCamera.startPreview();

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

    }

    @Override
    public SurfaceHolder getHolder() {
        return super.getHolder();
    }

    /**
     * Calculate the measurements of the layout
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {

        // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null){
            Log.d(TAG, "onMeasure: w x h: " + width + " x " + height);
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

    /**
     * Update the layout based on rotation and orientation changes.
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        Log.d(TAG, "onLayout: ");
        // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
        if (changed) {
            final int width = right - left;
            final int height = bottom - top;

            int previewWidth = width;
            int previewHeight = height;

            if (mPreviewSize != null){
                Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

                switch (display.getRotation())
                {
                    case Surface.ROTATION_0:
                        previewWidth = mPreviewSize.height;
                        previewHeight = mPreviewSize.width;
                        mCamera.setDisplayOrientation(90);
                        Log.d(TAG, "onLayout: rotation0");
                        break;
                    case Surface.ROTATION_90:
                        previewWidth = mPreviewSize.width;
                        previewHeight = mPreviewSize.height;
                        Log.d(TAG, "onLayout: rotation90");
                        break;
                    case Surface.ROTATION_180:
                        previewWidth = mPreviewSize.height;
                        previewHeight = mPreviewSize.width;
                        Log.d(TAG, "onLayout: rotation180");
                        break;
                    case Surface.ROTATION_270:
                        previewWidth = mPreviewSize.width;
                        previewHeight = mPreviewSize.height;
                        mCamera.setDisplayOrientation(180);
                        Log.d(TAG, "onLayout: rotation270");
                        break;
                }
            }

            final int scaledChildHeight = previewHeight * width / previewWidth;
            mCameraView.layout(0, height - scaledChildHeight, width, height);
        }
    }

    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        Log.d(TAG, "getOptimalPreviewSize: ");
        final double ASPECT_TOLERANCE = 0.05;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE){
                continue;
            }
            if (Math.abs(size.height - targetHeight) < minDiff) {
                Log.d(TAG, "getOptimalPreviewSize: found a match");
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            Log.d(TAG, "getOptimalPreviewSize: couldn't find match");
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        Log.d(TAG, "getOptimalPreviewSize: " + optimalSize.width + " x HEIGHT: " + optimalSize.height);
        return optimalSize;

    }

}


/**
 * Picture Callback for handling a picture capture and saving it out to a file.
 */
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        Camera.Parameters parameters = camera.getParameters();
        Camera.Size mPictureTakenSize = parameters.getPictureSize();
        System.out.println("picture taken size: " + mPictureTakenSize.width + " x " + mPictureTakenSize.height);
        if(data!=null){
            Log.d(TAG, "onPictureTaken: data not null, setting data to currentData");
//                currentData = data;
            setPictureTakenData(data);
            cameraViewModel.setPreview(true);
        }
        else{
            onProgress = false;
            Log.d(TAG, "onPictureTaken: data is null");
        }

    }
};

2 个答案:

答案 0 :(得分:1)

我刚遇到同样的问题。看起来你可以通过在PictureCallback的onPictureTaken方法中手动调用camera.stopPreview()来修复它。

答案 1 :(得分:0)

拍照后相机不会自动停止预览,因此您需要手动调用mCamera.stopPreview():

if (mCamera != null) {
    try {
        mCamera.stopPreview();
        pauseFlash();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// if current camera flash mode is TORCH, you need pause it.
private void pauseFlash() {
    if (currentFlashMode.equals(Camera.Parameters.FLASH_MODE_TORCH)) {
        params = mCamera.getParameters();
        params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        mCamera.setParameters(params);
    }
}

然后,在做了一些事情并导航回相机预览后:

@Override
public void startCameraPreview() {
    if (mCamera != null) {
        try {
            mCamera.startPreview();
            resumeFlash();
        } catch (Exception e) {
            e.printStackTrace();
            // TAKE CARE IF YOUR CAMERA HAS BEEN RELEASED
        }
    }
}

void resumeFlash() {
    flashChange(currentFlashMode);
}

我有一些性能提示:您应该在用户首次使用您的应用时找到最佳图片尺寸和预览尺寸,将其存储在SharedPreferences中,然后您可以在不重复计算后使用。

希望得到这个帮助。