Android Camera 2预览尺寸和设备宽高比

时间:2016-05-25 10:32:18

标签: android mobile

我在我的项目中实施了Camera 2 API。我使用TextureView和这些代码行设置相机全屏预览尺寸:

StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];

这似乎是设备支持的最大预览尺寸。我不确定这个尺寸是否适用于所有设备并且适合其设备的纵横比而不会被拉伸。有谁知道吗?

4 个答案:

答案 0 :(得分:8)

如果您的相机分辨率,纹理视图和设备的显示尺寸不同,则必须调整尺寸。为此,您必须将 TextureView放在FrameLayout 中。以下代码适用于具有各种显示分辨率的所有设备。

如果您要全屏预览,请选择展示尺寸。选择int DSI_heightint DSI_width全局变量。

    DisplayMetrics displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    DSI_height = displayMetrics.heightPixels;
    DSI_width = displayMetrics.widthPixels;

从Camera2 API中选择所需的分辨率并分配到Size imageDimension,全局拍摄private Size imageDimension并使用

setAspectRatioTextureView(imageDimension.getHeight(),imageDimension.getWidth());

并使用以下逻辑

private void setAspectRatioTextureView(int ResolutionWidth , int ResolutionHeight )
    {
        if(ResolutionWidth > ResolutionHeight){
            int newWidth = DSI_width;
            int newHeight = ((DSI_width * ResolutionWidth)/ResolutionHeight);
            updateTextureViewSize(newWidth,newHeight);

        }else {
            int newWidth = DSI_width;
            int newHeight = ((DSI_width * ResolutionHeight)/ResolutionWidth);
            updateTextureViewSize(newWidth,newHeight);
        }

    }

    private void updateTextureViewSize(int viewWidth, int viewHeight) {
        Log.d(TAG, "TextureView Width : " + viewWidth + " TextureView Height : " + viewHeight);
        textureView.setLayoutParams(new FrameLayout.LayoutParams(viewWidth, viewHeight));
    }

答案 1 :(得分:3)

可能存在边缘情况,这种方法会失败,但我对你的问题没有一个完美的答案。

相比之下,我对如何实现最有效的版本采取了正确的方法:

查看Google API demos for the Camera 2,我找到了一些示例代码,可以帮助您确保它适合所有正确尺寸的屏幕:

/**
 * Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
 * is at least as large as the respective texture view size, and that is at most as large as the
 * respective max size, and whose aspect ratio matches with the specified value. If such size
 * doesn't exist, choose the largest one that is at most as large as the respective max size,
 * and whose aspect ratio matches with the specified value.
 *
 * @param choices           The list of sizes that the camera supports for the intended output
 *                          class
 * @param textureViewWidth  The width of the texture view relative to sensor coordinate
 * @param textureViewHeight The height of the texture view relative to sensor coordinate
 * @param maxWidth          The maximum width that can be chosen
 * @param maxHeight         The maximum height that can be chosen
 * @param aspectRatio       The aspect ratio
 * @return The optimal {@code Size}, or an arbitrary one if none were big enough
 */
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
        int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {

    // Collect the supported resolutions that are at least as big as the preview Surface
    List<Size> bigEnough = new ArrayList<>();
    // Collect the supported resolutions that are smaller than the preview Surface
    List<Size> notBigEnough = new ArrayList<>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    for (Size option : choices) {
        if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
                option.getHeight() == option.getWidth() * h / w) {
            if (option.getWidth() >= textureViewWidth &&
                option.getHeight() >= textureViewHeight) {
                bigEnough.add(option);
            } else {
                notBigEnough.add(option);
            }
        }
    }

    // Pick the smallest of those big enough. If there is no one big enough, pick the
    // largest of those not big enough.
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizesByArea());
    } else if (notBigEnough.size() > 0) {
        return Collections.max(notBigEnough, new CompareSizesByArea());
    } else {
        Log.e(TAG, "Couldn't find any suitable preview size");
        return choices[0];
    }
}

Source

另外,您应该查看整个Camera2BasicFragment.javaAutoFitTextureView.java类,以便正确实施。

答案 2 :(得分:2)

更改AutoFitTextureView.java文件并设置如下所示的值:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension(width, height);
            Log.d("rlijeolid1",String.valueOf(width)+"\t"+String.valueOf(height));
        } else {
            setMeasuredDimension(width , height);
            Log.d("rlijeolid2",String.valueOf(height * mRatioWidth / mRatioHeight)+"\t"+String.valueOf(height));
        }
    }
}

答案 3 :(得分:2)

我通过不同的方法解决了这个问题。我得到了屏幕的宽度和高度,并计算了预览填充整个屏幕并保持宽高比所需的宽度或更高。它对我来说非常好,没有任何扭曲。

添加一个类成员变量:

public DisplayMetrics mMetrics = new DisplayMetrics();

将以下内容用作onMeasure

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(mMetrics);
        double ratio = (double)mRatioWidth / (double)mRatioHeight;
        double invertedRatio = (double)mRatioHeight / (double)mRatioWidth;
        double portraitHeight = width * invertedRatio;
        double portraitWidth = width * (mMetrics.heightPixels / portraitHeight);
        double landscapeWidth = height * ratio;
        double landscapeHeight = (mMetrics.widthPixels / landscapeWidth) * height;

        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension((int)portraitWidth, mMetrics.heightPixels);
        } else {
            setMeasuredDimension(mMetrics.widthPixels, (int)landscapeHeight);
        }
    }
}

非常感谢任何反馈;)

最佳M