android – 具有多个输出的Camera2

这是我的问题,我目前无法在调用捕获后用Camera2API中的静态捕获图像填充3个Surface中的一个.我使用了Google Camera2入门(需要链接)来设置样板,因此这段代码中很大一部分看起来很熟悉.

Camera2 capture声明:

Each request will produce one CaptureResult and produce new frames for one or more target Surfaces, set with the CaptureRequest builder’s addTarget(Surface) method. The target surfaces (set with addTarget(Surface)) must be a subset of the surfaces provided when this capture session was created.

好的Android,我会遵守

// in order to use a surface they must be registered when creating the session
List<Surface> surfaces = new ArrayList<>(previewSurfaces); //size + 1
surfaces.addAll(displaySurfaces); // size + 1
surfaces.add(mImageReader.getSurface()); //size + 1
try {
    mCameraDevice.createCaptureSession(surfaces, mCaptureSessionCallback , null);
 ...

然后这样做

// Add the display surfaces along with the internal image reader
captureBuilder.addTarget(mImageReader.getSurface());
for(Surface surface : this.displaySurfaces) {
     captureBuilder.addTarget(surface);  //theres only one
}
CaptureRequest captureRequest = captureBuilder.build();
mCaptureSession.capture(captureRequest, captureCallback, mBackgroundHandler);

此时,添加到请求的表面将传递给捕获方法,并将相机缓冲区输出到所有表面.但是,我只看到在displaySurfaces没有爱的情况下调用mImageReader的回调.

所以我开始调试调试器,并注意到传递给捕获的请求有一组大小为2的输出,以及相机会话的内部输出集的大小,如果大小为3(两者都正确).但是,显示表面没有显示任何内容.另一个表面显示预览,工作正常.

我检查过的事情:
a)是的,视图是可见的,其表面已准备就绪
b)视图具有相机支持的分辨率,并使用setFixedSize()设置

这里发生了什么我觉得我错过了什么.救命!

EDIT1

这是表面的生成方式;

private SurfaceView getPreviewView(Context context) throws CameraAccessException {
        // TODO set z overlay?
        Size previewSize = mCameraController.determineLargestSize();
        Log.d(LOG_TAG, "Setting preview dimensions to: \n" +
            "width: " + Integer.toString(previewSize.getWidth()) + "\n" +
            "height " + Integer.toString(previewSize.getHeight()));
        SurfaceView view = new SurfaceView(context);
        view.getHolder().addCallback(mPreviewViewCallback);
        view.getHolder().setFixedSize(previewSize.getWidth(),previewSize.getHeight());
        view.setOnTouchListener(mZoomFocusListener);
        return view;
    }

private SurfaceView getDisplayTile(Context context) throws CameraAccessException {
        SurfaceView previewTile = new SurfaceView(context);
        Size smallest = mCameraController.determineSmallestSize();
        int width = smallest.getWidth();
        int height = smallest.getHeight();
        Log.d(LOG_TAG, "Setting display tile dimensions to: \n" +
                "width: " + Integer.toString(smallest.getWidth()) + "\n" +
                "height " + Integer.toString(smallest.getHeight()));
        previewTile.getHolder().addCallback(mDisplayCallback);
        previewTile.getHolder().setFixedSize(width,height);
        previewTile.setZOrderMediaOverlay(true);
        previewTile.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        previewTile.setBackgroundColor(Color.BLUE);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width,height);
        params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
        params.addRule(RelativeLayout.ALIGN_PARENT_END);
        params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        params.setMargins(7,7,7,7);
        previewTile.setLayoutParams(params);
        return previewTile;
    }

以下是我将它们整合在一起的方式

private void initViews(Context context) throws CameraAccessException {
        mFrameLayout = new FrameLayout(context);
        // Add the view for the camera preview
        FrameLayout.LayoutParams surfaceParams = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT);
        mPreviewView = this.getPreviewView(context);
        mFrameLayout.addView(mPreviewView,surfaceParams);

        // Add the preview tile to the layout
        FrameLayout.LayoutParams displayParams = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.WRAP_CONTENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        displayParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
        RelativeLayout layout = new RelativeLayout(context);
        mCapturedTile = this.getDisplayTile(context);
        layout.addView(mCapturedTile);
        mFrameLayout.addView(layout, displayParams);
}

这是没有预览运行时应用程序的屏幕截图.我将右下方的框颜色为蓝色,这是显示表面没有显示相机输出.
《android – 具有多个输出的Camera2》

我也附上了Logcat,给你并了解发生了什么

12-19 16:00:33.185 29863-29863/ngc.com.camera2app I/CameraController: This device has 2 available cameras
12-19 16:00:33.202 29863-29863/ngc.com.camera2app D/CameraController: Retrieveing current crop region
12-19 16:00:33.206 29863-29863/ngc.com.camera2app D/CameraView: Setting preview dimensions to: 
                                                                width: 3264
                                                                height 2448
12-19 16:00:33.208 29863-29863/ngc.com.camera2app D/CameraView: Setting display tile dimensions to: 
                                                                width: 176
                                                                height 144
12-19 16:00:33.948 29863-29863/ngc.com.camera2app D/CameraView: Surface created
12-19 16:00:33.949 29863-29863/ngc.com.camera2app D/CameraView: preview surface changed dimensions are
12-19 16:00:33.950 29863-29863/ngc.com.camera2app D/CameraView: width : 3264 | height : 2448
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: Surface created
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: display surface changed dimensions are
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: width : 176 | height : 144
12-19 16:00:33.973 29863-29863/ngc.com.camera2app I/CameraController: Attempting to open camera
12-19 16:00:34.048 29863-29929/ngc.com.camera2app I/CameraController: Camera 0 is open for business
12-19 16:00:34.055 29863-29863/ngc.com.camera2app W/PathParser: Points are too far apart 4.000000596046461
12-19 16:00:34.065 29863-29929/ngc.com.camera2app D/CameraView: Camera ready
12-19 16:00:48.343 29863-29929/ngc.com.camera2app I/CameraController: Image available

我仍然陷入困境,并且想要解决这个明显微妙的复杂错误并简单地从ImageReader的回调中加载图像.但是,如果API说它可以做到,为什么不这样做!!

EDIT2

当来自曲面的两个回调都通过onChanged()时,会调用此方法

private synchronized void openCamera(){
        if(displayReady && previewReady){
            try {
                List<Surface> displaySurfaces = new ArrayList<>();
                //uncommenting this line adds a nasty bug
                displaySurfaces.add(mPreviewView.getHolder().getSurface());

                List<Surface> previewSurfaces = new ArrayList<>();
                previewSurfaces.add(mCapturedTile.getHolder().getSurface());

                mCameraController.openCamera(displaySurfaces, previewSurfaces);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

EDIT3
将两个显示的分辨率更改为相同,结果相同. SystemUI变得非常扭曲(ontop上的通知栏在整个屏幕上重复,底部软按钮移动到屏幕中间,非常奇怪).我试图拍摄这种行为,但这就是我得到的

《android – 具有多个输出的Camera2》

请注意,上面的屏幕截图不是UI为我显示的内容.此外,在应用程序关闭并重新启动后,预览屏幕的一半为绿色(再次,无法通过屏幕截图捕获此内容).有什么想法吗?我开始认为Camera2 API有一个bug,但是,我也开始认为需要在这些表面上设置一些配置.不知道为什么奇怪的UI行为虽然……

最佳答案 谢谢@EddyTalvala,原来这个问题是由于分辨率不匹配造成的.

 PreviewSurface:3264 x 2446

 DisplaySurface:176 X 148

我在中间遇到并将这两者的分辨率更改为640,480并解决了这个问题.

点赞