Android Camera2 旋转错误
Posted
技术标签:
【中文标题】Android Camera2 旋转错误【英文标题】:Android Camera2 Wrong Rotation 【发布时间】:2015-12-26 09:20:12 【问题描述】:我正在尝试实现 android.hardware.camera2,但我对此有点困惑。
相机随着手机旋转。
在拍照之前,如果我旋转手机,相机会旋转而不是保持相同的位置。
示例图片here。
我不知道为什么会这样。我没有用于持有人的两种布局。
相机 XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fab="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
tools:context=".Camera" >
<TextureView
android:id="@+id/texture"
android:layout_
android:layout_
android:layout_alignParentTop="true" />
<com.getbase.floatingactionbutton.FloatingActionButton
android:id="@+id/btn_takepicture"
android:layout_
android:layout_
fab:fab_icon="@drawable/ic_fab_foto"
fab:fab_colorNormal="#FFFF56B9"
fab:fab_colorPressed="#FFD5379B"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="16dp" />
<com.getbase.floatingactionbutton.FloatingActionButton
android:id="@+id/btn_switchcam"
android:layout_
android:layout_
fab:fab_icon="@drawable/ic_fab_switch"
fab:fab_colorNormal="#267300"
fab:fab_colorPressed="#1e5b00"
fab:fab_size="mini"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_marginTop="16dp"
android:layout_marginRight="16dp" />
</RelativeLayout>
相机活动:
public class AppCamera extends AppCompatActivity
private Size mPreviewSize;
private TextureView mTextureView;
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewBuilder;
private CameraCaptureSession mPreviewSession;
private static int cam = 0;
private FloatingActionButton mBtnShot;
private FloatingActionButton mBtnSwitch;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.camera);
mTextureView = (TextureView)findViewById(R.id.texture);
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
mBtnShot = (FloatingActionButton)findViewById(R.id.btn_takepicture);
mBtnSwitch = (FloatingActionButton)findViewById(R.id.btn_switchcam);
mBtnShot.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
takePicture();
);
mBtnSwitch.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
if (cam == 0)
cam = 1;
else
cam = 0;
if (null != mCameraDevice)
mCameraDevice.close();
mCameraDevice = null;
openCamera();
);
protected void takePicture()
if(null == mCameraDevice)
return;
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null)
jpegSizes = characteristics
.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(ImageFormat.JPEG);
int width = 640;
int height = 480;
if (jpegSizes != null && 0 < jpegSizes.length)
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH);
// Orientation
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
final File file = new File(Environment.getExternalStorageDirectory()+"/DCIM", "teste.jpg");
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener()
@Override
public void onImageAvailable(ImageReader reader)
Image image = null;
try
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
catch (FileNotFoundException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
finally
if (image != null)
image.close();
private void save(byte[] bytes) throws IOException
OutputStream output = null;
try
output = new FileOutputStream(file);
output.write(bytes);
finally
if (null != output)
output.close();
;
HandlerThread thread = new HandlerThread("CameraPicture");
thread.start();
final Handler backgroudHandler = new Handler(thread.getLooper());
reader.setOnImageAvailableListener(readerListener, backgroudHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback()
@Override
public void onCaptureCompleted(CameraCaptureSession session,
CaptureRequest request, TotalCaptureResult result)
super.onCaptureCompleted(session, request, result);
Toast.makeText(AppCamera.this, "Saved:"+file, Toast.LENGTH_SHORT).show();
startPreview();
;
mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback()
@Override
public void onConfigured(CameraCaptureSession session)
try
session.capture(captureBuilder.build(), captureListener, backgroudHandler);
catch (CameraAccessException e)
e.printStackTrace();
@Override
public void onConfigureFailed(CameraCaptureSession session)
, backgroudHandler);
catch (CameraAccessException e)
e.printStackTrace();
@Override
protected void onResume()
super.onResume();
private void openCamera()
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
String cameraId = manager.getCameraIdList()[cam];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];
manager.openCamera(cameraId, mStateCallback, null);
catch (CameraAccessException e)
e.printStackTrace();
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener()
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
openCamera();
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface,
int width, int height)
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface)
return false;
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface)
//Log.e(TAG, "onSurfaceTextureUpdated");
;
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback()
@Override
public void onOpened(CameraDevice camera)
mCameraDevice = camera;
startPreview();
@Override
public void onDisconnected(CameraDevice camera)
@Override
public void onError(CameraDevice camera, int error)
;
@Override
protected void onPause()
super.onPause();
if (null != mCameraDevice)
mCameraDevice.close();
mCameraDevice = null;
protected void startPreview()
if(null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize)
return;
SurfaceTexture texture = mTextureView.getSurfaceTexture();
if(null == texture)
return;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface surface = new Surface(texture);
try
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
catch (CameraAccessException e)
e.printStackTrace();
mPreviewBuilder.addTarget(surface);
try
mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback()
@Override
public void onConfigured(CameraCaptureSession session)
mPreviewSession = session;
updatePreview();
@Override
public void onConfigureFailed(CameraCaptureSession session)
Toast.makeText(AppCamera.this, "onConfigureFailed", Toast.LENGTH_LONG).show();
, null);
catch (CameraAccessException e)
e.printStackTrace();
protected void updatePreview()
if(null == mCameraDevice)
mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
HandlerThread thread = new HandlerThread("CameraPreview");
thread.start();
Handler backgroundHandler = new Handler(thread.getLooper());
try
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
【问题讨论】:
你解决了这个问题吗?有什么解决办法吗? 不,只是删除了项目并继续xD @ShylendraMadda 你解决了这个问题吗?如果有,请告诉我我正在尽力而为,但我无法解决。提前致谢 不,我没有找到它@AmareshJana 【参考方案1】:替换
static
ORIENTATIONS.append(Surface.ROTATION_0, 0);
ORIENTATIONS.append(Surface.ROTATION_90, 90);
ORIENTATIONS.append(Surface.ROTATION_180, 180);
ORIENTATIONS.append(Surface.ROTATION_270, 270);
【讨论】:
要测试一下,我会告诉你的! 不起作用。上面的代码是用于在打印后旋转图片,我在拍摄图片之前遇到了问题。【参考方案2】:如果“onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height)”被触发,调用如下方法:
/**
* Configures the necessary @link android.graphics.Matrix transformation to `mTextureView`.
* This method should be called after the camera preview size is determined in
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
*
* @param viewWidth The width of `mTextureView`
* @param viewHeight The height of `mTextureView`
*/
private void configureTransform(int viewWidth, int viewHeight)
Activity activity = getActivity();
if (null == mTextureView || null == mPreviewSize || null == activity)
return;
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation)
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
else if (Surface.ROTATION_180 == rotation)
matrix.postRotate(180, centerX, centerY);
mTextureView.setTransform(matrix);
有关详细信息,请查看以下文件: https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
【讨论】:
mPreviewSize
可能是什么?
@ShylendraMadda 我刚刚使用了来自 java.util 的 Size
我也用过android.util.Size
好的,谢谢你的更新..我昨天也用过同样的..;P以上是关于Android Camera2 旋转错误的主要内容,如果未能解决你的问题,请参考以下文章
支持 Android Camera Api 和 Camera2 Api 的问题
camera2(API 级别 21)是不是暴露了所有旧摄像头?