具有多个输出的Camera2

时间:2016-12-15 21:50:45

标签: android debugging android-camera2

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

Camera2 capture声明:

  

每个请求将生成一个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);
 ...

然后这样做

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

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

我还附加了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上的通知栏在整个屏幕上重复,底部软按钮移动到屏幕中间,非常奇怪)。我试图拍摄这种行为,但这就是我得到的

enter image description here

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

1 个答案:

答案 0 :(得分:1)

谢谢@EddyTalvala,原来这个问题是由于分辨率不匹配造成的。  PreviewSurface:3264 x 2446  DisplaySurface:176 X 148

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