android - 具有多个输出的 Camera2

标签 android debugging android-camera2

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

相机2 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);

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

所以我开始研究调试器并注意到传递给捕获的请求有一组大小为 2 的输出,并且相机 session 的内部输出集的大小为 3(两者都是正确的)。然而,显示表面什么也没有显示。另一个表面显示预览并且工作正常。

我检查过的东西: a) 是的, View 是可见的,它的表面已经准备好了 b) View 具有相机支持的分辨率,并已使用 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;
    }

下面是我如何将它们整合在一起

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 说它可以做到,为什么它不这样做!!

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

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

enter image description here

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

最佳答案

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

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

关于android - 具有多个输出的 Camera2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41173915/

相关文章:

java - 在BaseAdapter中调用onActivityResult

android - Camera2 API 支持的 FPS

javascript - 使用 StringRequest 通过 GDScript POST 到 Google Sheet。 GDScript 可以工作,但应用程序停止运行

android - 以编程方式复制/system/app/*.apk 到 sdcard

c++ - 如何在 C++ 中跟踪内存分配(尤其是新建/删除)

php - 检测哪个脚本导致服务器过载 - apache + php

debugging - 如何在 GAS 中测试触发功能?

android - 使用 Android Camera2 在视频捕获中设置亮度/对比度

android - 尝试第二次打开警报对话框时出现 FatalException