我有一个为Android 26 SDK开发的Camera App。 我曾经在Motorola G5和G6上愉快地使用过它,但是当我移动到Motorola G7时,当我按下按钮在应用程序中拍照时,应用程序崩溃。

G7正在运行Android9。我还有另一部Android 9手机,即Samsung S10 plus。 当我按下拍照按钮时,S10 plus不会崩溃。

调试时,我注意到G7不会调用S10时的ImageReader.OnImageAvailableListener。 查看代码,这是图像的保存位置,供以后在CameraCaptureSession.CaptureCallback中使用。 该回调函数期望填充字节并在不填充时崩溃(我没有包括堆栈跟踪,因为它并没有什么帮助,但是如果您认为自己愿意的话,我可以。)

如果在某些情况下通过调试缓慢运行G7,则可以保存该图像。

因此,我有一个按钮,在其中调用函数onImageCaptureClick()可以执行很多操作,但是它要做的一件事是创建ImageReader.OnImageAvailableListener。 OnImageAvailableListener保存图像并从图像缓冲区填充一个可变字节。 通过使用reader.setOnImageAvailableListener(readerListener,null)将此onImageAvailableListener附加到我的阅读器,并且从未使用过此侦听器。 当我进入CaptureCallBack时,类变量字节未填充,应用崩溃。

您有什么想法可以解决这个问题吗?

protected void onImageCaptureClick() {
    if (null == mCameraDevice) {
        logger.debug("null == mCameraDevice");
        Log.e(TAG, "cameraDevice is null");
        return;
    }
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

    try {
        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 = 640;
        int height = 480;
        if (jpegSizes != null && 0 < jpegSizes.length) {
            width = jpegSizes[0].getWidth();
            height = jpegSizes[0].getHeight();
        }
        ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
        List < Surface > outputSurfaces = new ArrayList < > (2);
        outputSurfaces.add(reader.getSurface());
        outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture()));
        final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(reader.getSurface());

        if (mFlashMode == FLASH_MODE_OFF) {
            captureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
            logger.debug("FLASH OFF");
        }

        if (mFlashMode == CONTROL_AE_MODE_ON) {
            captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                CaptureRequest.CONTROL_AE_MODE_ON);
            captureBuilder.set(CaptureRequest.FLASH_MODE,
                CaptureRequest.FLASH_MODE_TORCH);
            logger.debug("FLASH ON");
        }

        if (mFlashMode == CONTROL_AE_MODE_ON_AUTO_FLASH) {

            captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            captureBuilder.set(CaptureRequest.FLASH_MODE,
                CaptureRequest.FLASH_MODE_OFF);
            logger.debug("FLASH AUTO");
        }

        captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);

        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));

        final File file = new File(_pictureUri.getPath());
        logger.debug("OnImageCaptureClick: _pictureUri is: " + _pictureUri.getPath());
        // ************************************
        // this listener is not used on the G7,
        // and so the image isn't saved.
        // ************************************
        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();
                    bytes = new byte[buffer.capacity()];
                    buffer.get(bytes);
                    logger.debug("onImageCaptureClick, the filesize to save is: " + bytes.toString());
                    save();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (image != null) {
                        image.close();
                    }
                }
            }


            private void save() throws IOException {
                OutputStream output = null;
                try {
                    output = new FileOutputStream(file);
                    output.write(bytes);
                } finally {
                    if (null != output) {
                        output.close();
                    }
                }
            }


        };
        // ********************************************************
        // the reader sets the listener here but it is never called
        // and when I get in to the CaptureCallback the BitmapUtils
        // expects bytes to be populated and crashes the app
        // ********************************************************
        reader.setOnImageAvailableListener(readerListener, null);
        final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {

            @Override
            public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);

                try {
                    BitmapUtils.addTimeStampAndRotate(_pictureUri, bytes);


                    Intent intent = new Intent(CameraActivity.this, CameraReviewPhotoActivity.class);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, _pictureUri);
                    startActivityForResult(intent, CameraActivity.kRequest_Code_Approve_Image);

                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ImageReadException e) {
                    e.printStackTrace();
                } catch (ImageWriteException e) {
                    e.printStackTrace();
                }

            }
        };

        mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(CameraCaptureSession session) {
                try {
                    session.capture(captureBuilder.build(), captureListener, null);

                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(CameraCaptureSession session) {
                Log.w(TAG, "Failed to configure camera");
            }
        }, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    } finally {
        takePictureButton.setEnabled(false);
        mTextureView.setEnabled(false);
    }

#1楼 票数:0

我想我已经找到解决方案。

我有以下电话:

  • 三星S10 Plus
  • 摩托罗拉G7
  • 摩托罗拉G6

我的应用程序可以在S10和G6上运行。 S10和G6都在onCaptureCompleted回调之前调用OnImageAvailableListener函数。 然而,G7分别以onCaptureCompleted OnImageAvailableListener方式调用它们。

根据https://proandroiddev.com/understanding-camera2-api-from-callbacks-part-1-5d348de65950 ,正确的方法是onCaptureCompleted然后是OnImageAvailableListener

在我的代码中,我假设OnImageAvailableListener已保存图像,然后OnCaptureCompleted尝试对其进行操作,这将导致崩溃。

从每个设备的INFO_SUPPORTED_HARDWARE_LEVEL ,我具有以下级别的支持,从0级到3级以下。

  • 三星S10 Plus报告设备级别支持级别1
  • 摩托罗拉G7报告设备级别支持级别3
  • 摩托罗拉G6报告设备级别支持级别2

我现在的假设是,与其他级别相比,当您在级别3支持android-camera2 API时,事件以不同的顺序触发。

希望这可以帮助

#2楼 票数:0

API不保证onCaptureCompleted和OnImageAvailableListener的顺序。 它们可能以任意顺序到达,具体取决于设备,捕获设置,设备上的负载,甚至您拥有的特定操作系统版本。

请不要对此做任何假设。

相反,如果在处理某件事之前需要同时触发两个回调,则请等两个都发生后再继续。 例如,检查另一个回调是否已在每个回调中触发,如果是,则调用该方法进行处理。

  ask by Adam translate from so

未解决问题?本站智能推荐:

1回复

ImageReader 的 onImageAvailable 方法不调用并且预览仅显示 8 帧慢动作和冻结(Camera2)

我注意到小米红米 Note 9 Pro 上的奇怪行为。 我在数百部手机上测试了该应用程序,但此问题仅在此设备上出现,并且仅在使用具有YUV_420_888格式和 176*144 预览分辨率的 ImageReader 时才会出现(例如,使用 320 * 240 或 JPEG 或不使用ImageRead
1回复

当我使用 YUV_420_888 Image Reader 作为目标表面时,Camera 2 预览冻结

我正在开发一个应用程序,该应用程序需要在实时相机馈送中检测对象和面部。 为此,我正在使用 MLkit。 我已经成功地使用后置摄像头实现了对象检测部分,没有任何问题。 ML kit 建议使用 YUV_420_888,尺寸尽可能小,以获得更好的效果。 我正在使用 Camera 2 API,这是我设置I
2回复

使用ImageReader保存时,Android camera2预览图像无序

我正在使用Android Camera2 API拍摄一系列照片,用于实时姿势估计和环境重建(SLAM问题)。 目前我只是将所有这些图片保存在我的SD卡中进行离线处理。 我根据谷歌的Camera2Basic使用TextureView和ImageReader设置处理管道,它们都被设置为重复预
1回复

为什么Android的ImageReader类如此之慢?

我尝试使用OpenCV for Android 3.4.1的全新JavaCamera2View但它太慢了(仅显示摄像头视图~15fps)。 当我尝试使用较旧的JavaCameraView ,它给了我很好的结果(~30fps,这是我相机的极限)。 我想知道为什么Camera2版本如此缓慢并
1回复

尝试使用ImageReader获取每个Camera2帧时,出现“图像已关闭”的提示

我试图使用Camer2 API从相机获取每一帧以进行图像处理,但出现致命异常提示, 致命异常:主进程:com.example.avoor.camera2api,PID:2831 java.lang.IllegalStateException:图像已关闭 我可以成功打开相机并将其
1回复

如何使用 Android Camera2 API 访问 ImageReader 队列中的所有图像

在我的项目中,我需要连续捕捉相机流的帧。 这是我使用的当前代码片段。 为了设置 ImageReader,我将maxImages设置为 20。假设每次触发回调时,ImageReader 队列中都会有 20 帧。 然后访问这 20 帧的每个图像。 我使用了以下代码段。 这里的关键障碍是能够在回
1回复

使用格式 ImageFormat.Private 解释来自 ImageReader 的数据

我已经设置了一个针对 ImageReader 对象表面的 ConstrainedHighSpeedCaptureSession。 我的目标是捕捉一小段我想要进一步处理的高 FPS 镜头(例如,找到物体的加速度)。 HighSpeedCapture 会话仅在 ImageReader 的格式设置为
1回复

ImageReader使相机滞后

我遇到的问题是我使用ImageReader除了有一个SurfaceView用于显示相机的输出。 我已经像这样添加了SurfaceView本身和ImageReader的表面(并添加了ImageReader监听器以便在新图像上接收事件): 但是,如果我删除ImageReader,应用程序工