1.问题:
首先我的应用场景Mediacodec ,使用了摄像头流与录屏流,中间会进行切换,然后录出来一个完整的视频,也就是从摄像到录屏再到摄像再录屏,需求比较。。。因为要录像又要录屏,所以不可能直接用手机屏幕的实际分辨率。所以从camera.getParameters()获取宽高并设置为输出的视频的分辨率。现象是很多手机上看录制好的视频录屏那块被缩小了,其实是因为有黑边造成的。因此问题其实是基于录屏的输出视频分辨率为核心的,其他录屏方案也大多适用。
2.分析
大多数手机获取的camera的分辨率与屏幕的分辨率不一致,重要的是长宽比不一样,比如说。相机获取了1920*1080的分辨率,而你的手机是2340*1080的分辨率,在录屏的时候输出视频,第一录屏要全屏录,也就是宽是2340,第二视频不会裁剪,所以你最后要输出1920*1080,他的宽自然要缩小,高度也就跟着等比缩小,然后上下会有黑边填充。也就是其实视频最后输出的是1920*1080,之所以看起来小了是上下填充了黑边。
所以你要做的就是一个断点一个断点的去看相机支持的分辨率,然后一个一个去算比例,然后发现一些规律,然后换一部手机,然后再执行这一套操作,然后再换一步手机。。。
好在这些我都替你做了。
3.处理
查找camera支持的分辨率中最接近手机实际屏幕比例的值
其实是从手机支持的视频分辨率中找,不过因为也要用摄像头,视频支持的包括摄像头支持且比摄像头支持的多,所以要从摄像头支持的里找。即List<Camera.Size> prviewSizeList = myParameters.getSupportedPreviewSizes();不开摄像头的可以试着从List<Camera.Size> videoSizeList = myParameters.getSupportedVideoSizes();里找。下面是核心代码
public void initCamera() {
getScreenSize();
//注:摄像头相关的设置不写了,省的看混
............
Camera.Parameters myParameters = myCamera.getParameters();
//获取摄像头支持的分辨率
List<Camera.Size> prviewSizeList = myParameters.getSupportedPreviewSizes();
//获取手机支持的视频分辨率
//List<Camera.Size> videoSizeList = myParameters.getSupportedVideoSizes();
//获取最接近的分辨的索引
int selectIndex = bestVideoSize(prviewSizeList);
............
//设置相机预览尺寸
//TODO 在你设置视频大小的地方也是用这里计算出来的值,以为我设置录制视频分辨率的地方不在,
//这,不过也是取得这里的值,所以就不写了
myParameters.setPreviewSize(prviewSizeList.get(selectIndex).width,prviewSizeList.get(selectIndex).height);
}
int mRealSizeWidth;//手机屏幕真实宽度
int mRealSizeHeight;//手机屏幕真实高度
/**
* 查找最接近屏幕宽高比的参数
* @param cameraSizeList
* @return
*/
public int bestVideoSize(List<Camera.Size> cameraSizeList) {
if (cameraSizeList == null) {
return -1;
}
//计算屏幕的实际分辨率的比值
float realRatio = ((float) mRealSizeWidth / (float) mRealSizeHeight);
int index = 0;//目标索引
float outRatio = -1f;
for (int i = 0; i < cameraSizeList.size(); i++) {
if (cameraSizeList.get(i).height <= mRealSizeHeight) {//取的值高度不能高于屏
//幕真实高度
float ratio = (float) (cameraSizeList.get(i).width) / (float) (cameraSizeList.get(i).height);
if (outRatio == -1f) {
outRatio = Math.abs(ratio / realRatio - 1);
index = i;
} else {
if (outRatio > Math.abs(ratio / realRatio - 1)) {
//取绝对值小的值,即选择与屏幕分辨率最接近的值
index = i;
outRatio = Math.abs(ratio / realRatio - 1);
}else if (outRatio == Math.abs(ratio / realRatio - 1)) {
//如果有两组长宽比完全一样的,选择height比较大,小的可能会视频模糊
if (cameraSizeList.get(i).height >= cameraSizeList.get(index).height) {
index = i;
outRatio = Math.abs(ratio / realRatio - 1);
}
}
}
}
}
return index;
}
//计算屏幕真实分辨率
public void getScreenSize() {
WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point outPoint = new Point();
if (Build.VERSION.SDK_INT >= 19) {
// 可能有虚拟按键的情况
display.getRealSize(outPoint);
} else {
// 不可能有虚拟按键
display.getSize(outPoint);
}
mRealSizeHeight = outPoint.y;
mRealSizeWidth = outPoint.x;
}
注意:我录的是横屏,所以我比较的都是高度height,如果是竖屏,最好是用宽度width。
安卓手机的各种各样的分辨率问题不再多说了,没办法把所有的都测一遍,从我手里的一批手机测过后都是达到了比较完美的效果(除非你手机的相机有支持与屏幕比例一模一样的分辨率,否则几乎不会是完全的全屏,最终的效果也会因手机不同有些许差异),如果有不合适的,可以在bestVideoSize()方法里通过限制你要取值的height的高度范围这个方向考虑。