繁体   English   中英

预览在camera2 apis中延伸

[英]preview stretches in camera2 apis

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

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

你的问题是

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

让我们把它分解成两件事:

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

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

第 2 步:找到最佳纵横比

这个想法是循环尺寸,看看哪一个最合适。 您可能需要编写自己的“最佳匹配”实现。

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

Size findBestSize (Size[] sizes) {
    //Logic goes here
}

第 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) {
        //...
    }

第 4 步:使您的预览超出您的视口

这与 Camera2 API 无关。 我们通过让SurfaceView / TextureView延伸到设备视口之外来“裁剪”预览。

首先将SurfaceViewTextureView放在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);

如果您不关心第 2 步的结果,您实际上可以忽略第 1 步到第 3 步,只需使用那里的库,只要您可以配置其纵横比即可。 (貌似这个是最好的,不过我还没试过)

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

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

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

而且刚拍照后的预览也不会失真,因为预览也超出了您的屏幕。
但是输出图像将包含您在预览中看不到的区域,这很有意义。

Step 1 到 Step 3 的代码一般参考谷歌的 CameraView

这是某些设备上的常见问题。 我注意到它主要是在三星上。 您可以使用在TextureView上设置转换的TextureView ,使其像ImageView行为一样 centerCrop

我也遇到过类似的情况,但是这一行解决了我的问题

view_finder.preferredImplementationMode = PreviewView.ImplementationMode.TEXTURE_VIEW

在您的 xml 中:

<androidx.camera.view.PreviewView
    android:id="@+id/view_finder"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

对于使用cameraX的相机实现,您可以参考https://github.com/android/camera-samples/tree/master/CameraXBasic

我想出你的问题是什么。 你可能正在尝试这样的事情:

textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int j) {
        cam.startPreview(surfaceTexture, i, j);
        cam.takePicture();
    }

    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { }
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return false; }
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { }
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM