Android摄像头surfaceview方向
好了,所以我有一个延伸SurfaceView和覆盖Android摄像头surfaceview方向
surfaceChanged一类 - 只是调用startPreview
surfaceCreated - 打开相机,编辑PARAMS *,设置surfaceHolder
surfaceDestroyed - 电话stopPreview,释放相机
这一切工作的伟大,因为当方向为纵向:
从surfaceCreated *
m_camera = Camera.open();
Camera.Parameters p = m_camera.getParameters();
if (getResources().getConfiguration().orientation !=
Configuration.ORIENTATION_LANDSCAPE)
{
p.set("orientation", "portrait");
// CameraApi is a wrapper to check for backwards compatibility
if (CameraApi.isSetRotationSupported())
{
CameraApi.setRotation(p, 90);
}
}
但是,每次方向改变时,它都会调用Camera.open()...您可能知道这是一项相当昂贵的操作,导致转换不太流畅。
当我强迫风景的方向,预览是伟大的。创建只获取调用一次,这是因为预览在横向上,相机总是用户看到的。但是,我需要一种方法来设置纵向拍摄时拍摄的实际照片的方向。当我强迫风景时,表面永远不会被重新创建,并且相机被竖直放置时从未设置参数。
那么我怎样才能做到以下(完全)之一?如果当持有的方向变化,使过渡是平滑
部队景观和检测方向变化的另一种方式......旋转最终snaped图片
守住m_camera的onDestroy和之间的onCreate在肖像。
另外,如果我关闭基地有人能指点我一个更好的方向?谢谢。
我实现它的方式:
private Camera mCamera;
private OrientationEventListener mOrientationEventListener;
private int mOrientation = -1;
private static final int ORIENTATION_PORTRAIT_NORMAL = 1;
private static final int ORIENTATION_PORTRAIT_INVERTED = 2;
private static final int ORIENTATION_LANDSCAPE_NORMAL = 3;
private static final int ORIENTATION_LANDSCAPE_INVERTED = 4;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// force Landscape layout
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR | ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
/*
Your other initialization code here
*/
}
@Override
protected void onResume() {
super.onResume();
if (mOrientationEventListener == null) {
mOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
@Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
}
else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
}
else { // orientation <135 && orientation > 45
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
if (lastOrientation != mOrientation) {
changeRotation(mOrientation, lastOrientation);
}
}
};
}
if (mOrientationEventListener.canDetectOrientation()) {
mOrientationEventListener.enable();
}
}
@Override protected void onPause() {
super.onPause();
mOrientationEventListener.disable();
}
/**
* Performs required action to accommodate new orientation
* @param orientation
* @param lastOrientation
*/
private void changeRotation(int orientation, int lastOrientation) {
switch (orientation) {
case ORIENTATION_PORTRAIT_NORMAL:
mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 270));
mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 270));
Log.v("CameraActivity", "Orientation = 90");
break;
case ORIENTATION_LANDSCAPE_NORMAL:
mSnapButton.setImageResource(android.R.drawable.ic_menu_camera);
mBackButton.setImageResource(android.R.drawable.ic_menu_revert);
Log.v("CameraActivity", "Orientation = 0");
break;
case ORIENTATION_PORTRAIT_INVERTED:
mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 90));
mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 90));
Log.v("CameraActivity", "Orientation = 270");
break;
case ORIENTATION_LANDSCAPE_INVERTED:
mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 180));
mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 180));
Log.v("CameraActivity", "Orientation = 180");
break;
}
}
/**
* Rotates given Drawable
* @param drawableId Drawable Id to rotate
* @param degrees Rotate drawable by Degrees
* @return Rotated Drawable
*/
private Drawable getRotatedImage(int drawableId, int degrees) {
Bitmap original = BitmapFactory.decodeResource(getResources(), drawableId);
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
Bitmap rotated = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
return new BitmapDrawable(rotated);
}
,然后在PictureCallback集元数据以指示旋转级别:
private Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
// Populate image metadata
ContentValues image = new ContentValues();
// additional picture metadata
image.put(Media.DISPLAY_NAME, [picture name]);
image.put(Media.MIME_TYPE, "image/jpg");
image.put(Media.TITLE, [picture title]);
image.put(Media.DESCRIPTION, [picture description]);
image.put(Media.DATE_ADDED, [some time]);
image.put(Media.DATE_TAKEN, [some time]);
image.put(Media.DATE_MODIFIED, [some time]);
// do not rotate image, just put rotation info in
switch (mOrientation) {
case ORIENTATION_PORTRAIT_NORMAL:
image.put(Media.ORIENTATION, 90);
break;
case ORIENTATION_LANDSCAPE_NORMAL:
image.put(Media.ORIENTATION, 0);
break;
case ORIENTATION_PORTRAIT_INVERTED:
image.put(Media.ORIENTATION, 270);
break;
case ORIENTATION_LANDSCAPE_INVERTED:
image.put(Media.ORIENTATION, 180);
break;
}
// store the picture
Uri uri = getContentResolver().insert(
Media.EXTERNAL_CONTENT_URI, image);
try {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
OutputStream out = getContentResolver().openOutputStream(
uri);
boolean success = bitmap.compress(
Bitmap.CompressFormat.JPEG, 75, out);
out.close();
if (!success) {
finish(); // image output failed without any error,
// silently finish
}
} catch (Exception e) {
e.printStackTrace();
// handle exceptions
}
mResultIntent = new Intent();
mResultIntent.setData(uri);
} catch (Exception e) {
e.printStackTrace();
}
finish();
}
};
我希望它能帮助。
UPDATE现在,当基于横向的设备出现时,在OrientationEventListener中需要额外的检查。
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if (display.getOrientation() == Surface.ROTATION_0) {
// landscape oriented devices
} else {
// portrait oriented device
}
的完整代码(由LC有点浪费,但很容易证明的方法)
@Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if (display.getOrientation() == Surface.ROTATION_0) { // landscape oriented devices
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
} else { // portrait oriented devices
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
}
if (lastOrientation != mOrientation) {
changeRotation(mOrientation, lastOrientation);
}
}
我最终使用了默认的相机活动,但是这看起来不错,我可能会在另一次回来,谢谢 – 2011-03-03 19:38:10
欢迎。诚实的,我实现了我自己的相机活动,因为与不同的android手机上的默认相机活动的所有不一致,并且我不适合做各种各样的黑客来绕过他们。 – Audrius 2011-03-04 09:52:10
@Audrius我创建了带按钮的简单自定义相机但我需要在设备的4侧旋转摄像头...如何做到这一点? – 2014-02-27 05:58:18
你有没有考虑过使用的API文档多数民众赞成提供的标准方法,您可以在surfaceChanged打电话?您可以将度数存储在全局变量中,以便稍后在保存图片时使用。也可以对你的相机变量做一个简单的空检查器,所以你不要在surfaceCreated中再次创建它。
public void setCameraDisplayOrientation()
{
if (mCamera == null)
{
Log.d(TAG,"setCameraDisplayOrientation - camera null");
return;
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(CAM_ID, info);
WindowManager winManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
int rotation = winManager.getDefaultDisplay().getRotation();
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;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
{
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
mCamera.setDisplayOrientation(result);
}
如果你进入实现它,请注意,CAM_ID是一个全局变量,我在别处设置。 – OriginalCliche 2012-06-06 23:26:20
上面的代码不适用于我.. **在Samsung S2 **上进行测试 – swiftBoy 2013-10-04 05:56:56
我们在哪里必须调用setCameraDisplayOrientation()in surfaceCreaeted/surfaceChanged或onResume – Nepster 2015-04-27 13:57:59
正如你从其他答案中看到的,这段代码变得非常复杂。您可能需要使用一个库,帮助您提供此功能,例如调查,CWAC,相机支持OS 2.3及以上(希望你可以删除OS 2.1和OS 2.2支持现在):
https://github.com/commonsguy/cwac-camera
CWAC,相机支持将相机预览锁定到横向,并将自动将图像转换为您的校正方向。浏览project issues如果您想要了解所有需要解决的设备特定问题,哪些IMO更愿意尝试使用库而不是维护所有代码并进行测试。
+1我也对此感兴趣。默认谷歌相机应用程序执行此美丽:它不重新创建活动,但按钮和最后图像预览很好地旋转以匹配风景/人像方向。顺便说一句,在我的理解中,_p.set(“orientation”,“portrait”)_是一个隐藏的API用法,并没有官方支持,不是吗? – Audrius 2011-03-01 18:27:04
我不认为它实际上做了什么,哈哈。我喜欢的方法是强制风景。问题是我需要以某种方式检测方向另一种方式,因为然后cameraActivity不会被重新创建。 – 2011-03-01 19:31:49
啊,我明白你的想法。所以你会强制相机活动到一个风景,然后根据*真实*方向,只需旋转一张图片,对吧? [This](http://android-er.blogspot.com/2010/08/orientationeventlistener-detect.html)可以帮助你。这不是一个坏主意,我可能会自己去实现它( - 。 – Audrius 2011-03-02 13:33:47