使用Android camera2实现全屏预览

16
我正在使用新的camera2 API构建定制相机。我的代码基于Google提供的代码示例,可以在这里找到。
我找不到一种方法来使相机预览全屏显示。在代码示例中,他们使用比例优化来适应所有屏幕,但它只占据了屏幕高度的3/4左右。
这是我AutoFitTextureView的代码:
public class AutoFitTextureView extends TextureView {

private int mRatioWidth = 0;
private int mRatioHeight = 0;

public AutoFitTextureView(Context context) {
    this(context, null);
}

public AutoFitTextureView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

/**
 * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
 * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
 * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
 *
 * @param width  Relative horizontal size
 * @param height Relative vertical size
 */
public void setAspectRatio(int width, int height) {
    if (width < 0 || height < 0) {
        throw new IllegalArgumentException("Size cannot be negative.");
    }
    mRatioWidth = width;
    mRatioHeight = height;
    requestLayout();
}

@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, width * mRatioHeight / mRatioWidth);
        } else {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
        }
    }
}

非常感谢您的帮助。

}

2个回答

26

你应该将测量的宽度和高度改为覆盖整个屏幕,而不是适应屏幕大小如下所示。

来自:

if (width < height * mRatioWidth / mRatioHeight) 
if (width > height * mRatioWidth / mRatioHeight)

它对我来说运作良好。


1
我认为这样做不行。这会扭曲图像(在纵向模式下两侧被挤压)。 - J.M.
你好,我按照你的答案操作了,非常感谢,现在预览是全屏了。但是录制的视频旋转了180度,请问有解决方法吗?谢谢。 - Rishikesh pathak
1
如果您使用此解决方案,宽度会稍微被拉伸一些。 - ashwath hegde
1
当活动处于横屏状态时,这个不起作用。 - Georgios
1
使用了这个解决方案,认为它起作用了。我把它用于前置摄像头,但是相机中的图像没有居中。 - prex
显示剩余2条评论

11

这是您问题的解决方案。在这中,纵横比被设置为3/4。我修改了chooseVideSize方法,以选择具有高清分辨率的视频尺寸用于MediaRecorder

    private static Size chooseVideoSize(Size[] choices) {
        for (Size size : choices) {
            // Note that it will pick only HD video size, you should create more robust solution depending on screen size and available video sizes
            if (1920 == size.getWidth() && 1080 == size.getHeight()) {
                return size;
            }
        }
        Log.e(TAG, "Couldn't find any suitable video size");
        return choices[choices.length - 1];
    }

然后我更正了这个方法,根据视频大小的宽高比选择预览尺寸,以下是结果。

private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
    // Collect the supported resolutions that are at least as big as the preview Surface
    List<Size> bigEnough = new ArrayList<Size>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    double ratio = (double) h / w;
    for (Size option : choices) {
        double optionRatio = (double) option.getHeight() / option.getWidth();
        if (ratio == optionRatio) {
            bigEnough.add(option);
        }
    }

    // Pick the smallest of those, assuming we found any
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizesByArea());
    } else {
        Log.e(TAG, "Couldn't find any suitable preview size");
        return choices[1];
    }
}

我希望这能对你有所帮助!


3
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - J.M.
1
@J.M. 使用你的代码后,我发现屏幕右侧出现了额外的空白,有什么解决办法吗?如果我选择其他纵横比,它们要么太模糊,要么底部被裁剪。 - paul_hundal
您能提供设备信息,例如屏幕尺寸、首选预览大小和视频的首选预览大小吗? - MrOnyszko
在预览中显示水平线和扭曲的预览。可能出现了什么问题? - iMDroid
3
如果相机预览质量变差,则使用max而不是min Collections.max(bigEnough, new CompareSizesByArea()); - E.Abdel
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接