android camera2 api - onImageAvailable在session.capture之后不会被调用

问题描述:

我想用摄像头api2来捕捉图像。该代码在MOTO g4上运行良好,但是当我在NEXUS 6上测试代码时,onImageAvailable在session.capture之后未被调用,并且没有保存图像。真的很沮丧,非常感谢,如果有人可以帮助!非常感谢。android camera2 api - onImageAvailable在session.capture之后不会被调用

 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(); 
    } 

下面是承上启下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 
+0

谢谢!我正在使用的nexus 6正在运行android版本7.0。我认为它应该能够支持camera2 api。 – song

+0

我认为android.camera2 API会受到指责。复合这个问题的事实是这个API不支持低于21的任何API级别。许多摄像头应用程序仍然使用弃用的Camera API。 –

这将会是,如果你提供从发生故障的设备全输出logcat的有益,但我怀疑的问题是这样的:

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

你创建本地ImageReader对象,而不是将其保存为进一步使用。你从它得到一个Surface,但是Surface很像一个弱指针;如果没有引用它,它将不会使ImageReader获取GC'd(请参阅note in the developer references

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

由于GC算法的不同,它可能在Moto手机上工作;运行时尚未完全清除读者对象,因此有时间调用回调函数。

+0

非常感谢!你能更具体地告诉我吗? – song

+0

1)添加一个'私人ImageReader mReader'给你的班级。 2)将阅读器保存到mReader中 –