學(xué)習(xí)資料:
腎虛將軍android camera2 詳解說明極客學(xué)院android.hardware.camera2 使用指南Android 5.0(21)之后,android.hardware.Camera被廢棄(下面稱為Camera1),還有一個(gè)android.graphics.Camera,這個(gè)android.graphics.Camera不是用來照相的,是用來處理圖像的,可以做出3D的圖像效果之類的,之前的Camera1則由android.hardware.Camera2來代替
Camera2支持RAW輸出,可以調(diào)節(jié)曝光,對(duì)焦模式,快門等,功能比原先Camera強(qiáng)大
使用步驟:
調(diào)用Camera.open(),打開相機(jī),默認(rèn)為后置,可以根據(jù)攝像頭ID來指定打開前置還是后置調(diào)用Camera.getParameters()得到一個(gè)Camera.Parameters對(duì)象使用步驟2得到的Camera.Parameters對(duì)象,對(duì)拍照參數(shù)進(jìn)行設(shè)置調(diào)用Camera.setPReviewDispaly(SurfaceHolder holder),指定使用哪個(gè)SurfaceView來顯示預(yù)覽圖片調(diào)用Camera.startPreview()方法開始預(yù)覽取景調(diào)用Camera.takePicture()方法進(jìn)行拍照拍照結(jié)束后,調(diào)用Camera.stopPreview()結(jié)束取景預(yù)覽,之后再replease()方法釋放資源這幾個(gè)步驟從瘋狂Android講義中學(xué)到

使用SurfaceView進(jìn)行取景的預(yù)覽,點(diǎn)擊屏幕進(jìn)行拍照,用ImageView來展示拍的照片
取景
拍照預(yù)覽想買關(guān)于操作系統(tǒng)和C的書看,知乎很多人推薦這兩本,就買了,感覺確實(shí)不錯(cuò)。然而,深入理解操作系統(tǒng)買早了,啃不動(dòng)
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/surface_view_camera2_activity" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/iv_show_camera2_activity" android:layout_width="180dp" android:layout_height="320dp" android:visibility="gone" android:layout_centerInParent="true" android:scaleType="centerCrop" /></RelativeLayout>Activity代碼:
權(quán)限:
<uses-permission android:name="android.permission.CAMERA" />在獲得圖片后,想要顯示的效果是照片是豎直顯示,resource顯示的卻是逆時(shí)針旋轉(zhuǎn)了90°,照片是橫著的,就使用matrix.setRotate(90)進(jìn)行旋轉(zhuǎn)
Camera2拍照示意圖這里引用了管道的概念將安卓設(shè)備和攝像頭之間聯(lián)通起來,系統(tǒng)向攝像頭發(fā)送 Capture 請(qǐng)求,而攝像頭會(huì)返回 CameraMetadata。這一切建立在一個(gè)叫作 CameraCapturesession 的會(huì)話中。
camera2中主要的類以上從極客學(xué)院android.hardware.camera2 使用指南摘抄
CameraManaer 攝像頭管理器,用于檢測(cè)攝像頭,打開系統(tǒng)攝像頭,調(diào)用CameraManager.getCameraCharacteristics(String)可以獲取指定攝像頭的相關(guān)特性CameraCharacteristics 攝像頭的特性CameraDevice 攝像頭,類似android.hardware.Camera也就是Camera1的CameraCameraCaptureSession 這個(gè)對(duì)象控制攝像頭的預(yù)覽或者拍照,setRepeatingRequest()開啟預(yù)覽,capture()拍照,CameraCaptureSession提供了StateCallback、CaptureCallback兩個(gè)接口來監(jiān)聽CameraCaptureSession的創(chuàng)建和拍照過程。CameraRequest和CameraRequest.Builder,預(yù)覽或者拍照時(shí),都需要一個(gè)CameraRequest對(duì)象。CameraRequest表示一次捕獲請(qǐng)求,用來對(duì)z照片的各種參數(shù)設(shè)置,比如對(duì)焦模式、曝光模式等。CameraRequest.Builder用來生成CameraRequest對(duì)象。以上從腎虛將軍的android camera2 詳解說明摘抄
使用的依然是SurfaceView來進(jìn)行展示預(yù)覽
主要思路:
獲得攝像頭管理器CameraManager mCameraManager,mCameraManager.openCamera()來打開攝像頭指定要打開的攝像頭,并創(chuàng)建openCamera()所需要的CameraDevice.StateCallback stateCallback在CameraDevice.StateCallback stateCallback中調(diào)用takePreview(),這個(gè)方法中,使用CaptureRequest.Builder創(chuàng)建預(yù)覽需要的CameraRequest,并初始化了CameraCaptureSession,最后調(diào)用了setRepeatingRequest(previewRequest, null, childHandler)進(jìn)行了預(yù)覽點(diǎn)擊屏幕,調(diào)用takePicture(),這個(gè)方法內(nèi),最終調(diào)用了capture(mCaptureRequest, null, childHandler)在new ImageReader.OnImageAvailableListener(){}回調(diào)方法中,將拍照拿到的圖片進(jìn)行展示代碼:
public class Camera2Activity extends AppCompatActivity implements View.OnClickListener { private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); ///為了使照片豎直顯示 static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private ImageView iv_show; private CameraManager mCameraManager;//攝像頭管理器 private Handler childHandler, mainHandler; private String mCameraID;//攝像頭Id 0 為后 1 為前 private ImageReader mImageReader; private CameraCaptureSession mCameraCaptureSession; private CameraDevice mCameraDevice; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera2); initVIew(); } /** * 初始化 */ private void initVIew() { iv_show = (ImageView) findViewById(R.id.iv_show_camera2_activity); //mSurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surface_view_camera2_activity); mSurfaceView.setOnClickListener(this); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.setKeepScreenOn(true); // mSurfaceView添加回調(diào) mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { //SurfaceView創(chuàng)建 // 初始化Camera initCamera2(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView銷毀 // 釋放Camera資源 if (null != mCameraDevice) { mCameraDevice.close(); Camera2Activity.this.mCameraDevice = null; } } }); } /** * 初始化Camera2 */ @RequiresApi(api = Build.VERSION_CODES.LOLLipOP) private void initCamera2() { HandlerThread handlerThread = new HandlerThread("Camera2"); handlerThread.start(); childHandler = new Handler(handlerThread.getLooper()); mainHandler = new Handler(getMainLooper()); mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//后攝像頭 mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG,1); mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在這里處理拍照得到的臨時(shí)照片 例如,寫入本地 @Override public void onImageAvailable(ImageReader reader) { mCameraDevice.close(); mSurfaceView.setVisibility(View.GONE); iv_show.setVisibility(View.VISIBLE); // 拿到拍照照片數(shù)據(jù) Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes);//由緩沖區(qū)存入字節(jié)數(shù)組 final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); if (bitmap != null) { iv_show.setImageBitmap(bitmap); } } }, mainHandler); //獲取攝像頭管理 mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } //打開攝像頭 mCameraManager.openCamera(mCameraID, stateCallback, mainHandler); } catch (CameraaccessException e) { e.printStackTrace(); } } /** * 攝像頭創(chuàng)建監(jiān)聽 */ private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) {//打開攝像頭 mCameraDevice = camera; //開啟預(yù)覽 takePreview(); } @Override public void onDisconnected(CameraDevice camera) {//關(guān)閉攝像頭 if (null != mCameraDevice) { mCameraDevice.close(); Camera2Activity.this.mCameraDevice = null; } } @Override public void onError(CameraDevice camera, int error) {//發(fā)生錯(cuò)誤 Toast.makeText(Camera2Activity.this, "攝像頭開啟失敗", Toast.LENGTH_SHORT).show(); } }; /** * 開始預(yù)覽 */ private void takePreview() { try { // 創(chuàng)建預(yù)覽需要的CaptureRequest.Builder final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // 將SurfaceView的surface作為CaptureRequest.Builder的目標(biāo) previewRequestBuilder.addTarget(mSurfaceHolder.getSurface()); // 創(chuàng)建CameraCaptureSession,該對(duì)象負(fù)責(zé)管理處理預(yù)覽請(qǐng)求和拍照請(qǐng)求 mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③ { @Override public void onConfigured(CameraCaptureSession cameraCaptureSession) { if (null == mCameraDevice) return; // 當(dāng)攝像頭已經(jīng)準(zhǔn)備好時(shí),開始顯示預(yù)覽 mCameraCaptureSession = cameraCaptureSession; try { // 自動(dòng)對(duì)焦 previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 打開閃光燈 previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_Flash); // 顯示預(yù)覽 CaptureRequest previewRequest = previewRequestBuilder.build(); mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) { Toast.makeText(Camera2Activity.this, "配置失敗", Toast.LENGTH_SHORT).show(); } }, childHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } /** * 點(diǎn)擊事件 */ @Override public void onClick(View v) { takePicture(); } /** * 拍照 */ private void takePicture() { if (mCameraDevice == null) return; // 創(chuàng)建拍照需要的CaptureRequest.Builder final CaptureRequest.Builder captureRequestBuilder; try { captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); // 將imageReader的surface作為CaptureRequest.Builder的目標(biāo) captureRequestBuilder.addTarget(mImageReader.getSurface()); // 自動(dòng)對(duì)焦 captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自動(dòng)曝光 captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 獲取手機(jī)方向 int rotation = getWindowManager().getDefaultDisplay().getRotation(); // 根據(jù)設(shè)備方向計(jì)算設(shè)置照片的方向 captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); //拍照 CaptureRequest mCaptureRequest = captureRequestBuilder.build(); mCameraCaptureSession.capture(mCaptureRequest, null, childHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }}布局代碼以及權(quán)限與Camera1中一樣,效果一樣
預(yù)覽時(shí),是將mSurfaceHolder.getSurface()作為目標(biāo)顯示拍照結(jié)果時(shí),是將mImageReader.getSurface()作為目標(biāo)
Camera2的功能很強(qiáng)大,暫時(shí)也只是學(xué)習(xí)了最基本的思路
住的地方,沒有桌子,于是坐地上,趴在床上敲代碼,腰疼。逛淘寶買桌子去
感謝極客學(xué)院和腎虛將軍的學(xué)習(xí)資料
共勉 : )
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注