来自相机2 api的图像保存为黑色图像-Android Camera 2 api

时间:2016-04-07 07:03:10

标签: android image android-camera

我正在开发一个自定义相机,但在尝试使用Camera 2 api拍摄图像时,我正在获取黑色图像。我使用下面的代码进行捕获

  

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
            String cameraId = "";
            if (cameraFront) {
                cameraId = "" + findFrontFacingCamera();
            } else {
                cameraId = "" + findBackFacingCamera();
            }

            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
            // CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());

            Size[] jpegSizes = null;
            if (characteristics != null) {
                jpegSizes =
                        characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(
                                ImageFormat.JPEG);
            }
            int width = 720;
            int height = 640;
            if (jpegSizes != null && 0 < jpegSizes.length) {
                width = jpegSizes[0].getWidth();
                height = jpegSizes[0].getHeight();
            }
            StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            Size largest =
                    Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea());
            ImageReader reader =
                    ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, /* maxImages */1);
            // ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
            List<Surface> outputSurfaces = new ArrayList<Surface>(2);
            outputSurfaces.add(reader.getSurface());
            outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture()));

            final CaptureRequest.Builder captureBuilder =
                    mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureBuilder.addTarget(reader.getSurface());
            captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);

            // Orientation
            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            if (cameraFront) {
                captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation) + 180);

            } else {
                captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
            }
            final File file = getOutputMediaFile();

            ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener()
            {

                @Override
                public void onImageAvailable(ImageReader reader)
                {

                    Image image = null;
                    try {
                        image = reader.acquireLatestImage();
                        // ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                        // final byte[] bytes = new byte[buffer.capacity()];

                        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                        final byte[] bytes = new byte[buffer.remaining()];

                        buffer.get(bytes);
                        save(bytes);
                        buffer.clear();
                        runOnUiThread(new Runnable()
                        {

                            @Override
                            public void run()
                            {
                                mThumbnail.setVisibility(View.VISIBLE);
                                filePathLabel.setVisibility(View.VISIBLE);
                                filePathValue.setText(file.getAbsolutePath());

                                Bitmap bmp =
                                        UtilityMethods.getScaledBitmap(CameraImageTestActivityLoliipop.this, bytes);
                                mThumbnail.setImageBitmap(bmp);
                            }
                        });

                    } catch (FileNotFoundException e) {
                        AppLogger.exception(myContext, getClass().getSimpleName(), e);
                        // e.printStackTrace();
                    } catch (IOException e) {
                        AppLogger.exception(myContext, getClass().getSimpleName(), e);
                        // e.printStackTrace();
                    } finally {
                        if (image != null) {
                            image.close();
                        }
                    }
                }

                private void save(byte[] bytes) throws IOException
                {
                    OutputStream output = null;
                    try {
                        output = new FileOutputStream(file);
                        output.write(bytes);

                    } finally {
                        if (null != output) {
                            output.close();
                        }
                    }
                }

            };

            HandlerThread thread = new HandlerThread("CameraPicture");
            thread.start();
            final Handler backgroudHandler = new Handler(thread.getLooper());
            reader.setOnImageAvailableListener(readerListener, backgroudHandler);

            final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback()
            {

                @Override
                public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
                                               TotalCaptureResult result)
                {

                    super.onCaptureCompleted(session, request, result);

                    startPreview();
                }

            };

            mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback()
            {

                @Override
                public void onConfigured(CameraCaptureSession session)
                {

                    try {
                        session.capture(captureBuilder.build(), captureListener, backgroudHandler);
                    } catch (CameraAccessException e) {
                        AppLogger.exception(myContext, getClass().getSimpleName(), e);
                        // e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session)
                {

                }
            }, backgroudHandler);

        } catch (CameraAccessException e) {
            AppLogger.exception(myContext, getClass().getSimpleName(), e);
            // e.printStackTrace();
        }


and below are the methods for camera preview
  

protected void startPreview()           {               试试{

            if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
                Log.e(TAG, "startPreview fail, return");
                return;
            }

            SurfaceTexture texture = mTextureView.getSurfaceTexture();
            if (null == texture) {
                Log.e(TAG, "texture is null, return");
                return;
            }
            Log.e(TAG, "Width: " + mPreviewSize.getWidth() + "  Hieght : " + mPreviewSize.getHeight());
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            Surface surface = new Surface(texture);

            try {
                mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);

            } catch (CameraAccessException e) {
                AppLogger.exception(myContext, getClass().getSimpleName(), e);
                // e.printStackTrace();
            }
            mPreviewBuilder.addTarget(surface);

            mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback()
            {

                @Override
                public void onConfigured(CameraCaptureSession session)
                {

                    mPreviewSession = session;
                    updatePreview();
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session)
                {

                }
            }, null);
        } catch (CameraAccessException e) {
            AppLogger.exception(myContext, getClass().getSimpleName(), e);
            // e.printStackTrace();
        }
    }

    protected void updatePreview()
    {
        try {
            if (null == mCameraDevice) {
                Log.e(TAG, "updatePreview error, return");
            }

            mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
            // mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // Flash is automatically enabled when necessary.
            mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);

            HandlerThread thread = new HandlerThread("CameraPreview");
            thread.start();
            Handler backgroundHandler = new Handler(thread.getLooper());

            mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
        } catch (CameraAccessException e) {
          }

它可以在所有设备上工作,但是当我在Micromax Q382设备上运行时,然后在logcat中获得以下警告的黑色图像

  

I / Choreographer:跳过37帧!应用程序可能在其主线程上做了太多工作。   W / ImageReader_JNI:无法获取lockedBuffer,很可能客户端尝试锁定超过maxImages缓冲区

我不知道发生了什么。请帮助我。

3 个答案:

答案 0 :(得分:0)

您可以尝试在开始捕捉之前(以及打开相机后)设置一些延迟。类似的东西:

new Handler().postDelayed(() -> {
     //takePicture();
}, 500);

如果您愿意,我已经创建了一项服务,可以大规模使用Android Camera 2 API进行照片捕捉:https://github.com/hzitoun/android-camera2-secret-picture-taker。自述文件中描述了用法。

希望有所帮助!

答案 1 :(得分:0)

您将AE模式设置为“始终闪烁”,但是您不会运行预捕获序列以允许相机设备测量该闪光灯;这在任何设备上都可能无法正常工作,在某些设备上,您最终可能会遇到一些默认曝光值(不良)。

如果要激活闪光灯,则需要先在非LEGACY设备上使用预捕获序列(发送设置为AE_PRECAPTURE_TRIGGER的单个请求,等待PRECAPTURE AE_STATE结束,然后发出捕获请求)。如果设备是LEGACY级别,那么您当前的代码应该没问题。

答案 2 :(得分:0)

您在null内向createCaptureSession传递startPreview个参数。使之前使用的backgroudHandler对该方法可见(作为参数传递或将其初始化为类变量)并在那里使用。