预览在camera2 apis中延伸

Aka*_*iya 15 android screen-resolution android-camera android-textureview android-camera2

以下是在camera2 apis中使用纹理视图时的屏幕截图.在全屏幕中,预览会拉伸,但在使用较低分辨率(第二张图像)时可以使用.如何在不拉伸的情况下全屏使用此预览.

Sir*_*Lam 5

以下答案假定您仅处于纵向模式。

你的问题是

如何在不拉伸的情况下全屏使用预览

让我们将其分解为两件事:

  1. 您希望预览充满屏幕
  2. 预览不会失真

首先,您需要知道,如果设备的视口在相机提供的任何可用分辨率下具有不同的宽高比,则不进行裁剪在逻辑上是不可能的。

因此,我假设您接受裁剪预览。

步骤1:获取可用分辨率的列表

StreamConfigurationMap map = mCameraCharacteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
    throw new IllegalStateException("Failed to get configuration map: " + mCameraId);
}
Size[] sizes = map.getOutputSizes(SurfaceTexture.class);
Run Code Online (Sandbox Code Playgroud)

现在,您将获得设备相机可用分辨率(尺寸)的列表。

步骤2:找出最佳长宽比

这个想法是循环大小,然后看哪种最合适。您可能需要编写自己的“最佳匹配”实现。

我这里将不提供任何代码,因为我所拥有的与您的用例完全不同。但理想情况下,应该是这样的:

Size findBestSize (Size[] sizes) {
    //Logic goes here
}
Run Code Online (Sandbox Code Playgroud)

步骤3:告诉Camera API您要使用此大小

    //...
    textureView.setBufferSize(bestSize.getWidth(), bestSize.getHeight());
    Surface surface = textureView.getSurface();
    try {
        mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mPreviewRequestBuilder.addTarget(surface);
        mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                mSessionCallback, null);
    } catch (final Exception e) {
        //...
    }
Run Code Online (Sandbox Code Playgroud)

步骤4:使预览范围超出视口

然后,这与Camera2 API无关。我们让SurfaceView/ TextureView扩展到设备视口之外,从而“裁剪”预览。

首先将您SurfaceView或放置TextureView在中RelativeLayout

从第2步获得宽高比后,使用以下内容将其扩展到屏幕之外。
请注意,在这种情况下,甚至可能在启动相机之前需要了解该宽高比。

   //Suppose this value is obtained from Step 2.
    //I simply test here by hardcoding a 3:4 aspect ratio, where my phone has a thinner aspect ratio.
    float cameraAspectRatio = (float) 0.75;

    //Preparation
    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int screenWidth = metrics.widthPixels;
    int screenHeight = metrics.heightPixels;
    int finalWidth = screenWidth;
    int finalHeight = screenHeight;
    int widthDifference = 0;
    int heightDifference = 0;
    float screenAspectRatio = (float) screenWidth / screenHeight;

    //Determines whether we crop width or crop height
    if (screenAspectRatio > cameraAspectRatio) { //Keep width crop height
        finalHeight = (int) (screenWidth / cameraAspectRatio);
        heightDifference = finalHeight - screenHeight;
    } else { //Keep height crop width
        finalWidth = (int) (screenHeight * cameraAspectRatio);
        widthDifference = finalWidth - screenWidth;
    }

    //Apply the result to the Preview
    RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) cameraView.getLayoutParams();
    lp.width = finalWidth;
    lp.height = finalHeight;
    //Below 2 lines are to center the preview, since cropping default occurs at the right and bottom
    lp.leftMargin = - (widthDifference / 2);
    lp.topMargin = - (heightDifference / 2);
    cameraView.setLayoutParams(lp);
Run Code Online (Sandbox Code Playgroud)

如果您不关心步骤2的结果,则实际上可以忽略步骤1至步骤3,而只需在其中使用一个库即可,只要您可以配置其长宽比即可。(看来是最好的,但我还没有尝试过)

我已经使用分叉库进行了测试。在不修改库的任何代码的情况下,我仅使用步骤4就使全屏预览成为可能:

在使用步骤4之前:
在此处输入图片说明

使用第4步后:
在此处输入图片说明

拍照后的预览也不会变形,因为预览也扩展到了屏幕之外。
但是输出图像将包含您在预览中看不到的区域,这是很合理的。

通常从Google的CameraView引用步骤1到步骤3 的代码