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 的问题

Android Camera2预览偶尔会旋转90度

camera2(API 级别 21)是不是暴露了所有旧摄像头?

Android CameraSource 对多个设备的工作方式不同,并且不会旋转图像

Android:Camera2错误参数传递给相机服务

错误:包 android.hardware.camera2 不存在 OpenCV