我在屏幕顶部有一个摄像头预览,具有特定的高度和宽度。我正在使用前置摄像头来生成预览。相机正在工作,但问题是预览显示相机看到的底部部分。
我把相机放在脸前,它应该显示整个脸部。
这是我的surfaceview类:
public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e("Sizes", str.width + "/" + str.height);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int weight,
int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
Log.e("Surface changed", "surfaceChanged => w=" + weight + ", h=" + height);
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
// parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(mHolder);
//mediaRecorder.setOrientationHint(90);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (Exception e) {
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
if (mPreviewSize != null) {
float ratio;
if (mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
和xml:
<FrameLayout
android:id="@+id/videoview"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
>
</FrameLayout>
我尝试手动将值设置为parameters.setPreviewSize(300,200),但它只是在预览中显示黑屏。我是android中的相机API的新手,不幸的是我没时间阅读谷歌文档来了解相机api的原理并相应地操纵我的代码。 Anny帮助将不胜感激。
答案 0 :(得分:0)
您可以尝试将setMeasuredDimension参数更改为onMeasure方法。
答案 1 :(得分:0)
您无法对300×200进行硬编码,因为您只能选择一种支持的预览尺寸。但在您的情况下,不同设备的宽度可能会有所不同,宽高比也可能不同。
实际上,选择300×200并不是另一个原因:即使您的预览高度硬编码为200,它也是200dp
,但相机预览适用于真实像素。当预览尺寸不小于屏幕上预览曲面的(实际像素)尺寸时,可以获得最佳效果(无像素化)。
MyCameraSurfaceView 类的代码看起来不错。问题是如何将其插入videoview
框架。您应该将布局参数设置为Gravity.CENTER
。这将使您的预览从顶部和底部均匀裁剪。如果要发送所有像素以进行显示,您可以选择扭曲图像,或保留边距(类似于youtube显示窄视频的方式)。