【问题标题】:android camera2 api - onImageAvailable is not invoked after session.captureandroid camera2 api - 在 session.capture 之后不调用 onImageAvailable
【发布时间】:2017-03-03 18:11:40
【问题描述】:

我正在尝试使用相机 api2 来捕捉图像。该代码在 MOTO g4 上运行良好,但是当我在 NEXUS 6 上测试代码时,在 session.capture 之后没有调用 onImageAvailable,并且没有保存任何图像。真的很沮丧,如果有人可以提供帮助,将不胜感激!非常感谢。

        ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
        List<Surface> outputSurfaces = new ArrayList<Surface>(2);
        outputSurfaces.add(reader.getSurface());
        outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
        final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(reader.getSurface());
        captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
        // Orientation
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
        sendUri = getImageUri();
        final File file = new File(Environment.getExternalStorageDirectory()+"/"  + sendUri +".jpg");
        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();
                    byte[] bytes = new byte[buffer.capacity()];
                    buffer.get(bytes);
                    save(bytes);

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException 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();
                    }
                }
            }
        };
        reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
        final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {

            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
                //Toast.makeText(MainActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
                toast1("Saved:"+file);
                //createCameraPreview();
            }
        };
        cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(CameraCaptureSession session) {
                try {
                    session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onConfigureFailed(CameraCaptureSession session) {
            }
        }, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }

下面是nexus 6运行相机功能时的完整logcat输出,似乎没什么用......

03-07 13:04:34.526 1838-1838/examples.hello E/AndroidCameraApi: is camera open
03-07 13:04:34.527 1838-1838/examples.hello I/CameraManagerGlobal: Connecting to camera service
03-07 13:04:34.659 1838-1838/examples.hello E/AndroidCameraApi: openCamera X
03-07 13:04:34.694 1838-1838/examples.hello E/AndroidCameraApi: onOpened
03-07 13:04:34.722 1838-1883/examples.hello D/OpenGLRenderer: endAllActiveAnimators on 0x931bee80 (RippleDrawable) with handle 0x92c2cea0
03-07 13:04:43.952 1838-1838/examples.hello E/AndroidCameraApi: onPause

【问题讨论】:

  • 谢谢!我正在使用的nexus 6 正在运行android 7.0 版。我认为它应该能够支持camera2 api。
  • 我认为应该归咎于 android.camera2 API。更复杂的是,此 API 不支持任何低于 21 的 API 级别。许多相机应用程序仍在使用已弃用的相机 API。

标签: android android-camera2


【解决方案1】:

如果您包含故障设备的完整 logcat 输出会很有帮助,但我怀疑问题是这样的:

ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);

您正在创建一个本地 ImageReader 对象,而不是保存它以供进一步使用。你确实从中得到了一个 Surface,但 Surface 很像一个弱指针;如果没有引用它,它不会阻止 ImageReader 获得 GC(请参阅 note in the developer references)

所以我怀疑如果你只是创建一个类成员 mReader 变量,并将 reader 存储在其中,一切都会正常工作。

由于 GC 算法的不同,它可能在 Moto 手机上运行;运行时还没有完全清除读取器对象,所以它有时间调用回调。

【讨论】:

  • 非常感谢!你能告诉我更具体的吗?
  • 1) 将“私有 ImageReader mReader”添加到您的班级。 2)将阅读器保存到mReader
  • 超级有帮助,你节省了我用头撞墙的时间(甚至更多:D)
【解决方案2】:

像这样覆盖onConfigureFailed():

   @Override
   public void onConfigureFailed(CameraCaptureSession session) {
       ImageReader mReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);
       takePicture() // function to get image
       createCameraPreview(); // function to set camera Preview on screen
   }

调用createCameraPreview函数重启相机,否则会卡住。 您可以使用新值更改 ImageReader

ImageReader mReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);

并再次调用takePicture()函数,这样用户就不必再次点击来捕获图像了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    相关资源
    最近更新 更多