android camera2方向为仿真器相机错误

时间:2018-07-06 02:32:44

标签: java android android-camera2

我正在关注一个教程,并试图设置android camera2。这是它的代码。

MainActivity:

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Camera;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {


private static final int REQUEST_CAMERA_PERMISSION_RESULT = 0;
private Button btnCapture;
private TextureView mTextureView;
private TextureView.SurfaceTextureListener mSurfaceTextListener = new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
        setUpCamera(i,i1);
        connectCamera();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

    }
};
private CameraDevice mCameraDevice;
private  HandlerThread mBackgroundHandlerThread;
private Handler mBackgroundHandler;
private static SparseIntArray ORIENTATIONS = new SparseIntArray();
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);
}
private Size mPreviewSize;
private CaptureRequest.Builder mCaptureRequestBuilder;

private CameraDevice.StateCallback mCameraDeviceStateCallBack = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice cameraDevice) {
        mCameraDevice = cameraDevice;
        startPreview();
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
        cameraDevice.close();
        mCameraDevice = null;
    }

    @Override
    public void onError(@NonNull CameraDevice cameraDevice, int i) {
        cameraDevice.close();
        mCameraDevice = null;
    }
};
private String mCameraId;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mTextureView = findViewById(R.id.textureView);
}




@Override
protected void onResume() {
    super.onResume();

    startBackgroundThread();

    if (mTextureView.isAvailable()) {
        setUpCamera(mTextureView.getWidth(),mTextureView.getHeight());
        connectCamera();
    } else {
        mTextureView.setSurfaceTextureListener(mSurfaceTextListener);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CAMERA_PERMISSION_RESULT) {
        if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(getApplicationContext(),
                    "Application will not run without camera services ",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

private void closeCamera() {
    if (mCameraDevice != null) {
        mCameraDevice.close();
        mCameraDevice = null;
    }
}


private void startBackgroundThread() {
    mBackgroundHandlerThread = new HandlerThread("camera2VideoImage");
    mBackgroundHandlerThread.start();

    mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
}

private void stopBackgroundThread() {
    mBackgroundHandlerThread.quitSafely();
    try {
        mBackgroundHandlerThread.join();
        mBackgroundHandlerThread = null;
        mBackgroundHandler = null;
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics, int deviceOrientation) {
    int sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
    deviceOrientation = ORIENTATIONS.get(deviceOrientation);
    return ((sensorOrientation + deviceOrientation + 360) % 360);

}


private void setUpCamera(int width, int height) {
    CameraManager cameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String cameraId : cameraManager.getCameraIdList()) {
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
                    CameraCharacteristics.LENS_FACING_FRONT) {
                continue;
            }
            StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            int deviceOrientation = getWindowManager().getDefaultDisplay().getRotation();
            int totalRotation = sensorToDeviceRotation(cameraCharacteristics,deviceOrientation);
            boolean swapRotation = totalRotation == 90 || totalRotation == 270;
            int rotatedWidth = width;
            int rotatedHeight = height;
            if (swapRotation) {
                rotatedWidth = height;
                rotatedHeight = width;
            }
            mPreviewSize = chooseOptimaSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth ,
                    rotatedHeight);
            mCameraId = cameraId;
            return;
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private void connectCamera() {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
                    PackageManager.PERMISSION_GRANTED) {
                cameraManager.openCamera(mCameraId, mCameraDeviceStateCallBack, mBackgroundHandler);
            } else {
                if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
                    Toast.makeText(this,
                            "Video app requires access to camera"
                            ,Toast.LENGTH_SHORT).show();
                }
                requestPermissions(new String[] {Manifest.permission.CAMERA},
                        REQUEST_CAMERA_PERMISSION_RESULT);
            }
        } else {
            cameraManager.openCamera(mCameraId, mCameraDeviceStateCallBack, mBackgroundHandler);
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private void startPreview() {
    SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
    surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
    Surface previewSurface = new Surface(surfaceTexture);
    try {
        mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mCaptureRequestBuilder.addTarget(previewSurface);

        mCameraDevice.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                try {
                    cameraCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(),
                            null, mBackgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                Toast.makeText(getApplicationContext(),"unable to setup preview",
                        Toast.LENGTH_SHORT).show();
            }
        } , null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}



private static class CompareSizeByArea implements Comparator<Size> {

    @Override
    public int compare(Size lhs, Size rhs) {
        return Long.signum((long)lhs.getWidth() * lhs.getHeight() /
                (long) rhs.getWidth() * rhs.getHeight());
    }
}

private static Size chooseOptimaSize(Size[] choices, int width, int height) {
    List<Size> bigEnough = new ArrayList<Size>();
    for (Size option : choices) {
        if (option.getHeight() == option.getWidth() * height / width &&
                option.getWidth() >= width && option.getHeight() >= height) {
            bigEnough.add(option);
        }
    }
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizeByArea());
    } else {
        return choices[0];
    }

}


@Override
protected void onPause() {
    closeCamera();
    super.onPause();
    stopBackgroundThread();
    }
}

公共类MainActivity扩展了AppCompatActivity {

private static final int REQUEST_CAMERA_PERMISSION_RESULT = 0;
private Button btnCapture;
private TextureView mTextureView;
private TextureView.SurfaceTextureListener mSurfaceTextListener = new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
        setUpCamera(i,i1);
        connectCamera();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

    }
};
private CameraDevice mCameraDevice;
private  HandlerThread mBackgroundHandlerThread;
private Handler mBackgroundHandler;
private static SparseIntArray ORIENTATIONS = new SparseIntArray();
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);
}
private Size mPreviewSize;
private CaptureRequest.Builder mCaptureRequestBuilder;

private CameraDevice.StateCallback mCameraDeviceStateCallBack = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice cameraDevice) {
        mCameraDevice = cameraDevice;
        startPreview();
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
        cameraDevice.close();
        mCameraDevice = null;
    }

    @Override
    public void onError(@NonNull CameraDevice cameraDevice, int i) {
        cameraDevice.close();
        mCameraDevice = null;
    }
};
private String mCameraId;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mTextureView = findViewById(R.id.textureView);
}




@Override
protected void onResume() {
    super.onResume();

    startBackgroundThread();

    if (mTextureView.isAvailable()) {
        setUpCamera(mTextureView.getWidth(),mTextureView.getHeight());
        connectCamera();
    } else {
        mTextureView.setSurfaceTextureListener(mSurfaceTextListener);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CAMERA_PERMISSION_RESULT) {
        if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(getApplicationContext(),
                    "Application will not run without camera services ",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

private void closeCamera() {
    if (mCameraDevice != null) {
        mCameraDevice.close();
        mCameraDevice = null;
    }
}


private void startBackgroundThread() {
    mBackgroundHandlerThread = new HandlerThread("camera2VideoImage");
    mBackgroundHandlerThread.start();

    mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
}

private void stopBackgroundThread() {
    mBackgroundHandlerThread.quitSafely();
    try {
        mBackgroundHandlerThread.join();
        mBackgroundHandlerThread = null;
        mBackgroundHandler = null;
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics, int deviceOrientation) {
    int sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
    deviceOrientation = ORIENTATIONS.get(deviceOrientation);
    return ((sensorOrientation + deviceOrientation + 360) % 360);

}


private void setUpCamera(int width, int height) {
    CameraManager cameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String cameraId : cameraManager.getCameraIdList()) {
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
                    CameraCharacteristics.LENS_FACING_FRONT) {
                continue;
            }
            StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            int deviceOrientation = getWindowManager().getDefaultDisplay().getRotation();
            int totalRotation = sensorToDeviceRotation(cameraCharacteristics,deviceOrientation);
            boolean swapRotation = totalRotation == 90 || totalRotation == 270;
            int rotatedWidth = width;
            int rotatedHeight = height;
            if (swapRotation) {
                rotatedWidth = height;
                rotatedHeight = width;
            }
            mPreviewSize = chooseOptimaSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth ,
                    rotatedHeight);
            mCameraId = cameraId;
            return;
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private void connectCamera() {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
                    PackageManager.PERMISSION_GRANTED) {
                cameraManager.openCamera(mCameraId, mCameraDeviceStateCallBack, mBackgroundHandler);
            } else {
                if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
                    Toast.makeText(this,
                            "Video app requires access to camera"
                            ,Toast.LENGTH_SHORT).show();
                }
                requestPermissions(new String[] {Manifest.permission.CAMERA},
                        REQUEST_CAMERA_PERMISSION_RESULT);
            }
        } else {
            cameraManager.openCamera(mCameraId, mCameraDeviceStateCallBack, mBackgroundHandler);
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private void startPreview() {
    SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
    surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
    Surface previewSurface = new Surface(surfaceTexture);
    try {
        mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mCaptureRequestBuilder.addTarget(previewSurface);

        mCameraDevice.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                try {
                    cameraCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(),
                            null, mBackgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                Toast.makeText(getApplicationContext(),"unable to setup preview",
                        Toast.LENGTH_SHORT).show();
            }
        } , null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}



private static class CompareSizeByArea implements Comparator<Size> {

    @Override
    public int compare(Size lhs, Size rhs) {
        return Long.signum((long)lhs.getWidth() * lhs.getHeight() /
                (long) rhs.getWidth() * rhs.getHeight());
    }
}

private static Size chooseOptimaSize(Size[] choices, int width, int height) {
    List<Size> bigEnough = new ArrayList<Size>();
    for (Size option : choices) {
        if (option.getHeight() == option.getWidth() * height / width &&
                option.getWidth() >= width && option.getHeight() >= height) {
            bigEnough.add(option);
        }
    }
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizeByArea());
    } else {
        return choices[0];
    }

}


@Override
protected void onPause() {
    closeCamera();
    super.onPause();
    stopBackgroundThread();
}

}

activity_main xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextureView
   android:id="@+id/textureView"
   android:layout_width="match_parent"
   android:layout_above="@+id/buttonCapture"
   android:layout_height="match_parent" />

<Button
    android:layout_width="match_parent"
    android:layout_alignParentBottom="true"
    android:layout_height="wrap_content"
    android:id="@+id/buttonCapture"
    android:text="CAPTURE"/>


</RelativeLayout>

清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidcamera2api">

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.hardware.camera2.full" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".CameraActivity"></activity>
</application>

</manifest>

当前使用的是SDK 27。

我目前没有真正的Android手机要测试,因此我正在使用模拟器。 但是,即使手机处于纵向模式,我启动我的应用程序时,相机也会变成横向。看起来像这样。

enter image description here

我认为处理此问题的代码在setUpCamera方法中,如果方向为90或270,我会交换宽度和高度?感谢帮助!

1 个答案:

答案 0 :(得分:0)

我已经在Google Pixel 2(Android 8.1-与您使用的API相同)上测试了您的代码,并且图片正确显示-头部位于顶部,与您发布的屏幕截图不同

所以我得出结论,这是您正在使用的模拟器中的错误。

我只会对您的AndroidManifest.xml进行此更改:

<activity android:name=".MainActivity"
          android:screenOrientation="portrait">

这样,您将获得与例如三星和谷歌在其旗舰手机上使用其Camera应用程序。 UI布局的方向已锁定(如果将设备旋转到横向,则只有图标图片旋转,而UI布局不会旋转)。