hardware.Camera及SurfaceView
来源:互联网 发布:腾讯游戏优化 编辑:程序博客网 时间:2024/06/05 22:48
SufaceView
主要有Surface,SurfaceView及SurfaceHolder三个类。Surface对象代表着原始像素数据的缓冲区.SurfaceHolder是与Surface联系的纽带,而SurfaceView内部封装了一个专门用于绘制的Surface对象。(Provides a dedicated drawing surface embedded inside of a view hierarchy)。
Surface对象也是有生命周期的,当SurfaceView出现在屏幕上时会创建Surface,当SurfaceView从屏幕上消失时,Surface会销毁。为了正确把握Surface的生命周期,可以通过SurfaceHolder.Callback接口实现。
SurfaceView是View的特殊子类,用于在视图层级结构中提供一个专门用来绘图的Surface,其目的是将这个绘图Surface提供给另一个线程(非UI线程),这样系统就不必等到视图层级结构做好绘制准备后再进行绘制。相反,另一个线程执有Surface的引用,它可以根据自己的步调向自身的canvas中进行绘制 。
我们向应用程序添加的UI组件或者自定义控件,都会被加入到视图层级结构中,完整的视图树是在UI线程中进行绘制的。而SurfaceView是在自己的线程中进行绘制的,并不会用到UI线程。
SurfaceView与其他View不相同的地方在于,它不会进行自我绘制内容。把想将内容绘制到Surface缓冲区的对象,叫做Surface的客户端。
SurfaceHolder.Callback
Camera
启动系统相机
/** * 打开相机,将图片存储到指定的文件处 */ public static void openCamera(Activity activity, int requestCode, File file) { if (file == null) { return; } Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); if (requestCode != 0) { activity.startActivityForResult(intent, requestCode); } else { activity.startActivity(intent); } }如果将上面的隐匿intent的action设置为MediaStore.ACTION_VIDEO_CAPTURE就会启动录像功能。
//通知系统扫描 MediaScannerConnection.scanFile(this, new String[]{AppUtils.getCaptureImageFile(this).getAbsolutePath()}, null, null); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(captureImageFile)));其中captureImageFile是用来存储拍照的图片,而AppUtils.getCaptureImageFile()返回的是图片所在的文件夹。也就是说该方法只能刷新指定的文件,而不是刷新一个文件夹。
概述
Camera提供了对设备相机硬件级别的调用。相机是一种独占性资源,一次只能有一个activity调用相机,因此使用相机很关键的一点:需要时使用,使用完毕之后立即释放。如果忘记释放,除非重启设备,否则其他应用将无法使用相机。
权限
如果使用相机,需要在清单文件中添加相应的权限及<uses-feature>。<uses-feature>是用来指定应用使用了设备的某项特色功能,它可以保证只有那些具备了该功能的设备才能使用该应用。具体如下:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="true" />
打开与释放
在onResume()和onPause()回调方法中获取和释放相机资源。因为这两个方法是用户可以和视图交互的时间边界,只有用户可以与视图交互时才需要使用相机。获取和释放相机的代码如下:
@Overrideprotected void onResume() {//获取相机资源super.onResume();mCamera = Camera.open();}@Overrideprotected void onPause() {//释放相机资源if (mCamera != null) {mCamera.release();mCamera = null;}super.onPause();}
使用相机时必须进行非空判断,这是必须的。因为即使请求获取相机资源,也有可能获取不到。
判断是否有相机
具体代码如下:
/** * @return true代表有相机,false代表无相机 */private boolean hasCamera() {PackageManager pm = getPackageManager();return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)|| pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)|| Camera.getNumberOfCameras() > 0;}
常用方法
open():打开后置摄像头。一个重载方法open(int),它是在api9中添加的,系统会根据传入的值打开对应的相机。而open()方法默认打开的是后置摄像头。
open()源码:
public static Camera open() { int numberOfCameras = getNumberOfCameras(); CameraInfo cameraInfo = new CameraInfo(); for (int i = 0; i < numberOfCameras; i++) { getCameraInfo(i, cameraInfo); if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {//默认打开后置摄像头 return new Camera(i); } } return null; }
setDisplayOrientation():设置预览方向。默认时预览为横屏的,调用setDisplayOrientation(90)后,才会变成竖屏的。
getParameters():获取相机的参数。
setParameters():这相机设置参数。
autoFocus():自动对焦。参数为自动对焦后的回调。一般使用takePicture()进行拍照之后,都需要调用autoFocus进行对焦,只有对焦成功之后才进行调用takePicture()进行拍照。
setPreviewCallback():设置预览的回调。在该回调中,可以将预览的数据保存。
getCameraInfo(int ,CameraInfo):获取指定摄像头的info,会将info信息放置在第二个参数中。
getNumberOfCameras():获取摄像头的个数。按照open()的方法,可以打开指定的摄像头。
addCallbackBuffer():为预览回调添加预先分配好的缓冲区。
setPreviewCallbackWithBuffer():设置预览回调。与setPreviewCallback()类似,但fps比setPreviewCallback高。要结合addCallbackBuffer一起使用。具体使用可参考github。其关键点在于调用startPreview()之前要调用一次addCallbackBuffer()方法,在PreviewCallback#onPreviewFrame中也要调用一次addCallbackBuffer()。如
parameters = camera.getParameters(); int size = parameters.getPreviewSize().width * parameters.getPreviewSize().height; size = size * ImageFormat.getBitsPerPixel(parameters.getPreviewFormat()) / 8; mBuffer = new byte[size]; camera.setPreviewCallbackWithBuffer(this); camera.addCallbackBuffer(mBuffer); camera.startPreview();
该片段在surfaceChanged()中调用的,因为该片段可以知道Camera的预览大小,从而可以设置正确的缓冲区大小。
@Override public void onPreviewFrame(byte[] data, Camera camera) { iv.setImageBitmap(takePicture(data)); camera.addCallbackBuffer(data); }
每一次预览回调中,对数据处理之比后再调用一次addCallbackBuffer()。
预览
在设置预览之前,调用了SurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS),为了在低版本上运行这一点是必须有的。
在surfaceCreated()中调用setPreviewDisplay(),在surfaceChanged()中调用startPreview(),在surfaceDestroyed()中调用stopPreview()。
获取预览数据
主要通过setPreCallback()中的回调进行。如下:
camera.startPreview(); camera.setPreviewCallback(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { takePicture(data); } });takePicture是将参数转为bitmap的方法,如下:
private void takePicture(byte[] data) { Camera.Size size = camera.getParameters().getPreviewSize(); try { YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); ByteArrayOutputStream stream = new ByteArrayOutputStream(); image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream); Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());//获取预览的bitmap //do sth stream.close(); } catch (Exception ex) { Log.e("Sys", "Error:" + ex.getMessage()); } }该方法主要是利用系统自带的YuvImage类进行。其中第二个参数只能是ImageFormat.NV21或者ImageFormat.YUY2。
获取合适的预览尺寸
代码来源于apidemo
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; // Try to find an size match aspect ratio and size for (Camera.Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - h) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - h); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - h) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - h); } } } return optimalSize; }
拍照
if (mCamera != null) {mCamera.takePicture(new ShutterCallback() {public void onShutter() {System.out.println("咔咔响");}}, null, new PictureCallback() {//将数据存储成JPG格式public void onPictureTaken(byte[] data, Camera camera) {File directory = Environment.getExternalStorageDirectory();File f = new File(directory, "me.jpg");FileOutputStream fo = null;try {fo = new FileOutputStream(f);fo.write(data);} catch (Exception e) {e.printStackTrace();} finally {if (fo != null) {try {fo.close();} catch (IOException e1) {e1.printStackTrace();}}}finish();}});}
Camera.Parameters
常用方法
常见问题
拍摄指定位置的图像
现象
使用Camera进行拍照,在预览图上有边框,拍摄的图片是边框中的部分。
原理
Camera实现拍照,必须使用一个SurfaceView做为屏幕,用来显示预览图片。而边框可以使用另一个Surfaceview,两个SurfaceView采用帧布局。把底部的SurfaceView设置为Camera的预览区域,顶部是用来进行边框显示。
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{private SurfaceHolder holder;public MySurfaceView(Context context, AttributeSet attrs) {super(context, attrs);holder = getHolder();holder.addCallback(this);holder.setFormat(PixelFormat.TRANSPARENT);setZOrderOnTop(true);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}public void draw(){Canvas canvas = holder.lockCanvas();canvas.drawColor(Color.TRANSPARENT);Paint p = new Paint();p.setStrokeWidth(4);p.setColor(Color.RED);p.setStyle(Paint.Style.STROKE);p.setAntiAlias(true);canvas.drawRect(100, 300, 400, 600, p);//在顶部画一个矩形,可以根据surfaceview的位置进行画holder.unlockCanvasAndPost(canvas);}}最后在activity中将拍照获取的图片截取框中的部分即可。
方向
Camera#setDisplayOrientation():设置摄像头预览的方向。
Parameters#setRotate():设置拍照后图片的方向。
PreviewCallback#onPreviewFrame():拿到预览数据,并且处理成bitmap时,bitmap是旋转的。此时只能借助matrix或者canvas对拿到的bitmap进行旋转处理,Camera中没有处理该旋转的方法。
自动对焦
单次自动对焦可以直接调用Camera#autoFocus()。如果是隔一段时间自动对焦一次,可以用一子线程隔一段时间调用一次autoFocus,并且对焦的过程也可以放在子线程中进行。
具体示例可参数zxing中关于Camera部分的AutoFocusManager——在AsyncTask#doInbackground()中睡2s,然后调用autoFocus(),在autoFocus()的回调中又重新调用AsyncTask,形成循环,不断地autoFocus。
- hardware.Camera及SurfaceView
- camera hardware module
- android.hardware.Camera
- camera hardware module
- android.hardware.Camera
- Qualcomm camera hardware overview
- android-android.hardware.Camera
- 通过Camera、SurfaceView、自己实现拍照及预览效果
- androi surfaceview and camera
- Android之SurfaceView、Camera
- 一、Camera2 操作android.hardware.Camera 分析
- 相机硬件功能(Camera hardware features)
- SurfaceView与Camera制作照相机
- SurfaceView与Camera制作照相机
- Android Camera之SurfaceView学习
- SurfaceView预览Camera+GLSurfaceView绘制
- SoundPool、 VedioView、 MediaRecorder、 SurfaceView、 Camera、
- android Camera SurfaceView变形,为什么?
- 数据库设计逻辑主键
- nyoj60谁获得了最高奖学金
- Web Services--gSOAP 2.7.6 第二章(2)
- cocos2d label信息汇集
- Oracle调整顾问(SQL Tuning Advisor 与 SQL Access Advisor )
- hardware.Camera及SurfaceView
- 基本排序算法 - 基本知识点
- EAS WAF1新增单据保存时提示没有数据权限的问题分析。
- char*和CString转换
- char* 和char[]的区别
- myeclipse中关联jar包源代码
- ffmpeg avcodec_encode_video2 前面10多帧不能实时编码
- 备份
- 小经验