自定义Camera录制指定尺寸视频时预览画面变形问题求助
解决自定义Camera预览画面拉伸变形问题
这个问题我之前做相机应用时也碰到过,核心原因是预览控件(SurfaceView/TextureView)的显示比例没有和相机预览尺寸的比例保持一致。你已经选对了相机支持的视频/预览尺寸,但如果Surface的宽高比和这个尺寸的比例不匹配,系统就会强制拉伸画面适配,最终导致变形。下面是具体的解决方案:
1. 确保选中的相机尺寸比例正确
首先优化你获取支持视频尺寸的逻辑,优先匹配4:3比例(640×480是标准4:3)的尺寸,而不是只看宽度:
Camera.Size useMe = null; int targetWidth = 640; int targetHeight = 480; float targetRatio = (float) targetWidth / targetHeight; int minSizeDiff = Integer.MAX_VALUE; Camera.Parameters parameters = mCamera.getParameters(); List<Camera.Size> supportedSizes = parameters.getSupportedVideoSizes(); // 如果设备不单独返回视频尺寸,用预览尺寸替代 if (supportedSizes == null) { supportedSizes = parameters.getSupportedPreviewSizes(); } // 优先找比例匹配、尺寸最接近640×480的选项 for (Camera.Size size : supportedSizes) { float currentRatio = (float) size.width / size.height; // 允许0.01的比例误差,避免设备比例精度问题 if (Math.abs(currentRatio - targetRatio) < 0.01) { int diff = Math.abs(size.width - targetWidth) + Math.abs(size.height - targetHeight); if (diff < minSizeDiff) { minSizeDiff = diff; useMe = size; } } } // 找不到比例匹配的,再用原逻辑降级处理 if (useMe == null) { for (int i = 0; i < supportedSizes.size(); i++) { Camera.Size size = supportedSizes.get(i); if (size.width == targetWidth) { useMe = size; break; } if (size.width < targetWidth) { useMe = supportedSizes.get(Math.max(0, i - 1)); break; } } if (useMe == null) { useMe = supportedSizes.get(supportedSizes.size() / 2); } }
2. 让预览控件保持和相机尺寸一致的比例
在surfaceChanged方法中,不要直接给Surface设置固定尺寸,而是根据相机预览尺寸的比例,动态调整Surface的宽高,确保比例完全匹配:
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (mCamera == null || useMe == null) return; Camera.Parameters parameters = mCamera.getParameters(); float previewRatio = (float) useMe.width / useMe.height; ViewGroup parentContainer = (ViewGroup) mPreview.getParent(); int parentWidth = parentContainer.getWidth(); int parentHeight = parentContainer.getHeight(); // 计算符合比例的Surface尺寸 int targetSurfaceWidth, targetSurfaceHeight; if ((float) parentWidth / parentHeight > previewRatio) { // 容器宽度比预览比例宽,以容器高度为基准计算宽度 targetSurfaceHeight = parentHeight; targetSurfaceWidth = Math.round(targetSurfaceHeight * previewRatio); } else { // 容器高度比预览比例高,以容器宽度为基准计算高度 targetSurfaceWidth = parentWidth; targetSurfaceHeight = Math.round(targetSurfaceWidth / previewRatio); } // 设置SurfaceView的布局参数,强制保持比例 ViewGroup.LayoutParams layoutParams = mPreview.getLayoutParams(); layoutParams.width = targetSurfaceWidth; layoutParams.height = targetSurfaceHeight; mPreview.setLayoutParams(layoutParams); // 重新配置相机预览尺寸并启动预览 parameters.setPreviewSize(useMe.width, useMe.height); mCamera.setParameters(parameters); mCamera.startPreview(); }
3. 修正MediaRecorder的配置冲突
你同时调用了setProfile和setVideoSize,部分设备会因为CamcorderProfile的参数覆盖自定义尺寸,建议调整为:
// 先获取Profile,再修改视频尺寸 CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); profile.videoFrameWidth = useMe.width; profile.videoFrameHeight = useMe.height; mMediaRecorder.setProfile(profile); // 这里无需再调用setVideoSize,Profile已包含正确尺寸
总结
只要保证预览控件的宽高比和相机预览/视频录制尺寸的宽高比完全一致,就能解决拉伸变形的问题。上面的步骤从尺寸选择、控件布局到录制配置都做了优化,应该能解决你的问题。
内容的提问来源于stack exchange,提问作者Zee
相关产品推荐
相关产品推荐

