Android开发 之 Camera2之拍照
来源:互联网 发布:php redis 列表 编辑:程序博客网 时间:2024/06/05 17:23
Camera2之拍照
Android框架包括支持各种相机和相机的特性 设备,允许您捕获照片和视频在您的应用程序。 本文讨论了 快速、简单的图像和视频捕获方法,并概述了一个先进的方法来创建 为用户自定义相机的经验。
1.在清单文件中声明
权限
<uses-permission android:name="android.permission.CAMERA" />
如果保存照片,录视频还要添加两个权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
相机功能:相机的特性,例如
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />还有很多如下:
android.hardware.camera应用使用设备的后置相机。只有前置相机的设备不会列出该功能,因此如果您的应用可与任何朝向的相机通信,请改用 android.hardware.camera.any 功能。android.hardware.camera.any应用使用设备的其中一个相机或用户为设备连接的外置相机。 如果您的应用不要求相机必须是后置式,请使用此值来替代 android.hardware.camera。android.hardware.camera.autofocus应用使用设备相机支持的自动对焦功能。应用通过使用该功能暗示其还使用 android.hardware.camera 功能,除非这个父功能在声明时使用了 android:required="false"。android.hardware.camera.capability.manual_post_processing应用使用设备相机支持的 MANUAL_POST_PROCESSING 功能。您的应用可以通过该功能替换相机的自动白平衡功能。 使用 android.colorCorrection.transform、android.colorCorrection.gains 以及 TRANSFORM_MATRIX 的 android.colorCorrection.mode。android.hardware.camera.capability.manual_sensor应用使用设备相机支持的 MANUAL_SENSOR 功能。该功能隐含对自动曝光锁定 (android.control.aeLock) 的支持,该支持可以让相机的曝光时间和灵敏度一直固定在特定值。android.hardware.camera.capability.raw应用使用设备相机支持的 RAW 功能。该功能暗示设备可以保存 DNG(原始)文件,并且设备的相机提供您的应用直接处理这些原始图像所需的 DNG 相关元数据。android.hardware.camera.external应用与用户为设备连接的外置相机通信。 但该功能不能保证外置相机可供您的应用使用。android.hardware.camera.flash应用使用设备相机支持的闪光功能。应用通过使用该功能暗示其还使用 android.hardware.camera 功能,除非这个父功能在声明时使用了 android:required="false"。android.hardware.camera.front应用使用设备的前置相机。应用通过使用该功能暗示其还使用 android.hardware.camera 功能,除非这个父功能在声明时使用了 android:required="false"。android.hardware.camera.level.full应用使用设备的至少一个相机提供的 FULL 级图像捕捉支持。 提供 FULL 支持的相机可提供快速捕捉功能、逐帧控制和手动后期处理控制。
1.本文是利用textureview预览视图数据的。在xml文件中定义textureview组件
创建handler线程,创建handler;
给textureview设置监听
mPreviewView = (TextureView) findViewById(R.id.textureview); mThreadHandler = new HandlerThread("CAMERA2"); mThreadHandler.start(); mHandler = new Handler(mThreadHandler.getLooper()); mPreviewView.setSurfaceTextureListener(surfaceTextureListener);在textureveiw监听中可以看到以下方法;创建时,尺寸改变时,销毁时,更新时。
我们在textureview初始化的时候创建初始化相机功能,这里先要检察权限,没有权限要去申请权限。
private TextureView.SurfaceTextureListener surfaceTextureListener=new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) { checkPermission(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { } };
public void checkPermission() { //检查是否有权限 if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 0); }else{ initCamera(); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 0: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initCamera(); } break; } }2.初始化相机功能
获得相机设备要通过相机服务CameraManager
通过相机id获得相机的参数类CameraCharactoristics对象,这个对象封装了相机相关的支持动能参数,例如支持的分辨率,摄像头旋转角度
通过cameraManager传入相机的id打开相机,设置回调
public void initCamera() { cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE); try { //获取可用相机设备id列表 String[] CameraIdList = cameraManager.getCameraIdList(); //获得前置摄像头的属性对象。 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(CameraIdList[0]); //这可用流配置 相机设备支持; 还包括最低帧持续时间 和每个格式的停滞时间/大小组合。// characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); //分辨率: StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); android.util.Size[] outputSizes = map.getOutputSizes(ImageFormat.JPEG); for(android.util.Size size:outputSizes) { list.add(size.getWidth()+"*"+size.getHeight()); Log.e("fbl",size.getWidth()+"*"+size.getHeight()); } //获取摄像头的旋转角度 mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); ArrayAdapter arr_adapter= new ArrayAdapter(Camera2Activity.this, R.layout.spinner_item_layout, list); arr_adapter.setDropDownViewResource(R.layout.spinner_item_layout); spinner.setAdapter(arr_adapter);// spinner.setSelection(5); //就像这样 cameraManager.openCamera(CameraIdList[0], mCameraDeviceStateCallback, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }在回调中有打开,失去连接,错误方法的回调
在开发相机回调中设置spinner的监听,对于选择不同的分辨率下创建不同尺寸的ImageReader对象,这个对象是封装了拍照数据的类,设置拍照监听回调后保存照片
开始预览,创建捕捉会议
/** * 相机监听,这个回调不是运行在ui线程的,不能更新UI */ private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCaera = camera; mFile = new File(Environment.getExternalStorageDirectory(),"TTT.jpg"); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { TextView tv= (TextView) view; String text = (String) tv.getText(); String[] split = text.split("\\*"); imageReader = ImageReader.newInstance(Integer.parseInt(split[1]), Integer.parseInt(split[0]), ImageFormat.JPEG, /*maxImages*/2); imageReader.setOnImageAvailableListener(mOnImageAvailableListener, mHandler); ViewGroup.LayoutParams layoutParams = mPreviewView.getLayoutParams(); layoutParams.width=min; layoutParams.height=Integer.parseInt(split[0])*min/Integer.parseInt(split[1]); mPreviewView.setLayoutParams(layoutParams); try { if(mSession!=null){ mSession.close(); } startPreview(mCaera); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onNothingSelected(AdapterView<?> adapterView) { } }); } @Override public void onDisconnected(CameraDevice camera) {} @Override public void onError(CameraDevice camera, int error) {} };3.创建捕捉会议,开始预览
获得预览的surface,图片缓存的surface
设置会议监听
会议监听中通过会议发送请求,这只请求监听
4.通过点击事件触发拍照
/** * 开始预览 * @param camera * @throws CameraAccessException */ private void startPreview(CameraDevice camera) throws CameraAccessException { SurfaceTexture texture = mPreviewView.getSurfaceTexture(); //我们将默认缓冲区的大小配置为我们想要的相机预览的大小。 texture.setDefaultBufferSize(mPreviewView.getWidth(), mPreviewView.getHeight()); surface = new Surface(texture); //我们设置了一个具有输出Surface的CaptureRequest.Builder。 try { mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewBuilder.addTarget(surface); } catch (CameraAccessException e) { e.printStackTrace(); } //创建捕捉会议 camera.createCaptureSession(Arrays.asList(surface,imageReader.getSurface()), mSessionStateCallback, mHandler); }
/** * 会议状态监听 */ private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { //session.capture(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler); mSession = session; //这句是预览的真正代码 session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) {} }; private CameraCaptureSession.CaptureCallback mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { } @Override public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult){ } };
4.通过点击事件触发拍照
创建捕捉请求操作就会在ImageReader的surface中获取一张照片,然后之前设置的拍照监听中去处理图片
@Override public void onClick(View view) { switch (view.getId()) { case R.id.bt_cut: takePicture(); break; case R.id.imagebutton: break; } }
public void takePicture(){ try { CaptureRequest.Builder captureRequestBuilder = mCaera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); // 将imageReader的surface作为CaptureRequest.Builder的目标 captureRequestBuilder.addTarget(imageReader.getSurface()); // 自动对焦 captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 获取手机方向 int rotation = getWindowManager().getDefaultDisplay().getRotation(); // 根据设备方向计算设置照片的方向 captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); //拍照 CaptureRequest mCaptureRequest = captureRequestBuilder.build(); mSession.stopRepeating(); mSession.capture(mCaptureRequest, null, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }5.处理保存图片
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { MyToast.makeText(Camera2Activity.this,"拍照成功"); mHandler.post(new ImageSaver(reader.acquireNextImage(), mFile)); } };
/** * 保存图片 */ private static class ImageSaver implements Runnable { /** * The JPEG image */ private final Image mImage; /** * The file we save the image into. */ private final File mFile; public ImageSaver(Image image, File file) { mImage = image; mFile = file; } @Override public void run() { ByteBuffer buffer = mImage.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); FileOutputStream output = null; try { output = new FileOutputStream(mFile); output.write(bytes); } catch (IOException e) { e.printStackTrace(); } finally { mImage.close(); if (null != output) { try { output.close(); } catch (IOException e) { e.printStackTrace(); } } } } }6.关闭摄像头,释放资源
@Override protected void onPause() { closeCamera(); stopBackgroundThread(); super.onPause(); } public void closeCamera() { if(mSession!=null) { mSession.close(); mSession=null; } if (null != mCaera) { mCaera.close();//关掉摄像头 mCaera = null; } } /** * Stops the background thread and its {@link Handler}. */ private void stopBackgroundThread() { mThreadHandler.quitSafely();//线程安全停止 try { mThreadHandler.join(); mThreadHandler = null; mHandler = null; } catch (InterruptedException e) { e.printStackTrace(); } }
总体比5.0以前的相机操作复杂很多,很多回调监听。
本文参考官方提供的demo:https://github.com/googlesamples/android-Camera2Basic
阅读全文
0 0
- Android开发 之 Camera2之拍照
- Android开发之拍照
- android camera2 拍照流程
- Camera2开发之CameraDevice类
- Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照
- app:Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照
- Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照
- Android Camera2 拍照入门学习
- Android Camera2 拍照入门学习
- Android Camera2 拍照入门学习
- Android camera2 之我的理解
- Android开发之控制摄像头拍照
- Android开发之拍照功能实现
- Android开发之拍照功能实现
- Android Camera开发之通过Intent拍照
- Android开发之调用摄像头拍照
- Android开发之调用摄像头拍照
- Camera框架之Camera2
- Spring源码构建项目,导入eclipse后,缺失spring-cglib-repack-3.2.4.jar和spring-objenesis-repack-2.4.jar的解决办法
- Android开发培训(08)--使用openGL ES作图
- [Java] java.util.HashMap
- hdu 6047
- halcon标定板说明
- Android开发 之 Camera2之拍照
- Python网络爬虫与信息提取-Day7-基于bs4库的HTML内容遍历方法
- Quartz.NET 入门,带C#实例
- linux: xargs处理参数时,文件名中包含空格的解决方法
- 【LintCode】反转整数
- 在VMware Workstation 12中安装Mac OS X 10.11
- UFT-c/s常用WinComboBox ,WinList,WinMenu,WinRadioButton
- Springmvc和mybatis整合
- Json对象与Json字符串的转化、JSON字符串与Java对象的转换