问题描述
我正在为我的AR View应用程序使用自定义相机。在全屏人像模式下,“相机”预览正变得捉襟见肘。
我已经尝试了许多关于stackoverflow的解决方案,但是它不适用于我的代码。 谁能告诉我如何解决这个问题?
我在下面的预览被拉伸的地方添加了我的相机工作代码和屏幕截图。
这是我的自定义相机类别:
public class ARCamera extends ViewGroup implements SurfaceHolder.Callback {
private final static float Z_NEAR = 0.5f;
private final static float Z_FAR = 2000;
private final String TAG = ARCamera.class.getSimpleName();
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Camera camera;
Activity activity;
float[] projectionMatrix = new float[16];
int cameraWidth;
int cameraHeight;
int screenWidth,screenHeight;
int rotation;
public ARCamera(Context context,SurfaceView surfaceView) {
super(context);
this.surfaceView = surfaceView;
this.activity = (Activity) context;
surfaceHolder = this.surfaceView.getHolder();
surfaceHolder.addCallback(this);
displayMetrics displayMetrics = new displayMetrics();
WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultdisplay().getMetrics(displayMetrics);
rotation = windowManager.getDefaultdisplay()
.getRotation();
this.screenWidth = displayMetrics.widthPixels;
this.screenHeight = displayMetrics.heightPixels;
}
public void setCamera(Camera camera) {
this.camera = camera;
}
@Override
protected void onLayout(boolean changed,int left,int top,int right,int bottom) {
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (camera != null) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK,info);
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
camera.setdisplayOrientation((info.orientation - degrees + 360) % 360);
camera.setPreviewdisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG,"IOException caused by setPreviewdisplay()",exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
}
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height) {
if (camera != null) {
this.cameraWidth = width;
this.cameraHeight = height;
Camera.Parameters parameters = camera.getParameters();
try {
List<Camera.Size> supportedSizes = camera.getParameters().getSupportedPreviewSizes();
for (Camera.Size element : supportedSizes) {
element.width -= cameraWidth;
element.height -= cameraHeight;
}
Collections.sort(supportedSizes,new Resolutionorders());
parameters.setPreviewSize(width + supportedSizes.get(supportedSizes.size() - 1).width,height + supportedSizes.get(supportedSizes.size() - 1).height);
} catch (Exception ex) {
parameters.setPreviewSize(screenWidth,screenHeight);
}
this.camera.setParameters(parameters);
this.camera.startPreview();
generateProjectionMatrix();
}
}
private void generateProjectionMatrix() {
float ratio = (float) this.screenWidth / this.screenHeight;
final int OFFSET = 0;
final float LEFT = -ratio;
final float RIGHT = ratio;
final float BottOM = -1;
final float TOP = 1;
Matrix.frustumM(projectionMatrix,OFFSET,LEFT,RIGHT,BottOM,TOP,Z_NEAR,Z_FAR);
}
public float[] getProjectionMatrix() {
return projectionMatrix;
}
class Resolutionorders implements java.util.Comparator<Camera.Size> {
public int compare(Camera.Size left,Camera.Size right) {
return Float.compare(left.width + left.height,right.width + right.height);
}
}
}
解决方法
在表面已更改的块中,您必须以编程方式根据设备选择最佳尺寸。
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
这将为您提供支持的照相机总数。您必须从中选择合适的尺寸。我使用了名为“ chooseOptimalSize”的功能。
Size aspectRatio = new Size(matrix.widthPixels,matrix.heightPixels);
Camera.Size previewSize = chooseOptimalSize(previewSizes,PREFERRED_PREVIEW_WIDTH,PREFERRED_PREVIEW_HEIGHT,aspectRatio,this);
这是函数“ chooseOptimalSize”:-
public static Camera.Size chooseOptimalSize(List<Camera.Size> choices,int width,int height,Size aspectRatio,Context c) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
double ratio = (double) h / w;
int loopCounter=0;
for (Camera.Size size : choices) {
int orientation = c.getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=720) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=3840 ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=5120 ) {//Retina 5K
if((size.width/16) == (size.height/9) && size.width <=7680 ) {//8K UHDTV Super Hi-Vision
Log.e(TAG,"chooseOptimalSize:"+size+"--LoopPosition---==>"+loopCounter);
return size;
}
} else {
Log.e(TAG,"chooseOptimalSize:--given--"+size);
if((size.width/16) == (size.height/9) && ((size.width <=1280)||(size.height<=1920))) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4320 ) ) {//8K UHDTV Super Hi-Vision
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2880 ) ) {//Retina 5K
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2160 ) ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=1280 ) ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4480 && size.getWidth() >=1280) ) {
Log.e(TAG,"chooseOptimalSize:"+size+"-16:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/18) == (size.height/9) && ((size.width <=3840)||(size.height<=2160))) {
Log.e(TAG,"chooseOptimalSize:"+size+"-18:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/18.5) == (size.height/9) && ((size.width <=3840)||(size.height<=2160))) {
Log.e(TAG,"chooseOptimalSize:"+size+"-18.5:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((width/19) == (height/9) && ((width <=3840)||(height<=2160))) {
/*if((size.getWidth()/19) == (size.getHeight()/9) && ((size.getWidth() <=3840)||(size.getHeight()<=2160))) {*/
Log.e(TAG,"chooseOptimalSize:"+size+"-19:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/19.5) == (size.height/9) && ((size.width<=3840)||(size.height<=2160))) {
Log.e(TAG,"chooseOptimalSize:"+size+"-19.5:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else{
Log.e(TAG,"chooseOptimalSize"+" not proper aspect resolution");
}
//2340
}
// if(screenWidth==size.getWidth()){
// Log.e(TAG1,loopCounter+".choose:width Matched:"+screenWidth+"="+size.getWidth());
// }else{
// Log.e(TAG1,loopCounter+".choose:width Not Matched:"+screenWidth+"="+size.getWidth());
// }
//
// if(screenHeight==size.getHeight()){
// Log.e(TAG1,loopCounter+".choose:height Matched:"+screenHeight+"="+size.getHeight());
// }else{
// Log.e(TAG1,loopCounter+".choose:height Not Matched:"+screenHeight+"="+size.getHeight());
// }
loopCounter++;
}
// 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.get(0);
// }
}
/*
* Compares two {@code Size}s based on their areas.
*/
static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs,Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
如果我不想使用该代码,则可以取消注释该代码。
此功能将为您提供设备相机的最佳尺寸。您可以使用:
进行设置parameters.setPreviewSize(previewSize.width,previewSize.height);
您完成了!!!