【问题标题】:Android camera preview of image taken not showing on specific devices拍摄的图像的 Android 相机预览未在特定设备上显示
【发布时间】:2017-01-11 23:04:06
【问题描述】:

通常,带有 PreviewCallback 的 android 相机 api 在拍摄照片后会冻结相机,这可以用作拍摄图像的批准屏幕。我的问题是这不是三星 S6 和 S6 edge 等手机的行为。这两款手机在拍照后继续进行实时预览。

拍摄的照片仍然很好,可以供以后使用,但预览不显示,我的应用程序设置方式,我有一个复选标记和一个 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");
        }

    }
};

【问题讨论】:

    标签: android camera android-camera samsung-mobile


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      拍照后相机不会自动停止预览,需要手动调用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 中,你可以在以后使用而无需重新计算。

      希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-15
        • 2015-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多