Android Working with Camera2 API
Compared with old Camera API, new Camera2(android.hardware.camera2) is much complex as it involves all asynchronous calls. Android API 21 introduced this new Camera2 API. So, if you are working on API less than 21, use the old Camera API(android.hardware.camera) and for all above API 21 use this API as the old one is deprecated.
Camera2 works in the following way:-
- CameraManager-We uses it to get all camera’s available in the device each having cameraId like front camera and back camera and its properties can be obtained from CameraCharacterstics class.
- CameraDevice- We can get camera device from cameraManager class by its id and perform related operations.
- CaptureRequest- Create a CaptureRequest from cameradevice to capture images.
- CameraCaptureSession- Create a CameraCaptureSession to get CaptureRequest’s from CameraDevice.
- CameraCaptureSession.CaptureCallback- It will provide all the capture session results.
So, Let’s Start
1.Open Android Studio -> New Project->Android Application Project-> Name of Application-> Follow all instructions and complete by clicking on Finish.
2.To use Camera in your application add following permissions to AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera2.full" />
3. Now create a layout file containing texture view for the camera.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextureView android:id="@+id/textureview" android:layout_width="match_parent" android:layout_height="match_parent" /> <Button android:id="@+id/getpicture" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="getPicture"/> </RelativeLayout>
4. Now create MainActivity.java and code to save pictures clicked by camera.
MainActivity.java
package com.coderzpassion.camera2sample; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.util.Size; import android.util.SparseIntArray; import android.view.Menu; import android.view.MenuItem; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.logging.LogRecord; public class MainActivity extends AppCompatActivity { private Size previewsize; private Size jpegSizes[]=null; private TextureView textureView; private CameraDevice cameraDevice; private CaptureRequest.Builder previewBuilder; private CameraCaptureSession previewSession; Button getpicture; 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); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textureView=(TextureView)findViewById(R.id.textureview); textureView.setSurfaceTextureListener(surfaceTextureListener); getpicture=(Button)findViewById(R.id.getpicture); getpicture.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getPicture(); } }); } void getPicture() { if(cameraDevice==null) { return; } CameraManager manager=(CameraManager)getSystemService(Context.CAMERA_SERVICE); try { CameraCharacteristics characteristics=manager.getCameraCharacteristics(cameraDevice.getId()); if(characteristics!=null) { jpegSizes=characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG); } int width=640,height=480; if(jpegSizes!=null && jpegSizes.length>0) { width=jpegSizes[0].getWidth(); height=jpegSizes[0].getHeight(); } ImageReader reader=ImageReader.newInstance(width,height,ImageFormat.JPEG,1); List<Surface> outputSurfaces=new ArrayList<Surface>(2); outputSurfaces.add(reader.getSurface()); outputSurfaces.add(new Surface(textureView.getSurfaceTexture())); final CaptureRequest.Builder capturebuilder=cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); capturebuilder.addTarget(reader.getSurface()); capturebuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); int rotation=getWindowManager().getDefaultDisplay().getRotation(); capturebuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation)); ImageReader.OnImageAvailableListener imageAvailableListener=new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Image image = null; try { image = reader.acquireLatestImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.capacity()]; buffer.get(bytes); save(bytes); } catch (Exception ee) { } finally { if(image!=null) image.close(); } } void save(byte[] bytes) { File file12=getOutputMediaFile(); OutputStream outputStream=null; try { outputStream=new FileOutputStream(file12); outputStream.write(bytes); }catch (Exception e) { e.printStackTrace(); }finally { try { if (outputStream != null) outputStream.close(); }catch (Exception e){} } } }; HandlerThread handlerThread=new HandlerThread("takepicture"); handlerThread.start(); final Handler handler=new Handler(handlerThread.getLooper()); reader.setOnImageAvailableListener(imageAvailableListener,handler); final CameraCaptureSession.CaptureCallback previewSSession=new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) { super.onCaptureStarted(session, request, timestamp, frameNumber); } @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); startCamera(); } }; cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { session.capture(capturebuilder.build(),previewSSession,handler); }catch (Exception e) { } } @Override public void onConfigureFailed(CameraCaptureSession session) { } },handler); } catch (Exception e) { } } public void openCamera() { CameraManager manager=(CameraManager)getSystemService(Context.CAMERA_SERVICE); try { String camerId=manager.getCameraIdList()[0]; CameraCharacteristics characteristics=manager.getCameraCharacteristics(camerId); StreamConfigurationMap map=characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); previewsize=map.getOutputSizes(SurfaceTexture.class)[0]; manager.openCamera(camerId,stateCallback,null); }catch (Exception e) { } } private TextureView.SurfaceTextureListener surfaceTextureListener=new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { openCamera(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } }; private CameraDevice.StateCallback stateCallback=new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { cameraDevice=camera; startCamera(); } @Override public void onDisconnected(CameraDevice camera) { } @Override public void onError(CameraDevice camera, int error) { } }; @Override protected void onPause() { super.onPause(); if(cameraDevice!=null) { cameraDevice.close(); } } void startCamera() { if(cameraDevice==null||!textureView.isAvailable()|| previewsize==null) { return; } SurfaceTexture texture=textureView.getSurfaceTexture(); if(texture==null) { return; } texture.setDefaultBufferSize(previewsize.getWidth(),previewsize.getHeight()); Surface surface=new Surface(texture); try { previewBuilder=cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); }catch (Exception e) { } previewBuilder.addTarget(surface); try { cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { previewSession=session; getChangedPreview(); } @Override public void onConfigureFailed(CameraCaptureSession session) { } },null); }catch (Exception e) { } } void getChangedPreview() { if(cameraDevice==null) { return; } previewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); HandlerThread thread=new HandlerThread("changed Preview"); thread.start(); Handler handler=new Handler(thread.getLooper()); try { previewSession.setRepeatingRequest(previewBuilder.build(), null, handler); }catch (Exception e){} } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private static File getOutputMediaFile() { File mediaStorageDir = new File( Environment .getExternalStorageDirectory(), "MyCameraApp"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") .format(new Date()); File mediaFile; mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); return mediaFile; } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.coderzpassion.camera2sample" > <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera2.full" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
For Official Documentation click here
Output