捕获Camera2预览帧返回空缓冲区

5

我一直在开发一个简单的Android应用程序,旨在将流式相机帧从Android Camera2 API管道传递到我的算法中。我已经制作了几个应用程序,都是使用Android Camera1 API忠实地完成此操作的,但即使在检查(Google文档、论坛)以确认正确编码后,我仍无法从onImageAvailable()中的ImageReader中捕获任何真实数据。请注意以下相关代码:

  1. Setting up the ImageReaders:

    private void setUpCameraOutputs(int width, int height) {
    
    [....code....]
    
    mImageReader = ImageReader.newInstance(smallestJPEG.getWidth(), 
                                           smallestJPEG.getHeight(),
                                           ImageFormat.JPEG, /*maxImages*/2);
    // mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null);
    mPreviewImageReader = ImageReader.newInstance(smallest.getWidth(), 
                                                  smallest.getHeight(), 
                                                  ImageFormat.YUV_420_888, 2);
    mPreviewImageReader.setOnImageAvailableListener(mOnPreviewImageAvailableListener,
                                                    mBackgroundHandler);
    
    [....code....]
    
    }
    
  1. Setting up the CaptureSession:

    private void createCameraPreviewSession() {
    try {
        //Create Texture from Screen's TextureView
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
    
        assert texture != null;
    
        //Configure Default Buffer Size
        texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    
        //Create Output Surface from Texture
        Surface surface = new Surface(texture);
    
        // Set up a CaptureRequest.Builder with the output Surface.
        mPreviewRequestBuilder
                = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    
        //Add Output Display surface
        mPreviewRequestBuilder.addTarget(surface);
    
        //Add Preview frame-grabbing surface 
        mPreviewRequestBuilder.addTarget(mPreviewImageReader.getSurface());
    
        mCameraDevice.createCaptureSession(Arrays.asList(surface, mPreviewImageReader.getSurface()),
                new CameraCaptureSession.StateCallback() {
    
                    @Override
                    public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                        // The camera is already closed
                        if (null == mCameraDevice) {
                            return;
                        }
    
                        // When the session is ready, we start displaying the preview.
                        mCaptureSession = cameraCaptureSession;
                        try {
                            // Auto focus should be continuous for camera preview. [...code...]
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                            // Flash is automatically enabled when necessary.
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
    
                            // Finally, we start displaying the camera preview.
                            mPreviewRequest = mPreviewRequestBuilder.build();
                            mCaptureSession.setRepeatingRequest(mPreviewRequest,
                                    mCaptureCallback, mBackgroundHandler);
                        } catch (CameraAccessException e) {
                            [...code...]
                        }
                    }
    
                    @Override
                    public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                        [...code...]
                    }
                }, null
        );
    } catch (CameraAccessException e) {
        [...code...]
    }
    }
    
  1. Setting up the OnImageAvailableListener:

    private ImageReader mPreviewImageReader;
    private final ImageReader.OnImageAvailableListener mOnPreviewImageAvailableListener
    = new ImageReader.OnImageAvailableListener() {
    
    @Override
    public void onImageAvailable(ImageReader reader) {
    
        //Acquire Image, ByteBuffer, then byte array
        Image image = reader.acquireLatestImage();
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
    
        //Check bytes array for anydata
        int cnt = 0;
        for (int i = 0; i < bytes.length; i++){
            if (bytes[i] != 0)cnt++;
        }
        Log.i(TAG, "cnt = " + cnt);
        image.close();
    
        //At this point, byte[] bytes is empty (all zero)
        [...code...]
    }
    
    };
    
在代码片段#3中,无论ImageReader格式如何,我的字节缓冲区始终返回空(全零)。是否有人遇到过这个问题?我有没有漏掉任何代码?

我也遇到了同样的问题。你解决了吗? - SasukeIsCool
我相信在我的onImageAvailable示例中缺少了"buffer.get(bytes)"(将其作为实际代码的第四行)。 - shandroid
你是如何处理“无法在尚未调用Looper.prepare()的线程中创建handler”的问题的? - Bjqn
2个回答

6
byte[] bytes = new byte[buffer.remaining()];之后加上buffer.get(bytes);

许多在线样本实际上都存在这个错误,如果你不仔细看,很容易就会错过它。 - Jay Snayder

0
you miss some code check this,

 ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);
        FileOutputStream output = null;
        try {
            output = new FileOutputStream(mFile);
            output.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            mImage.close();
            if (null != output) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接