Android预览Camera数据
使用Camera
注意:导入的包是android.hardware.Camera,不是android.graphics.Camera类,前者是硬件相关的相机Api,后者是2D图片转换3D图片使用的。这里要预览相机,要使用hardward硬件包下的。
清单文件需要声明使用Camera权限
<uses-permission android:name="android.permission.CAMERA" />
在6.0及以上版本需要动态申请相机权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
} else {
// 初始化Camera
}
// 使用Camera.open获取Camera实例,Camera.CameraInfo.CAMERA_FACING_FRONT为前置相机,Camera.CameraInfo.CAMERA_FACING_BACK为后置相机
Camera mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
Camera.Parameters parameters = mCamera.getParameters();
//Android 中Google支持的 Camera Preview Callback的YUV常用格式有两种:一个是NV21,一个是YV12。Android一般默认使用YCbCr_420_SP的格式(NV21)
parameters.setPreviewFormat(ImageFormat.NV21);
// parameters.setPreviewSize(1280, 720);
// 方向旋转90度
mCamera.setDisplayOrientation(90);
// 设置预览数据回调
mCamera.setPreviewCallback(this);
使用SurfaceView预览
布局文件中添加surfaceView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
public class MainActivity extends AppCompatActivity implements Camera.PreviewCallback {
private Camera mCamera;
private SurfaceView mSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = findViewById(R.id.surface_view);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
} else {
// 初始化Camera
initCamera();
}
mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
if(mCamera==null)return;
try {
mCamera.setPreviewDisplay(holder); //设置预览Holder
mCamera.startPreview(); //开始预览
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
if (mCamera != null) {
mCamera.stopPreview(); //停止预览
mCamera.release(); //释放资源
}
}
});
}
private void initCamera() {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
// parameters.setPreviewSize(1280, 720);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewCallback(this);
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initCamera();
} else {
Toast.makeText(this, "拒绝相机权限,无法预览", Toast.LENGTH_SHORT).show();
}
}
}
}
使用TextureView预览
布局文件换成TextureView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextureView
android:id="@+id/texture_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
public class MainActivity extends AppCompatActivity implements Camera.PreviewCallback {
private Camera mCamera;
private TextureView mTextureView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextureView = findViewById(R.id.texture_view);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
} else {
// 初始化Camera
initCamera();
}
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
if (mCamera == null) return;
try {
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
return false;
}
@Override
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
}
});
}
private void initCamera() {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
// parameters.setPreviewSize(1280, 720);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewCallback(this);
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initCamera();
} else {
Toast.makeText(this, "拒绝相机权限,无法预览", Toast.LENGTH_SHORT).show();
}
}
}
}
总结
SurfaceView和TextureView都可以实现Camera预览图像,调用api差异不大,使用SurfaceView预览要使用 mCamera.setPreviewDisplay(holder),使用TextureView预览要使用 mCamera.setPreviewTexture(surface),具体在使用中应该使用哪个,结合需求使用,SurfaceView适合游戏这种高渲染的情境,TextureView适合相机预览的情境。具体可以百度下两者间的差异。