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
</activity> </application> </manifest>