具有多个输出的 Camera2

Clo*_*ker 5 debugging android android-camera2

这是我的问题,我目前无法在调用捕获后使用来自 Camera2API 的静止捕获图像填充 3 个表面之一。我使用了 Google Camera2 Getting Started(需要链接)来设置样板,因此这段代码的大部分内容可能看起来很熟悉。

Camera2捕获状态:

每个请求将生成一个 CaptureResult 并为一个或多个目标 Surface 生成新帧,使用 CaptureRequest 构建器的 addTarget(Surface) 方法设置。目标表面(使用 addTarget(Surface) 设置)必须是创建此捕获会话时提供的表面的子集。

好的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);
 ...
Run Code Online (Sandbox Code Playgroud)

然后这样做

// 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);
Run Code Online (Sandbox Code Playgroud)

此时,被添加到被传递给捕获方法的请求中的表面会将相机缓冲区输出到所有表面。但是,我只看到 mImageReader 的回调被调用,而 displaySurfaces 没有得到爱。

所以我开始在调试器中寻找并注意到传递给捕获的请求有一组大小为 2 的输出,如果大小为 3(两者都正确),则相机会话的内部输出的大小设置。然而,显示表面什么也没显示。另一个表面显示预览,效果很好。

我检查过的东西:a) 是的,视图是可见的,它的表面已经准备好了 b) 视图具有相机支持的分辨率,并已使用 setFixedSize() 设置

这里发生的事情我觉得我错过了一些东西。帮助!

编辑1

以下是曲面的生成方式;

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;
    }
Run Code Online (Sandbox Code Playgroud)

这就是我如何将它们组合在一起

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);
}
Run Code Online (Sandbox Code Playgroud)

这是未运行预览时应用程序的屏幕截图。我将右下角的框着色为蓝色,这是未显示相机输出的显示表面。

我还附上了 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
Run Code Online (Sandbox Code Playgroud)

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

编辑2

当来自表面的两个回调都通过 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();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

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

Clo*_*ker 1

谢谢@EddyTalvala,结果发现问题是由于分辨率不匹配造成的。预览表面:3264 x 2446 显示表面:176 X 148

我在中间开会,将这两个决议都更改为640,480,从而解决了问题。