相机预览人像设置参数失败
Posted
技术标签:
【中文标题】相机预览人像设置参数失败【英文标题】:camera preview portrait setParameters failed 【发布时间】:2013-06-18 11:45:51 【问题描述】:我想获得全屏肖像相机预览。使用 Google 的示例,预览在纵向屏幕上以横向格式显示。当我将预览设置为 480 x 864(工作横向尺寸的倒数)时,我收到 setParameters failed 错误。
我已经阅读了我能找到的所有 ***,但我不明白为什么横向支持的尺寸在纵向上会失败。我也找不到强制全屏纵向预览的方法。手机上的相机应用程序提供全屏肖像预览,所以我知道这不是硬件限制。
我正在使用运行 android 2.3.3 的 Droid 3 进行测试
如果有任何建议,我将不胜感激。
public class SimplePreview extends ViewGroup implements SurfaceHolder.Callback
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
int cameraId;
Activity activity;
public SimplePreview(Activity context, int defaultCamera)
super(context);
activity = context;
cameraId = defaultCamera;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
public void setCamera(Camera camera)
mCamera = camera;
if (mCamera != null)
mSupportedPreviewSizes = mCamera.getParameters()
.getSupportedPreviewSizes();
requestLayout();
public void switchCamera(Camera camera)
setCamera(camera);
try
camera.setPreviewDisplay(mHolder);
catch (IOException exception)
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
Log.i(TAG, "setting View measured dimensions to width: " + width
+ " height: " + height);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null)
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width,
height);
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
if (changed && getChildCount() > 0)
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null)
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth)
final int scaledChildWidth = previewWidth * height
/ previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
else
final int scaledChildHeight = previewHeight * width
/ previewWidth;
child.layout(0, (height - scaledChildHeight) / 2, width,
(height + scaledChildHeight) / 2);
public void surfaceDestroyed(SurfaceHolder holder)
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null)
mCamera.stopPreview();
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h)
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes)
Log.v(TAG, " width: " + size.width + " height: " + size.height);
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);
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null)
minDiff = Double.MAX_VALUE;
for (Size size : sizes)
if (Math.abs(size.height - targetHeight) < minDiff)
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
Log.i(TAG, "optimal preview width: " + optimalSize.width + " height: "
+ optimalSize.height);
return optimalSize;
public void surfaceCreated(SurfaceHolder holder)
// The Surface has been created, acquire the camera and tell it where
// to draw.
try
if (mCamera != null)
final int width = getWidth();
final int height = getHeight();
Log.i(TAG, "view width: " + width + " height: " + height);
if (height > width)
Log.i(TAG, "in portrait mode so rotate camera preview");
// THis line fixed the camera display orientation. seems to
// have to be called before setPreviewDisplay()
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(holder);
catch (IOException exception)
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
/**
* orientation and rotation work done here. Now that the size is known, set
* up the camera parameters and begin the preview.
*/
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
if (mCamera != null)
mCamera.stopPreview();
Camera.Parameters parameters = mCamera.getParameters();
// mCamera.setDisplayOrientation(90);
final int width = getWidth();
final int height = getHeight();
Log.i(TAG, "view width: " + width + " height: " + height);
if (height > width)
Log.i(TAG, "portrait: setting preview width: " + 480
+ " height: " + 864);
parameters.setPreviewSize(480, 864);
// had no effect
parameters.set("orientation", "portrait");
else
Log.i(TAG, "landscape: setting preview width: "
+ mPreviewSize.width + " height: "
+ mPreviewSize.height);
parameters.setPreviewSize(mPreviewSize.width,
mPreviewSize.height);
requestLayout();
// *** following line throws setParameters failed error ***
mCamera.setParameters(parameters);
mCamera.startPreview();
以及来自 Activity 的 onCreate() 的调用:
preview = new SimplePreview(this, defaultCameraId);
setContentView(preview);
【问题讨论】:
【参考方案1】:试试这个代码:
package com.example.dragme;
import java.io.IOException;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
private SurfaceHolder mHolder;
public Camera mCamera;
private static boolean DEBUGGING = true;
private static final String LOG_TAG = "CameraPreviewSample";
private static final String CAMERA_PARAM_ORIENTATION = "orientation";
private static final String CAMERA_PARAM_LANDSCAPE = "landscape";
private static final String CAMERA_PARAM_PORTRAIT = "portrait";
protected Activity mActivity;
protected List<Camera.Size> mPreviewSizeList;
protected List<Camera.Size> mPictureSizeList;
protected Camera.Size mPreviewSize;
protected Camera.Size mPictureSize;
public CameraPreview(Context context, Camera camera)
super(context);
mActivity=(Activity)context;
mCamera = camera;
// 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);
public void surfaceCreated(SurfaceHolder holder)
// The Surface has been created, now tell the camera where to draw the preview.
try
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
catch (IOException e)
Log.d("CameraView", "Error setting camera preview: " + e.getMessage());
public void surfaceDestroyed(SurfaceHolder holder)
// empty. Take care of releasing the Camera preview in your activity.
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
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
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
configureCameraParameters(cameraParams, portrait);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
catch (Exception e)
Log.d("CameraView", "Error starting camera preview: " + e.getMessage());
public void onPause()
if (null == mCamera)
return;
mCamera.stopPreview();
mCamera.release();
mCamera = null;
protected void configureCameraParameters(Camera.Parameters cameraParams, boolean portrait)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) // for 2.1 and before
if (portrait)
cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
else
cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
else // for 2.2 and later
int angle;
Display display = mActivity.getWindowManager().getDefaultDisplay();
switch (display.getRotation())
case Surface.ROTATION_0: // This is display orientation
angle = 90; // This is camera orientation
break;
case Surface.ROTATION_90:
angle = 0;
break;
case Surface.ROTATION_180:
angle = 270;
break;
case Surface.ROTATION_270:
angle = 180;
break;
default:
angle = 90;
break;
Log.v(LOG_TAG, "angle: " + angle);
mCamera.setDisplayOrientation(angle);
cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
if (DEBUGGING)
Log.v(LOG_TAG, "Preview Actual Size - w: " + mPreviewSize.width + ", h: " + mPreviewSize.height);
Log.v(LOG_TAG, "Picture Actual Size - w: " + mPictureSize.width + ", h: " + mPictureSize.height);
mCamera.setParameters(cameraParams);
public boolean isPortrait()
return (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
【讨论】:
谢谢。此预览创建了全屏肖像。然而,这一行 您要纵向查看吗? mCamera.setDisplayOrientation(角度);引发错误,导致显示屏逆时针旋转 90 度。我通过将以下代码添加到 surfaceCreated() final int width = getWidth(); 来解决这个问题最终 int 高度 = getHeight();如果(高度 > 宽度) mCamera.setDisplayOrientation(90); mCamera.setPreviewDisplay(holder); mCamera.startPreview(); 启动相机预览时出错:设置显示方向失败 您使用的是哪个设备和安卓版本?以上是关于相机预览人像设置参数失败的主要内容,如果未能解决你的问题,请参考以下文章