AndroidCamera详解
概述
Android提供了俩种使⽤相机的⽅式
⼀种是直接通过Intent调⽤系统相机组件,这种⽅法快速⽅便,适⽤于直接获取照⽚的场景
另⼀种是使⽤相机Api来⾃定义相机,这种⽅法⽤于需要定制相机界⾯或开发相机特殊功能的场景
相机中的关键API
Camera开发主要⽤到了来个类
Camera类:最主要的类⽤于管理和操作camera资源,它提供了完整的相机底层接⼝
SurfaceView 或TextureView:负责把Camera的数据显⽰在屏幕上
Camera类的API解释
getNumberOfCameras获取设备的相机数量,⼀般有俩个 前置相机和后置相机open(CameraId)获取Camera实例,传⼊参数1 是获取前置摄像头, 0 为后置摄像头
getParameters获取相机的参数,包括闪光灯模式,对焦模式,预览和拍照尺⼨
setParameters把⾃⼰设置好的相机参数,设置给相机
setPreviewDisplay(SurfaceHolder)绑定预览图像的SurfaceView,当相机和surfaceView绑定后,相机预览的图像会通过
surfaceView显⽰在屏幕上
setPreviewTexture(SurfaceTexture)绑定预览图像的TextureView,当相机和TextureView绑定后,相机预览的图像会通过
TextureView显⽰在屏幕上
setPreviewCallback获取相机的预览数据setDisplayOrientation设置预览画⾯,顺时针旋转的⾓度startPreview开始预览
stopPreview停⽌预览release释放相机
takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback
jpeg)
这个是实现相机拍照的主要⽅法,包含了三个回调参数。shutter是快门按下时的回调,raw是获取拍照原始数据的回调,jpeg是获取经过压缩成jpg格式的图像数据的回调。
getCameraInfo(int cameraId, CameraInfo cameraInfo)获取指定id的相机信息startFaceDetection开始⼈脸检测
stopFaceDetection停⽌⼈脸检测setFaceDetectionListener设置⼈脸监听回调
我们继续看⼀下Camera类的内部类Parameters
上⾯我们说到⼀个getParameters⽅法,这个⽅法的返回值就是Parameters类
Camera.Parameters类的Api解释
getSupportedPreviewSizes获取相机⽀持预览图⽚⼤⼩
setPreviewSize(640, 480);设置预览图⽚带下,这⾥就是设置预览图⽚为640*480
getSupportedPreviewFormats获得相机⽀持的图⽚预览格式,所有的相机都⽀持ImageFormat.NV21
更多的图⽚格式可以⾃⾏百度或是查看Camera.Parameters类的Api解释
ImageFormat类
setPreviewFormat(int
设置预览图⽚的格式
pixel_format)
getSupportedPictureSizes获取相机⽀持采集的图⽚⼤⼩(就是拍摄照⽚的带下)
setPictureSize(int width, int
设置拍摄照⽚的⼤⼩
height)
getSupportedPictureFormats获取相机⽀持的图⽚格式
setPictureFormat设置拍摄图⽚的格式
getSupportedFocusModes获取相机⽀持的对焦模式
setFocusMode设置相机对焦模式
getMaxNumDetectedFaces返回当前相机所⽀持的最⼤的⼈脸检测个数
SurfaceView
⽤于绘制相机预览图像,提供给⽤户实时的预览图像,普通的View以及派⽣类都是共享⼀个Surface的,所有的绘制都需要在UI线程中,⽽SurfaceView是⼀种⽐较特殊的View,他不与其他普通View共享Surface,⽽是在他内部有⼀个独⽴的Surface,SurfaceView只负责管理这个Surface的格式尺⼨以及显⽰位置,由于Ui线程还需要处理其他Ui交互,并不能保证View的更新速度和帧率,⽽SurfaceView有⼀个独⽴的Surface,因此可以在独⽴线程中绘制,因此可以提⾼更⾼的帧率
SurfaceView的优缺点
优点:
可以在⼀个独⽴的线程绘制,不会影响主线程
使⽤双缓冲机制,播放视频更流畅
双缓冲机制:SurfaceView更新视图时⽤到了俩个Canvas,⼀个frontCanvas⼀个backCavans,每次实际显⽰的就是
frontCanvas,backCavans储存的是上⼀次跟改前的视图,当lockCanvas()获取画布时,实际得到的是backCavans,⽽不是正在显⽰的frontCanvas,之后你在backCavans绘制视图,再unlockCanvasAndPost(canvas)这个视图,那么上传的canvas会替代frontCanvas,⽽原来的frontCanvas将切换到后台作为backCavans
缺点:
SurfaceView它的显⽰也不受View的属性控制,所以不能进⾏平移,缩放等变换,但是在7.0以后SurfaceView可以进⾏平移,缩放等
SurfaceHolder:SurfaceHolder是控制Surface的⼀个抽象接⼝,它能够控制Surface的尺⼨格式,修改surface的像素,监听surface 的变化等,Surface的典型⽤例就是⽤于SurfaceView中,通过getHolder获取SurfaceHolder,来监听Surface的状态
SurfaceHolder.Callback接⼝:负责监听Surface状态变化的接⼝,有三个⽅法
surfaceCreated(SurfaceHolder holder):当Surface被创建后⽴即被调⽤,在这⾥可以进⾏打开相机资
源的操作
surfaceChanged():当Surface的size发⽣变化时调⽤
surfaceDestroyed(SurfaceHolder holder):当Surface被销毁时调⽤,可以在这⾥清相机资源
TextureView
TextureView继承⾃View,他将内容流直接投影到View中,和SurfaceView不同的是,他是⼀个普通的View,他可以平移,缩放等,他必须运⾏在硬件加速的窗⼝中
优点
他可以向普通的View⼀样进⾏平移缩放,截图
缺点
他必须运⾏在硬件加速的窗⼝,内存占⽤⽐SurfaceView⾼,5.0之前是在主线程渲染,5.0之后有单独的渲染线程
那么怎么选择这俩个控件
在7.0系统上SurfaceView⽐TextureView更有优势,可以使⽤动画,并且不会有⿊边,如果在7.0以下有动画效果那么就需要⽤到TextureView
从安全和性能上考虑应该使⽤SurfaceView
⾃定义相机预览开发步骤
添加权限
在 l 中添加相机权限
<uses-permission android:name="android.permission.CAMERA" />
把SurfaceView写⼊XML
<SurfaceView
android:id="@+id/surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"/>
监听Surface状态
surfaceView =findViewById(R.id.surface);
private SurfaceHolder.Callback surfaceCallback =new SurfaceHolder.Callback(){
@Override
public void surfaceCreated(SurfaceHolder holder){
//在这⾥打开相机
}
@Override
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
}
@Override
public void surfaceDestroyed(SurfaceHolder holder){
//在这⾥回收相机资源
}
};
查看摄像头数量
int cameras = NumberOfCameras();
这个⽅法返回相机的数量,在有前后摄像头的⼿机,会返回数量2
打开摄像头
mCamera = Camera.open(0);
传⼊参数CameraId,通常0为后置摄像头,1为前置摄像头
设置旋转⾓度和参数简述android概述
mCamera.setDisplayOrientation(90);
Camera.Parameters parameters = Parameters();
parameters.setPreviewFormat(ImageFormat.NV21);
//预览⼤⼩设置
parameters.setPreviewSize(640,480);
mCamera.setParameters(parameters);
设置预览画⾯,顺时针旋转⾓度,和设置预览画⾯的⼤⼩,可以设置的参数有很多参考上⽅的API 开始预览
mCamera.Holder());
mCamera.startPreview();
拿到预览数据
mCamera.setPreviewCallback(new Camera.PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera camera){//这⾥的data就是每⼀帧的数据
}
});
完整的代码
private void initView(){
surfaceView =findViewById(R.id.surface);
}
private SurfaceHolder.Callback surfaceCallback =new SurfaceHolder.Callback(){
@Override
public void surfaceCreated(SurfaceHolder holder){
start();
}
@Override
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){ }
@Override
public void surfaceDestroyed(SurfaceHolder holder){
}
};
public void start(){
if(mCamera == null){
mCamera = Camera.open(0);
}
//因为横屏
mCamera.setDisplayOrientation(90);
try{
Camera.Parameters parameters = Parameters();
parameters.setPreviewFormat(ImageFormat.NV21);
//预览⼤⼩设置
parameters.setPreviewSize(640,480);
mCamera.setParameters(parameters);
mCamera.Holder());
mCamera.setPreviewCallback(new Camera.PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera camera){
}
});
mCamera.startPreview();
}catch(Exception e){
e.printStackTrace();
}
}
//摄像头数据的回调
@Override
public void onPreviewFrame(byte[] data, Camera camera){
}
开发相机所遇到的坑
相机的预览⽅向问题
我们先了解⼀下基本概念

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。