繁体   English   中英

拍照时未调用 ImageReader.OnImageAvailableListener()

ImageReader.OnImageAvailableListener() not being called when taking a picture

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

我有一个为 Android 26 SDK 开发的相机应用程序。 我一直很高兴地在摩托罗拉 G5 和 G6 上使用它,但是当我移动到摩托罗拉 G7 时,当我按下按钮在我的应用程序中拍照时,应用程序崩溃了。

G7 运行的是 Android 9。我还有另一部 Android 9 手机和三星 S10 plus。 当我按下拍照按钮时,S10 plus 不会崩溃。

在调试时,我注意到 G7 不调用 ImageReader.OnImageAvailableListener 而 S10 调用。 查看代码,这是保存图像以供以后在 CameraCaptureSession.CaptureCallback 中使用的位置。 回调期望字节被填充并在没有填充时崩溃(我没有包括堆栈跟踪,因为它不是有点无用,但如果你认为你想看到它,我可以)。

如果我在“某些”场合通过调试缓慢运行它,我可以让 G7 保存图像。

所以我有一个按钮,它在里面调用 function onImageCaptureClick() 做了很多事情,但其中一件事是创建一个 ImageReader.OnImageAvailableListener。 OnImageAvailableListener 保存图像并从图像缓冲区填充可变字节。 这个 onImageAvailableListener 通过使用 reader.setOnImageAvailableListener(readerListener, null) 附加到我的阅读器,并且从未使用过这个监听器。 当我进入 CaptureCallBack 时,未填充 class 变量字节并且应用程序崩溃。

你知道我会在哪里解决这个问题吗?

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);
    }
2 个回复

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

我有以下手机:

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

我的应用适用于 S10 和 G6。 S10 和 G6 在onCaptureCompleted回调之前都调用了OnImageAvailableListener function。 然而,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 时,事件以不同的顺序触发。

希望这可以帮助

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

请不要对此做任何假设。

相反,如果您需要在处理某些事情之前触发两个回调,那么在继续之前等待两者都发生。 例如,检查每个回调中是否触发了另一个回调,如果是,则调用该方法进行处理。

2 什么可能是ImageReader.OnImageAvailableListener在Android Things上始终因“缓冲区已释放”而失败的原因

我想用官方的Raspberry Pi相机拍照,并将其保存到临时文件夹中,以用作嵌入式http(nanoHttp)服务器的资源,以将其显示在当前版本的Android Things上运行的网页上。 问题是,我离目标还很遥远。 我知道这通常是一个Android问题,但是对我来说,如果没有屏幕来 ...

3 在ImageReader.OnImageAvailableListener中执行时,线程代码未完成

本质上,我想完成的工作是将摄像机的视图预览到屏幕上,然后对线程中可用的每个图像执行一些背景处理。 我尝试依次运行下面的代码(没有线程),该代码可以正常运行,但是由于进行了大量的处理,相机开始出现很多卡顿现象。 一旦将处理代码放在线程上,摄像机就会再次平稳运行,但是该线程永远不会完成其功能 ...

6 拍照后未调用onActivityResult

我知道该主题的文献记录很丰富,因此我已经阅读了很多有关该问题的文章,但是仍然存在以下问题:当我使用我的应用拍照并单击“验证”按钮时,什么也没有发生。 我正在做的动画:不仅向缩略图传递onActivityReult函数,而且传递相机拍摄的“整个”照片。 这是为“拍照”按钮定义的侦听器: ...

8 拍照时预览未暂停

我有一个相机应用程序,可以帮上忙。 在我的Camera Fragment中,我调用了takePicture方法,该方法旨在暂停预览(根据API )。 在我以前的HTC One X上确实如此,但是刚升级到HTC One mini2时,预览不再暂停。 是否有逻辑上的原因? 对我的代码 ...

10 在 Android 中拍照后未调用 onActivityResult

我正在使用此代码,但我的 onActivityResult 从未被调用。 我过去常常提出请求,而没有传递将图像保存到 SD 卡的额外意图,而且效果很好 - onActivityResult()会像我期望的那样被调用。 但是因为我添加了 SD 卡代码 - 没有运气! 我添加(或错过)了什么? 我以h ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM