以编程方式创建布局时在 Camera2 API 中预览拉伸
Preview streched in Camera2 API when creating layout programmaticaly
更新我们的应用程序后,我们现在使用 Camera2 API,不幸的是预览在我们的测试设备上被拉伸:三星 SM-J330F/DS,Android-版本 8.0.0, API26
因为我们在同一台设备上使用 Google 的 Camera2Basic 项目时没有遇到这个问题,所以我们尝试调整我们的项目以使用相同的预览实现。目前我们无法找出两个项目之间 不同预览的确切原因。
这是预期的:
与 Camera2Basic 项目相比,我们的 RelativeLayout
是在 Activity class 中以编程方式创建的,然后将 AutoFitTextureView
添加到此对象:
mMainLayout = new FrameLayout(this);
mMainLayout.setBackgroundColor(Color.BLACK);
mMainLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
mPreview = new AutoFitTextureView(this);
mPreview.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, Gravity.TOP));
mMainLayout.addView(mPreview);
this.setContentView(mMainLayout);
AutoFitTextureView
的实现与Camera2Basic项目中相同。
稍后在 Camera2 class 中将 setUpCameraOutputs()
中的预览设置为 640x480 像素(所有设备都应支持的分辨率)后,我们在 mPreview 上调用 setAspectRatio(width, height)
:
mPreviewSize = new Size(640, 480);
if (mFrameOrientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(
mPreviewSize.getWidth(), mPreviewSize.getHeight()
);
} else {
mTextureView.setAspectRatio(
mPreviewSize.getHeight(), mPreviewSize.getWidth()
);
}
注意:同样在较新的设备(如 Honor 10)上,预览看起来不错。
我认为问题是您固定了 mPreviewSize
的值。由于这个原因,相机预览会在某些分辨率大于 640*480 的设备中拉伸。
mPreviewSize
应与 AutoFitTextureView
.
大小相同
mPreviewSize = new Size(mPreview.getHeight(), mPreview.getWidth());
这个问题的解决方案是在 openCamera()
和 onSurfaceTextureSizeChanged()
中调用以下函数:
/**
* Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
* This method should be called after the camera preview size is determined in
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
*
* @param viewWidth The width of `mTextureView`
* @param viewHeight The height of `mTextureView`
*/
private void configureTransform(int viewWidth, int viewHeight) {
Activity activity = getActivity();
if (null == mTextureView || null == mPreviewSize || null == activity) {
return;
}
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
mTextureView.setTransform(matrix);
}
更新我们的应用程序后,我们现在使用 Camera2 API,不幸的是预览在我们的测试设备上被拉伸:三星 SM-J330F/DS,Android-版本 8.0.0, API26
因为我们在同一台设备上使用 Google 的 Camera2Basic 项目时没有遇到这个问题,所以我们尝试调整我们的项目以使用相同的预览实现。目前我们无法找出两个项目之间 不同预览的确切原因。
这是预期的:
与 Camera2Basic 项目相比,我们的 RelativeLayout
是在 Activity class 中以编程方式创建的,然后将 AutoFitTextureView
添加到此对象:
mMainLayout = new FrameLayout(this);
mMainLayout.setBackgroundColor(Color.BLACK);
mMainLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
mPreview = new AutoFitTextureView(this);
mPreview.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, Gravity.TOP));
mMainLayout.addView(mPreview);
this.setContentView(mMainLayout);
AutoFitTextureView
的实现与Camera2Basic项目中相同。
稍后在 Camera2 class 中将 setUpCameraOutputs()
中的预览设置为 640x480 像素(所有设备都应支持的分辨率)后,我们在 mPreview 上调用 setAspectRatio(width, height)
:
mPreviewSize = new Size(640, 480);
if (mFrameOrientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(
mPreviewSize.getWidth(), mPreviewSize.getHeight()
);
} else {
mTextureView.setAspectRatio(
mPreviewSize.getHeight(), mPreviewSize.getWidth()
);
}
注意:同样在较新的设备(如 Honor 10)上,预览看起来不错。
我认为问题是您固定了 mPreviewSize
的值。由于这个原因,相机预览会在某些分辨率大于 640*480 的设备中拉伸。
mPreviewSize
应与 AutoFitTextureView
.
mPreviewSize = new Size(mPreview.getHeight(), mPreview.getWidth());
这个问题的解决方案是在 openCamera()
和 onSurfaceTextureSizeChanged()
中调用以下函数:
/**
* Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
* This method should be called after the camera preview size is determined in
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
*
* @param viewWidth The width of `mTextureView`
* @param viewHeight The height of `mTextureView`
*/
private void configureTransform(int viewWidth, int viewHeight) {
Activity activity = getActivity();
if (null == mTextureView || null == mPreviewSize || null == activity) {
return;
}
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
mTextureView.setTransform(matrix);
}