一、前言
在android 5.0 之后 官方已经不推荐Camear这个类了,而是推荐 android.hardware.camera2 包下的api.但我们还是有必要学习一下。
Camera这个类可以被用来照相、start/top相机预览、将图像帧编码成video。它对于相机服务相当于一个客户端,它管理者真正的硬件Camera。
要访问硬件Camera我们必须在AndroidManifest.xml中声明相机权限。还必须确保AndroidManifest.xml 包含相机功能的声明( < uses- feature >)。比如如果想使用相机的 auto-focus,就必须在AndroidManifest.xml中声明:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
使用这个类照相可以分为以下几步:
1、使用 Camera的 opent(int).创建一个实例
2、通过getParameters(). 获得默认的参数
3、如果必要的话,通过setParameters(Camera.Parameters). 修改参数
4、使用 setDisplayOrientation(int)改正当前预览的方向
5、初始化一个SurfaceHolder,并通过 setPreviewDisplay(SurfaceHolder). 设置,如果没有设置将不能开始预览
6、 调用startPreview()开始预览,拍照前必须开始预览
7、调用 takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback) 等待image 数据
8、拍完照之后,如果还想继续拍照重新调用 startPreview()
9、调用 stopPreview()停止预览
10、调用 release() 释放。应用程序应该在 onPause()时立即调用该方法,在onResume重新打开。
使用这个类录像分为以下几步:
1、和上文描述的一样 创建一个实例,之后开启预览
2、调用unlock() 去允许media process 访问camera
3、通过MediaRecord的 setCamera(Camear camera)
4、当结束录制之后,调用reconnect() 去请求,并re-lock Camera
5、如果希望继续拍照或者录像,重新调用 startPreviews()
6、调用stopPreview() 和 release()结束
下面是一个简单的拍照示例:
public class CameraActivity extends BaseActivity {
private static final String TAG = "CameraActivity";
@BindView(R.id.btn_take_picture)
Button btnTakePicture;
@BindView(R.id.btn_start_record)
Button btnStartRecord;
@BindView(R.id.surfaceView)
SurfaceView surfaceView;
private SurfaceHolder holder;
private Camera mCamera;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_camera);
ButterKnife.bind(this);
initView();
}
private void initCamera() {
/**
* Step 1.
* 获得一个Camera实例,(默认获得为后置摄像头)
*/
if(mCamera==null){
mCamera = Camera.open();
}
/**
* Step 2.
* 获得默认的参数
*/
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG);
/**
* Stop 3.
* 设置参数
*/
mCamera.setParameters(parameters);
/**
* Step 4.
* 修正当前的方向
*/
setCameraDisplayOrientation(this, Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
/**
* Step 5.
* 设置 SurfaceHolder
*/
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
/**
* Step 6.
* 开始预览
*/
mCamera.startPreview();
}
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().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;
}
camera.setDisplayOrientation(result);
}
private void initView() {
holder = surfaceView.getHolder();
holder.addCallback(callback);
holder.setKeepScreenOn(true);
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
initCamera();
}
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause: ");
/**
* Step 9. 停止预览
*/
mCamera.stopPreview();
/**
* Step 10. 释放
*/
mCamera.release();
mCamera = null;
}
@OnClick({R.id.btn_take_picture, R.id.btn_start_record})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_take_picture:
/**
* Step 7.
* 拍照
*/
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (data != null) {
/**
* Step 8. 重新开始预览
*/
mCamera.startPreview();
writeImage2Sdcard(data);
}
}
});
break;
case R.id.btn_start_record:
break;
}
}
private void writeImage2Sdcard(final byte[] data) {
new Thread() {
@Override
public void run() {
FileOutputStream out = null;
try {
out = new FileOutputStream(new File("sdcard/test",
System.currentTimeMillis() + ".jpg"));
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
initCamera();
Log.i(TAG, "surfaceCreated: ");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged: ");
setCameraDisplayOrientation(CameraActivity.this,
Camera.CameraInfo.CAMERA_FACING_BACK,mCamera);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed: ");
}
};
如果需要录制视频的话加入以下代码:
if (!started) {
started = true;
btnStartRecord.setText("结束录像");
mediaRecorder = new MediaRecorder();
/**
* 录像 Step A.
*/
mCamera.unlock();
/**
* 录像 Step B.
*/
mediaRecorder.setCamera(mCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mediaRecorder.setOutputFile(Environment.getExternalStorageDirectory()+
File.separator+System.currentTimeMillis()+".3gp");
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaRecorder.start();
//
} else {
started = false;
btnStartRecord.setText("开始录像");
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
/**
* 录像 Step C.
*/
try {
mCamera.reconnect();
} catch (IOException e) {
e.printStackTrace();
}
mCamera.lock();
/**
* 录像 Step D.
*/
mCamera.startPreview();
}
最后完整代码如下:
public class CameraActivity extends BaseActivity {
private static final String TAG = "CameraActivity";
@BindView(R.id.btn_take_picture)
Button btnTakePicture;
@BindView(R.id.btn_start_record)
Button btnStartRecord;
@BindView(R.id.surfaceView)
SurfaceView surfaceView;
private SurfaceHolder holder;
private Camera mCamera;
private MediaRecorder mediaRecorder;
private boolean started;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_camera);
ButterKnife.bind(this);
initView();
}
private void initCamera() {
/**
* Step 1.
* 获得一个Camera实例,(默认获得为后置摄像头)
*/
if (mCamera == null) {
mCamera = Camera.open();
}
/**
* Step 2.
* 获得默认的参数
*/
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG);
/**
* Stop 3.
* 设置参数
*/
mCamera.setParameters(parameters);
/**
* Step 4.
* 修正当前的方向
*/
setCameraDisplayOrientation(this, Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
/**
* Step 5.
* 设置 SurfaceHolder
*/
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
/**
* Step 6.
* 开始预览
*/
mCamera.startPreview();
}
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().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;
}
camera.setDisplayOrientation(result);
}
private void initView() {
holder = surfaceView.getHolder();
holder.addCallback(callback);
holder.setKeepScreenOn(true);
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
initCamera();
}
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause: ");
/**
* Step 9. 停止预览
*/
mCamera.stopPreview();
/**
* Step 10. 释放
*/
mCamera.release();
mCamera = null;
}
@OnClick({R.id.btn_take_picture, R.id.btn_start_record})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_take_picture:
/**
* Step 7.
* 拍照
*/
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (data != null) {
/**
* Step 8. 重新开始预览
*/
mCamera.startPreview();
writeImage2Sdcard(data);
}
}
});
break;
case R.id.btn_start_record:
if (!started) {
started = true;
btnStartRecord.setText("结束录像");
mediaRecorder = new MediaRecorder();
/**
* 录像 Step A.
*/
mCamera.unlock();
/**
* 录像 Step B.
*/
mediaRecorder.setCamera(mCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mediaRecorder.setOutputFile(Environment.getExternalStorageDirectory()+
File.separator+System.currentTimeMillis()+".3gp");
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaRecorder.start();
//
} else {
started = false;
btnStartRecord.setText("开始录像");
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
/**
* 录像 Step C.
*/
try {
mCamera.reconnect();
} catch (IOException e) {
e.printStackTrace();
}
mCamera.lock();
/**
* 录像 Step D.
*/
mCamera.startPreview();
}
break;
}
}
private void writeImage2Sdcard(final byte[] data) {
new Thread() {
@Override
public void run() {
FileOutputStream out = null;
try {
out = new FileOutputStream(new File("sdcard/test",
System.currentTimeMillis() + ".jpg"));
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
initCamera();
Log.i(TAG, "surfaceCreated: ");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged: ");
setCameraDisplayOrientation(CameraActivity.this,
Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed: ");
}
};
}
权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-feature android:name="android.hardware.camera"></uses-feature>
<uses-feature android:name="android.hardware.camera.autofocus"></uses-feature>
<uses-permission android:name="android.permission.RECORD_AUDIO" />