Camera2
Camera2是Android5.0中的其中一个新的特性,新的API。与原来的camera API相比,不同之处在于:
- 原生支持RAW照片输出
- 突发拍摄模式
制约拍照速度的不再是软件而是硬件。以Nexus 5为例,分辨率全开下Andorid L的连拍速度可达到30fps。
- 全手动控制
快门、感光度、对焦、测光、硬件视频防抖等多种参数都被整合到了新的API内。新的API中添加的手动控制功能列表:
- 感光度
- 手动对焦/AF开关
- AE/AF/AWB模式
- AE/AWB锁
- 硬件视频防抖
- 连续帧
干货
Camera2 程序逻辑与原Camera有很大不同。
CameraManager,系统服务,通过 CameraManager去获得camera设备对象。CameraDevices提供描述相机硬件设备支持可用的和输出的参数,这些信息通过 CameraCharacteristics获得,CameraCharacteristics又是从 getCameraCharacteristics(cameraId)获得,通过freamwork中的源码发现,其实这里就是直接调用的Camera API接口。
通过camera拍照,应用首先要创建由相机设备的输出surface组成的拍照会话,createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)。每个surface必须预先设置适当的大小和格式去匹配相机设备的可支持的大小和格式。一个目标surface可以从不同的类中获取,包括SurfaceView,SurfaceTexture via Surface(SurfaceTexture), MediaCodec, MediaRecorder, Allocation, and ImageReader.
一旦请求被建立,他可以交给活动的拍照会话:一次拍照(one-shot )或者无止境连续拍照或预览(Repeating)。两种方法都有一个其他的方式:接受一系列的请求作为burst拍照/重复burst。
public void openCamera (String cameraId, CameraDevice.StateCallback callback, Handler handler)
使用getCameraIdList()来获得可用摄像设备的列表。一旦成功打开相机,CameraDevice.StateCallback中的onOpened(CameraDevice)将被调用。相机设备可以通过调用createCaptureSession()和createCaptureRequest()去设置操作。如果打开相机设备失败,那么设备回调的onError方法将被调用,和后续调用相机设备将抛出一个CameraAccessException。
public abstract CaptureRequest.Builder createCaptureRequest (int templateType)
为请求拍照创建一个CaptureRequest.Builder,初始化目标用例的模板。选择最好的设置为特定的相机设备,所以不建议为不同的相机设备重用相同的请求,创建一个builder为具体的设备和模板和根据需要覆盖的设置。
public abstract void createCaptureSession (List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
活动着的会话决定了相机的output Surfaces 为每个拍照的要求。给定请求可以使用全部或只有部分的output Surfaces。一旦CameraCaptureSession创建,可以提交capture请求、captureBurst请求,setRepeatingRequest请求或setRepeatingBurst请求。
权限
<uses-permission android:name="android.permission.CAMERA"/>
布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextureView android:id="@+id/textureview" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout>
核心代码
public class CameraFragment extends Fragment implements TextureView.SurfaceTextureListener { private TextureView mPreviewView; private Handler mHandler; private HandlerThread mThreadHandler; private Size mPreviewSize; private CaptureRequest.Builder mPreviewBuilder; public static CameraFragment newInstance() { return new CameraFragment(); } @SuppressWarnings("ResourceType") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.camera_frag, null); initLooper(); initUIAndListener(v); return v; } //很多过程都变成了异步的了,所以这里需要一个子线程的looper private void initLooper() { mThreadHandler = new HandlerThread("CAMERA2"); mThreadHandler.start(); mHandler = new Handler(mThreadHandler.getLooper()); } //可以通过TextureView或者SurfaceView private void initUIAndListener(View v) { mPreviewView = (TextureView) v.findViewById(R.id.textureview); mPreviewView.setSurfaceTextureListener(this); } @SuppressWarnings("ResourceType") @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { try { //获得CameraManager CameraManager cameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE); //获得属性 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics("0"); //支持的STREAM CONFIGURATION StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); //显示的size mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0]; //打开相机 cameraManager.openCamera("0", mCameraDeviceStateCallback, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } //TextureView.SurfaceTextureListener @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { try { startPreview(camera); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(CameraDevice camera) { } @Override public void onError(CameraDevice camera, int error) { } }; //开始预览,主要是camera.createCaptureSession这段代码很重要,创建会话 private void startPreview(CameraDevice camera) throws CameraAccessException { SurfaceTexture texture = mPreviewView.getSurfaceTexture(); texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface surface = new Surface(texture); try { mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); } catch (CameraAccessException e) { e.printStackTrace(); } mPreviewBuilder.addTarget(surface); camera.createCaptureSession(Arrays.asList(surface), mSessionStateCallback, mHandler); } private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { updatePreview(session); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { } }; private void updatePreview(CameraCaptureSession session) throws CameraAccessException { session.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler); } }
我是天王盖地虎的分割线
源码:https://github.com/pinguo-yuyidong/Camera2