在前置摄像头上拉伸的摄像头预览
Camera Preview Stretched on Front Facing Camera
你好,我正在开发一个 android 自定义相机应用程序,但在以下设备的前置摄像头上遇到相机预览拉伸的问题:
- 华为荣耀4c(仅前置摄像头)
- HTC One M7(仅限前置摄像头)
- 一些其他设备也...因为我只有以下设备要测试,所以其他设备也可能存在问题。
问题是相机预览在后置相机上运行得很好,但只有当我将我的应用程序与前置相机一起使用时它才会拉伸!
代码
这是我用于相机预览的代码Class:
import android.content.Context;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
//Variables de' Preview
private SurfaceHolder mHolder;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
private int FOCUS_AREA_SIZE=300;
public static Camera previewCamera;
////////////////////////
//protected LOGGER keys
protected final String EXCEPTION_KEY="xception";
//////////////////////////
public CameraPreview(Context context, Camera camera) {
super(context);
//get the camera
previewCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = previewCamera.getParameters().getSupportedPreviewSizes();
// 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);
mHolder.setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try{
//when the surface is created, we can set the camera to draw images in this surfaceholder
previewCamera.setPreviewDisplay(surfaceHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceCreated: "+exp.toString());
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
//before changing the application orientation, you need to stop the preview, rotate and then start it again
if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try{
previewCamera.stopPreview();
} catch (Exception e){
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try{
//set the camera preview on every preview change
setPreview();
previewCamera.setPreviewDisplay(mHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceChanged: "+exp.toString());
}
}
public void setPreview(){
try{
//set the focusable true
this.setFocusable(true);
//set the touch able true
this.setFocusableInTouchMode(true);
//set the camera display orientation lock
previewCamera.setDisplayOrientation(90);
//get the camera parameters
Camera.Parameters parameters = previewCamera.getParameters();
//set the preview size
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
//set the parameter
previewCamera.setParameters(parameters);
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM setPreview: "+exp.toString());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//our app has only one screen, so we'll destroy the camera in the surface
//if you are using with more screens, please move this code your activity
try{
//handle in Activity onResume and onPause
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceDestroyed: "+exp.toString());
}
}
//Override Methods here
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try{
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = PreviewSizeParameters.getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM onMeasure: "+exp.toString());
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void stopPreviewAndFreeCamera() {
if (previewCamera != null) {
// Call stopPreview() to stop updating the preview surface.
previewCamera.stopPreview();
// Important: Call release() to release the camera for use by other
// applications. Applications should release the camera immediately
// during onPause() and re-open() it during onResume()).
previewCamera.release();
previewCamera = null;
}
}
//end of class here
}
有人能告诉我我的代码中遗漏了什么吗,因为它只影响某些使用 前置摄像头 的设备。
谢谢
以下代码在我的环境中有效。
在 surfaceChanged
中用 SurfaceView
和高度调用 getOptimalPreviewSize
。
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
...
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int w, int h) {
//before changing the application orientation, you need to stop the preview, rotate and then start it again
if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try{
previewCamera.stopPreview();
} catch (Exception e){
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try{
//set the focusable true
this.setFocusable(true);
//set the touch able true
this.setFocusableInTouchMode(true);
//set the camera display orientation lock
previewCamera.setDisplayOrientation(90);
Camera.Parameters params = previewCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size optimalSize = getOptimalPreviewSize(sizes,w,h);
params.setPreviewSize(optimalSize.width,optimalSize.height);
previewCamera.setParameters(params);
previewCamera.setPreviewDisplay(mHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceChanged: "+exp.toString());
}
}
...
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.width / size.height;
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;
}
//end of class here
}
你好,我正在开发一个 android 自定义相机应用程序,但在以下设备的前置摄像头上遇到相机预览拉伸的问题:
- 华为荣耀4c(仅前置摄像头)
- HTC One M7(仅限前置摄像头)
- 一些其他设备也...因为我只有以下设备要测试,所以其他设备也可能存在问题。
问题是相机预览在后置相机上运行得很好,但只有当我将我的应用程序与前置相机一起使用时它才会拉伸!
代码
这是我用于相机预览的代码Class:
import android.content.Context;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
//Variables de' Preview
private SurfaceHolder mHolder;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
private int FOCUS_AREA_SIZE=300;
public static Camera previewCamera;
////////////////////////
//protected LOGGER keys
protected final String EXCEPTION_KEY="xception";
//////////////////////////
public CameraPreview(Context context, Camera camera) {
super(context);
//get the camera
previewCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = previewCamera.getParameters().getSupportedPreviewSizes();
// 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);
mHolder.setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try{
//when the surface is created, we can set the camera to draw images in this surfaceholder
previewCamera.setPreviewDisplay(surfaceHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceCreated: "+exp.toString());
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
//before changing the application orientation, you need to stop the preview, rotate and then start it again
if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try{
previewCamera.stopPreview();
} catch (Exception e){
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try{
//set the camera preview on every preview change
setPreview();
previewCamera.setPreviewDisplay(mHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceChanged: "+exp.toString());
}
}
public void setPreview(){
try{
//set the focusable true
this.setFocusable(true);
//set the touch able true
this.setFocusableInTouchMode(true);
//set the camera display orientation lock
previewCamera.setDisplayOrientation(90);
//get the camera parameters
Camera.Parameters parameters = previewCamera.getParameters();
//set the preview size
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
//set the parameter
previewCamera.setParameters(parameters);
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM setPreview: "+exp.toString());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//our app has only one screen, so we'll destroy the camera in the surface
//if you are using with more screens, please move this code your activity
try{
//handle in Activity onResume and onPause
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceDestroyed: "+exp.toString());
}
}
//Override Methods here
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try{
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = PreviewSizeParameters.getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM onMeasure: "+exp.toString());
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void stopPreviewAndFreeCamera() {
if (previewCamera != null) {
// Call stopPreview() to stop updating the preview surface.
previewCamera.stopPreview();
// Important: Call release() to release the camera for use by other
// applications. Applications should release the camera immediately
// during onPause() and re-open() it during onResume()).
previewCamera.release();
previewCamera = null;
}
}
//end of class here
}
有人能告诉我我的代码中遗漏了什么吗,因为它只影响某些使用 前置摄像头 的设备。
谢谢
以下代码在我的环境中有效。
在 surfaceChanged
中用 SurfaceView
和高度调用 getOptimalPreviewSize
。
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
...
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int w, int h) {
//before changing the application orientation, you need to stop the preview, rotate and then start it again
if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try{
previewCamera.stopPreview();
} catch (Exception e){
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try{
//set the focusable true
this.setFocusable(true);
//set the touch able true
this.setFocusableInTouchMode(true);
//set the camera display orientation lock
previewCamera.setDisplayOrientation(90);
Camera.Parameters params = previewCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size optimalSize = getOptimalPreviewSize(sizes,w,h);
params.setPreviewSize(optimalSize.width,optimalSize.height);
previewCamera.setParameters(params);
previewCamera.setPreviewDisplay(mHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceChanged: "+exp.toString());
}
}
...
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.width / size.height;
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;
}
//end of class here
}