前言
摄像头是移动设备的重要工具。随着移动端技术的发展,摄像头作为移动设备的图像采集工具,也变得越来越重要。不论是AR特效,计算机视觉技术,都离不开摄像头稳定高效地工作。
由于摄像头可调参数极多,又涉及硬件厂商的各种兼容性。在Android中,这并不是一个简单的工作。本文只记录一种快速使用,能够简单的预览画面,录制视频。
快速开始
MainActivity.java
public class MainActivity extends AppCompatActivity {
SurfaceView mSurfaceView;
Camera camera;
boolean isPreview;
Button mBtnRecord;
SurfaceHolder mSurfaceHolder;
boolean isRecording = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = findViewById(R.id.sv_test);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
mSurfaceHolder.addCallback(mSurfaceCallback);
mBtnRecord = findViewById(R.id.btn_start_record);
mBtnRecord.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isRecording){
RecordManager.getInstance().record(camera , mSurfaceHolder.getSurface());
}else {
RecordManager.getInstance().stop();
camera.lock();
}
isRecording = !isRecording;
}
});
}
private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
/**
*
* @param surfaceHolder 持有当前 Surface 的 SurfaceHolder 对象
*/
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
Camera.CameraInfo info = new Camera.CameraInfo();
int cameraPosition = -1;
for(int cameraIndex = 0; cameraIndex<Camera.getNumberOfCameras(); cameraIndex++){
Camera.getCameraInfo(cameraIndex, info);
if(info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
cameraPosition = cameraIndex;
}
}
camera = Camera.open(cameraPosition);
//设置角度
setCameraDisplayOrientation(MainActivity.this, cameraPosition, camera);
camera.setPreviewDisplay(surfaceHolder);//通过SurfaceView显示取景画面
camera.startPreview();//开始预览
isPreview = true;//设置是否预览参数为真
} catch (IOException e) {
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**
* 在 Surface 被销毁时立即调用:失去焦点时。一般在这里将画图的线程停止销毁
*
* @param surfaceHolder 持有当前 Surface 的 SurfaceHolder 对象
*/
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if (camera != null) {
if (isPreview) {//正在预览
camera.stopPreview();
camera.release();
}
}
}
};
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
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);
}
}
RecordManager.java
public class RecordManager {
private MediaRecorder recorder;
private volatile static RecordManager instance;
private RecordManager(){
}
public static RecordManager getInstance(){
if (instance == null){
synchronized (RecordManager.class){
instance = new RecordManager();
}
}
return instance;
}
public void record(Camera camera , Surface surface){
recorder = new MediaRecorder();
recorder.setCamera(camera);
recorder.setPreviewDisplay(surface);
recorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
@Override
public void onError(MediaRecorder mr, int what, int extra) {
Log.d("tag" , "MediaRecorder error what = "+ what +" , extra = " +extra);
}
});
//设置视频源
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//设置音频源
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
//设置文件输出格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//设置视频编码方式
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
//设置音频编码方式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
recorder.setOrientationHint(270);
// 保存到文件中(路径)
File saveFile = null;
try {
saveFile = new File(Environment.getExternalStorageDirectory()
.getCanonicalFile()
+ "/zzzzzzz"
+ System.currentTimeMillis()
+ ".mp4");
recorder.setOutputFile(saveFile.getAbsolutePath());
camera.unlock();
recorder.prepare();
recorder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop(){
recorder.stop();
recorder.release();
recorder = null;
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.HARDWARE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
细节点
部分细节点,本文没有做细致的讨论,因为这会让基本实现变得复杂。只在此列出,引起注意。
- 在Android6.0及以上,需要动态申请权限。在权限获得同意后,才能初始化相机相关组件,否则会直接报错
- 相机中有很多参数可以设置,如闪光灯,录制码率,预览尺寸等。但所有的参数设置,都需要先获取硬件的支持情况。如果硬件不支持,则可能报错。
- Camera.open()在大部分手机上,可以在子线程中启动,减少主线程的卡帧情况。但在部分机型如魅族上,只能在主线程启动。相机相关的组件,需要非常注意机型适配的问题。
以上就是Android Camera组件的快速使用。如有间题,欢迎指正。
网友评论