Android: How to improve the performance of my camera - android

I develop an android camera app! I use camera2 to implement the camera module! The problem is that when I take a picture with it, the size of the image is too high, something about 9MB!!! So my gallery is too slow! What is the reason of it?
I test it in different cell phones, the size of images are different, but still too high!! I tried photo.compress(Bitmap.CompressFormat.JPEG, 50, out); this code to reduce the size, but the quality of image is too important to me, so I don't want to reduce the resolution! Here is my camera code:
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;
private static VirtualFileSystem vfs;
ImageButton getpicture;
ImageButton btnShow;
Button btnSetting;
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 = (ImageButton) findViewById(R.id.getpicture);
btnShow = (ImageButton) findViewById(R.id.button2);
btnSetting = (Button) findViewById(R.id.btn_setting);
btnSetting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, Setting.class));
}
});
btnShow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, Gallery2.class));
}
});
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);
Bitmap photo = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 50, out);
save(out);
photo = Bitmap.createScaledBitmap(photo, 120, 120, false);
btnShow.setImageBitmap(photo);
save(out);
} catch (Exception ee) {
} finally {
if (image != null)
image.close();
}
}
void save(ByteArrayOutputStream bytes) {
File file12 = getOutputMediaFile();
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file12);
outputStream.write(bytes.toByteArray());
} 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];
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
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, 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 File getOutputMediaFile() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File mediaFile;
File(Environment.getExternalStorageDirectory()+"/MyCamAppCipher1"+"/" + mTime + ".jpg");
mediaFile = new File("/myfiles.db"+"/" + mTime + ".jpg");
return mediaFile;
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}

In this piece of code, you're selecting the first available resolution, which usually is the highest one.
int width = 640, height = 480;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
Aside from doing what you're saying, which is reduce image quality by calling photo.compress(Bitmap.CompressFormat.JPEG, 50, out);, your alternative is selecting a smaller camera resolution, by iterating the jpegSizes array and selecting a lower resolution.
Take into account that to do so you should use relative compares (i.e. width >= minWidth), or find the middle resolution, but always selecting one of the ones available in this array. Notice that this array will vary from phone to phone (i.e. it depends on the camera characteristics).
For example, let's say that you need a minimum of 3M pixels (2048x1536). You could have the following code:
int width = Integer.MAX_VALUE, height = Integer.MAX_VALUE;
for (int i = 0; i < jpegSizes.length; i++) {
int currWidth = jpegSizes[0].getWidth();
int currHeight = jpegSizes[0].getHeight();
if ((currWidth < width && currHeight < height) && // smallest resolution
(currWidth > 2048 && currHeight > 1536)) { // at least 3M pixels
width = currWidth;
height = currHeight;
}
}
Notice that there are two conditions:
in the first line, we're looking for the smallest possible resolution (always smaller than the previous one; notice also the initial values for width and height, Integer.MAX_VALUE, which means that at least the first value will always match this condition)
in the second line, we're making sure is at least 3M pixels
So, all combined this code will select the smallest resolution possible, at least 3M pixels.
Finally, you may add a fallback condition: if no matching resolution is found (i.e. width and height are Integer.MAX_VALUE), select the first one as you're currently doing.

I have done a camera app with camera2 too and saving images into disk is nearly immediate, even with 12 or 15 Mb picture size (no need of compressing to 50%). When you say your gallery is slow... are you loading full size images into thumbnails? Are you displaying full size images? Try to load small pictures to your thumbnails and display.

Related

Not taking picture in background using textureview and camera2 api

Here is my Camera2Manger code
i have added permissions in manifist file and take permissions in run time but still this code is not working i am calling this class in my other class like
Camera2Manager camera2Manager = new Camera2Manager(mTextureView,GestureSelfUnlockActivity.this);
camera2Manager.initCamera();
and my Manager class is below i have checked code surfaceviewlistener is not working anyone can help me out thanks
public class Camera2Manager {
private static final int SETIMAGE = 1;
private static final int MOVE_FOCK = 2;
private TextureView mTextureView;
private Context mContext;
private Handler mHandler;
private Handler mUIHandler;
private ImageReader mImageReader;
private CaptureRequest.Builder mPreViewBuidler;
private CameraCaptureSession mCameraSession;
private CameraCharacteristics mCameraCharacteristics;
private Size mPreViewSize;
private Rect maxZoomrect;
private int maxRealRadio;
// camera zoom related
private Rect picRect;
public Camera2Manager(TextureView textureView, Context context) {
mTextureView = textureView;
mContext = context;
}
public void initCamera() {
mUIHandler = new Handler(new InnerCallBack());
mTextureView.setSurfaceTextureListener(mSurfacetextlistener);
// Toast.makeText(mContext, "Caremmaa", Toast.LENGTH_SHORT).show();
}
#SuppressLint("NewApi")
private final ImageReader.OnImageAvailableListener onImageAvaiableListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
mHandler.post(new ImageSaver(imageReader.acquireNextImage()));
}
};
private Surface surface;
#SuppressLint("NewApi")
private final CameraDevice.StateCallback cameraOpenCallBack = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice cameraDevice) {
try {
mPreViewBuidler = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
SurfaceTexture texture = mTextureView.getSurfaceTexture();
texture.setDefaultBufferSize(mPreViewSize.getWidth(), mPreViewSize.getHeight());
surface = new Surface(texture);
mPreViewBuidler.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), mSessionStateCallBack, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onDisconnected(CameraDevice cameraDevice) {
}
#Override
public void onError(CameraDevice cameraDevice, int i) {
}
};
#SuppressLint("NewApi")
private final CameraCaptureSession.StateCallback mSessionStateCallBack = new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
try {
mCameraSession = cameraCaptureSession;
cameraCaptureSession.setRepeatingRequest(mPreViewBuidler.build(), null, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
}
};
private final TextureView.SurfaceTextureListener mSurfacetextlistener = new TextureView
.SurfaceTextureListener() {
#SuppressLint("NewApi")
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
HandlerThread thread = new HandlerThread("Camera2");
thread.start();
mHandler = new Handler(thread.getLooper());
CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
String cameraid = CameraCharacteristics.LENS_FACING_FRONT + "";
Toast.makeText(mContext, "Caremmaa", Toast.LENGTH_SHORT).show();
try {
mCameraCharacteristics = manager.getCameraCharacteristics(cameraid);
//The area of ​​the screen sensor, in pixels.
maxZoomrect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
//Maximum digital zoom
maxRealRadio = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM).intValue();
picRect = new Rect(maxZoomrect);
StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)
), new CompareSizeByArea());
mPreViewSize = map.getOutputSizes(SurfaceTexture.class)[0];
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, 5);
mImageReader.setOnImageAvailableListener(onImageAvaiableListener, mHandler);
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
manager.openCamera(cameraid, cameraOpenCallBack, mHandler);
//Set the monitor for clicking and taking pictures
takePhoto();
} catch (CameraAccessException e) {
ToastUtil.showToast(e.getMessage());
e.printStackTrace();
}
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
#SuppressLint("NewApi")
private void takePhoto() {
try {
Toast.makeText(mContext, "Camera started", Toast.LENGTH_SHORT).show();
mCameraSession.setRepeatingRequest(initDngBuilder().build(), null, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#SuppressLint("NewApi")
private CaptureRequest.Builder initDngBuilder() {
CaptureRequest.Builder captureBuilder = null;
try {
captureBuilder = mCameraSession.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
captureBuilder.addTarget(surface);
// Required for RAW capture
captureBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON);
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
captureBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, (long) ((214735991 - 13231) / 2));
captureBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
captureBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, (10000 - 100) / 2);//Set ISO, Sensitivity
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, 90);
//set 30 frames per second
CaptureRequest mCaptureRequest = captureBuilder.build();
mCameraSession.capture(mCaptureRequest, null, mHandler); //take a picture
CameraManager cameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
String cameraid = CameraCharacteristics.LENS_FACING_FRONT + "";
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraid);
Range<Integer>[] fps = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
captureBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fps[fps.length - 1]);
} catch (CameraAccessException | NullPointerException e) {
e.printStackTrace();
}
return captureBuilder;
}
private class ImageSaver implements Runnable {
Image reader;
public ImageSaver(Image reader) {
this.reader = reader;
}
#SuppressLint("NewApi")
#Override
public void run() {
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS+"/lock").getAbsoluteFile();
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, System.currentTimeMillis() + ".jpg");
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
ByteBuffer buffer = reader.getPlanes()[0].getBuffer();
byte[] buff = new byte[buffer.remaining()];
buffer.get(buff);
BitmapFactory.Options ontain = new BitmapFactory.Options();
ontain.inSampleSize = 50;
Bitmap bm = BitmapFactory.decodeByteArray(buff, 0, buff.length, ontain);
Message.obtain(mUIHandler, SETIMAGE, bm).sendToTarget();
outputStream.write(buff);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private class InnerCallBack implements Handler.Callback {
#SuppressLint("NewApi")
#Override
public boolean handleMessage(Message message) {
switch (message.what) {
case SETIMAGE:
Bitmap bm = (Bitmap) message.obj;
//preview avatar
break;
case MOVE_FOCK:
mPreViewBuidler.set(CaptureRequest.SCALER_CROP_REGION, picRect);
try {
mCameraSession.setRepeatingRequest(mPreViewBuidler.build(), null,
mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
break;
}
return false;
}
}
#SuppressLint("NewApi")
public static class CompareSizeByArea implements java.util.Comparator<Size> {
#Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
}
}
}
But this code is not working.

Camera2 Api: LegacyCameraDevice_nativeGetSurfaceId: Could not retrieve native Surface from surface

I was trying to use the Camera2 API of Android. The front camera is working fine, but when it comes to using the back/rear camera, this error occurs:
LegacyCameraDevice_nativeGetSurfaceId: Could not retrieve native Surface from surface.
This problem occurs after I click the button to take a picture. The capture callback is successful, but I get no image in onImageAvailable().
I followed the tutorial of https://web.archive.org/web/20161011160303/https://inducesmile.com/android/android-camera2-api-example-tutorial/ . I do not have any idea on how to proceed with the error that I am facing right now.
Here is the code used in capturing the image:
private void takePicture() {
if (mCameraDevice == null) {
return;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
CameraManager mManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics mCharacteristics = mManager.getCameraCharacteristics(mCameraDevice.getId());
Size[] jpegSizes = null;
if (mCharacteristics != null) {
jpegSizes = mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
int width = 640;
int height = 480;
for(int x = 0; x < jpegSizes.length; x++) {
Log.wtf("jpegSizes", String.valueOf(jpegSizes[x]));
}
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[4].getWidth();
height = jpegSizes[4].getHeight();
}
final ImageReader mReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> mOutputSurface = new ArrayList<>(2);
mOutputSurface.add(mReader.getSurface());
mOutputSurface.add(new Surface(mTextureView.getSurfaceTexture()));
final CaptureRequest.Builder mCaptureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
mCaptureBuilder.addTarget(mReader.getSurface());
mCaptureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
int mRotation = getWindowManager().getDefaultDisplay().getRotation();
int jpegOrientation = (ORIENTATIONS.get(mRotation) + mSensorOrientation + 270) % 360;
if(cameraId.equals("0")) {
mCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(mRotation));
} else {
if(extras.getString("orient").equals("landscape")) {
mCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(mRotation));
} else {
mCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegOrientation);
}
}
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, #NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
if(mImage == null) {
Toast.makeText(StartCameraActivity.this, "Capturing Image Failed, Please Try Again", Toast.LENGTH_SHORT).show();
Log.wtf("onCaptureComplete", "Image not Available");
} else {
Log.wtf("onCaptureComplete", "Image Available");
}
//createCameraPreview();
}
#Override
public void onCaptureFailed(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, #NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Log.wtf("FAILED", failure.toString());
}
};
mCameraDevice.createCaptureSession(mOutputSurface, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
Log.wtf("onConfigured", "succes");
try {
session.capture(mCaptureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession session) {
Log.wtf("onConfigureFailed", "failed");
}
}, mBackgroundHandler);
mReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(final ImageReader reader) {
mImage = reader.acquireLatestImage();
Log.wtf("imageAvail", "OnImageAvailable");
StartCameraActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if (mImage == null) {
return;
}
final Image.Plane[] planes = mImage.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mTextureView.setVisibility(View.INVISIBLE);
if(cameraId.equals("0")) {
screenshotHolder.setImageBitmap(bitmap);
} else {
screenshotHolder.setImageBitmap(flip(bitmap, mImage.getWidth(), mImage.getHeight()));
}
new RenderPicture(StartCameraActivity.this).execute();
if (mImage != null) {
mImage.close();
}
if(mReader != null) {
mReader.close();
}
}
});
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
Your ImageReader is a local variable in takePicture, and doesn't look like it's stored anywhere in the parent class. It's likely being garbage collected immediately or soon after takePicture exits, so when the camera tries to set itself up, the Surface reports as being abandoned.
A Surface is like a weak reference and won't keep the ImageReader alive by itself. Store it in the parent class like you do with the camera device.

Android java.lang.IllegalArgumentException: previewSize must not be taller than activeArray

My application was working good in large number of phones. However, when I installed it in my old android phone the following error is thrown and application crashes while taking the photo.
Android java.lang.IllegalArgumentException: previewSize must not be
taller than activeArray
Photo Capturing code:
public class Camera1 extends AppCompatActivity {
private static final String TAG = "AndroidCameraApi";
private TextureView textureView;
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 Bitmap scaled;
private Bitmap mBitmapToSave;
private Bitmap mBitmapToSave1;
private String cameraId;
protected CameraDevice cameraDevice;
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest captureRequest;
protected CaptureRequest.Builder captureRequestBuilder;
private Size imageDimension;
private ImageReader imageReader;
private File file;
private com.google.android.gms.vision.face.FaceDetector detector;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private boolean mFlashSupported;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
private int width = 640;
private int height = 480;
private int index;
//Image request code
private int PICK_IMAGE_REQUEST = 1;
private int a=0;
//storage permission code
private static final int STORAGE_PERMISSION_CODE = 123;
//Bitmap to get image from gallery
private Bitmap bitmap;
//Uri to store the image uri
private Uri filePath;
private String name,dl_no,truck_id, tstatus;
private float l_value;
private String dl;
private int c=0;
File fileToUpload;
int f=0;
private String uuid;
String latitude;
String longitude;
String time1;
String date1;
private int mSensorOrientation;
CameraCharacteristics characteristics;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_camera2_api);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
textureView = (TextureView) findViewById(R.id.texture);
assert textureView != null;
textureView.setSurfaceTextureListener(textureListener);
detector = new FaceDetector.Builder(getApplicationContext())
.setMode(FaceDetector.ACCURATE_MODE)
.build();
uuid = UUID.randomUUID().toString();
Bundle extras = getIntent().getExtras();
if (extras != null) {
l_value=extras.getFloat("v");
tstatus=extras.getString("status");
name=extras.getString("name");
dl_no=extras.getString("dl");
truck_id=extras.getString("tid");
latitude=extras.getString("lat");
longitude=extras.getString("lon");
time1 =extras.getString("t");
date1=extras.getString("d");
}
fileToUpload = new File(Environment.getExternalStorageDirectory() + "/" + "/Faceapp/"+name+"_"+dl_no+"_"+truck_id+"_"+latitude+"_"+longitude+"_"+time1+"_"+date1+"_"+a+".jpg");
//Intent uplaod_intent = new Intent(Camera1.this, uploadRest.class);
// Add extras to the bundle
// Start the service
// Camera1.this.startService(uplaod_intent);
}
private int getOrientation(int rotation) {
// Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X
// We have to take that into account and rotate JPEG properly.
// For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
// For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
//open your camera here
openCamera();
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Transform you image captured size according to the surface width and height
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice camera) {
//This is called when the camera is open
Log.e(TAG, "onOpened");
cameraDevice = camera;
createCameraPreview();
}
#Override
public void onDisconnected(CameraDevice camera) {
cameraDevice.close();
}
#Override
public void onError(CameraDevice camera, int error) {
cameraDevice.close();
cameraDevice = null;
}
};
final CameraCaptureSession.CaptureCallback captureCallbackListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(Camera1.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
}
};
protected void startBackgroundThread() {
mBackgroundThread = new HandlerThread("Camera Background");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
protected void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void goToCompletedActivity(Context mContext) {
Intent login = new Intent(mContext, Completed.class);
mContext.startActivity(login);
}
private void userLogin() {
//first getting the values
final String Driver_id = dl_no;
class UserLogin extends AsyncTask<Void, Void, String> {
ProgressBar progressBar;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar = (ProgressBar) findViewById(R.id.progressBar);
//progressBar.setVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// progressBar.setVisibility(View.GONE);
try {
//converting response to json object
JSONObject obj = new JSONObject(s);
//if no error in response
if (!obj.getBoolean("error")) {
Toast.makeText(getApplicationContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
//getting the user from the response
JSONObject userJson = obj.getJSONObject("user");
//creating a new user object
User user = new User(
userJson.getString("Driver_id"),
userJson.getString("Driver_name"),
userJson.getString("Truck_id"),
userJson.getString("Trainingstatus")
);
//storing the user in shared preferences
SharedPrefManager.getInstance(getApplicationContext()).userLogin(user);
//starting the profile activity
finish();
startActivity(new Intent(getApplicationContext(), ProfileActivity.class));
} else {
Toast.makeText(getApplicationContext(), "Invalid Driver ID", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
protected String doInBackground(Void... voids) {
//creating request handler object
RequestHandler requestHandler = new RequestHandler();
//creating request parameters
HashMap<String, String> params = new HashMap<>();
params.put("Driver_id", Driver_id);
//returing the response
return requestHandler.sendPostRequest(URLs.URL_LOGIN, params);
}
}
UserLogin ul = new UserLogin();
ul.execute();
}
public void launchuploadservice() {
// Construct our Intent specifying the Service
Intent i = new Intent(this, Upload.class);
// Add extras to the bundle
i.putExtra("name", name);
i.putExtra("dl", dl_no);
i.putExtra("tid", truck_id);
i.putExtra("lat", latitude);
i.putExtra("lon", longitude);
i.putExtra("status", tstatus);
i.putExtra("t", time1);
i.putExtra("d", date1);
// Start the service
startService(i);
}
protected void takePicture() {
if (null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
return;
}
final CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
if (jpegSizes != null && 0 < jpegSizes.length) {
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);
// Orientation
int displayRotation = this.getWindowManager().getDefaultDisplay().getRotation();
int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (sensorOrientation == 90 || sensorOrientation == 270) {
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
swappedDimensions = true;
}
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (sensorOrientation == 0 || sensorOrientation == 180) {
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
swappedDimensions = true;
}
}
break;
}
int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
ImageReader.OnImageAvailableListener readerListener = 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);
mBitmapToSave = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (detector.isOperational() && mBitmapToSave != null) {
Frame frame = new Frame.Builder()
.setBitmap(mBitmapToSave)
//.setImageData(buffer, width, height, YUV_420_888)
//.setRotation(getWindowManager().getDefaultDisplay().getRotation())
.build();
SparseArray<Face> faces = detector.detect(frame);
for (index = 0; index < faces.size(); ++index) {
Face face = faces.valueAt(index);
}
if (faces.size() == 0) {
Toast.makeText(Camera1.this, "No Face" + "\n", Toast.LENGTH_SHORT).show();
saveImageToDisk(bytes);
MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.not);
mediaPlayer.start();
// mBitmapToSave.recycle();
} else {
saveImageToDisk(bytes);
Toast.makeText(Camera1.this, "Face Found " + "\n", Toast.LENGTH_SHORT).show();
launchuploadservice();
}
}
} catch (Exception ee) {
}
finally {
if(image!=null)
image.close();
}
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
createCameraPreview();
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, mBackgroundHandler);
mBitmapToSave = null;
} catch(CameraAccessException e){
e.printStackTrace();
}
}
private void saveImageToDisk(final byte[] bytes) {
final File file = new File(Environment.getExternalStorageDirectory() + "/"+"/Faceapp/"+name+"_"+dl_no+"_"+truck_id+"_"+longitude+"_"+latitude+"_"+time1+"_"+date1 + "_.jpg");
try (final OutputStream output = new FileOutputStream(file)) {
output.write(bytes);
//this.picturesTaken.put(file.getPath(), bytes);
} catch (IOException e) {
Log.e(TAG, "Exception occurred while saving picture to external storage ", e);
}
}
protected void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback(){
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
//The camera is already closed
if (null == cameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(Camera1.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "is camera open");
try {
cameraId = manager.getCameraIdList()[1];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
// Add permission for camera and let user grant the permission
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(Camera1.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION);
return;
}
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e(TAG, "openCamera X");
}
protected void updatePreview() {
if(null == cameraDevice) {
Log.e(TAG, "updatePreview error, return");
}
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void closeCamera() {
if (null != cameraDevice) {
cameraDevice.close();
cameraDevice = null;
}
if (null != imageReader) {
//image.close();
imageReader.close();
imageReader = null;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// close the app
Toast.makeText(Camera1.this, "Sorry!!!, you can't use this app without granting permission", Toast.LENGTH_LONG).show();
finish();
}
}
}
// #Override
/* public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// close the app
Toast.makeText(Camera1.this, "Sorry!!!, you can't use this app without granting permission", Toast.LENGTH_LONG).show();
finish();
}
}
}
*/
#Override
protected void onResume() {
final Intent intent = new Intent(Camera1.this, Completed.class);
super.onResume();
Log.e(TAG, "onResume");
startBackgroundThread();
if (textureView.isAvailable()) {
openCamera();
} else {
textureView.setSurfaceTextureListener(textureListener);
}
final int PICTURES_LIMIT = 1;
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
int pictureNo=0;
public void run() {
if (pictureNo>PICTURES_LIMIT){
timer.cancel();
finish();
} else {
takePicture();
pictureNo++;
}
}
},10, 5500);
}
#Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause");
closeCamera();
stopBackgroundThread();
}
}
Based on the code found here, its pretty self explanatory that the old device preview size is less than the size that you're trying to crop.
Check the getPreviewCropRectangleUnzoomed function in the code that I have mentioned above. The documentation of the function says the cause of the error specifically. From the documentation.
/**
* Calculate the effective crop rectangle for this preview viewport;
* assumes the preview is centered to the sensor and scaled to fit across one of the dimensions
* without skewing.
*
* <p>The preview size must be a subset of the active array size; the resulting
* rectangle will also be a subset of the active array rectangle.</p>
*
* <p>The unzoomed crop rectangle is calculated only.</p>
*
* #param activeArray active array dimensions, in sensor space
* #param previewSize size of the preview buffer render target, in pixels (not in sensor space)
* #return a rectangle which serves as the preview stream's effective crop region (unzoomed),
* in sensor space
*
* #throws NullPointerException
* if any of the args were {#code null}
* #throws IllegalArgumentException
* if {#code previewSize} is wider or taller than {#code activeArray}
*/
Check the part - The preview size must be a subset of the active array size; the resulting rectangle will also be a subset of the active array rectangle. which declares the preview size must be smaller than the actual active array size.
In this case, you might consider having a try/catch block while you are taking picture using the camera.
try {
takePicture();
} catch (IllegalArgumentException e) {
Toast.makeText(this, "Your phone is too old", Toast.LENGTH_SHORT).show();
}
Hope that helps.
I believe that this may happen in very old devices with small image sensors, although seems to me (only guessing) more like a mistake by the manufacturer when they implemented the camera2 legacy wrapper.
A solution could be that when you are resolving the optimal preview size, then also to take into account that such preview size it doesn't exceed the size specified by SENSOR_INFO_ACTIVE_ARRAY_SIZE, which can be queried in the CameraCharacteristics:
CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE

Android camera2 qr code reader

I have a fragment which is scanning for a qr code using camera2 API and zxing (google's zebra crossing) API, it works fine for all the phones, the problem is with this specific tablet NVIDIA SHIELD. It would just not find the qr in the image, tried a lot:
Smaller, bigger screen/image dimension.
All different camera settings like iso, contrast, lighter, darker.
Using all image formats like JPEG, YUV_422_888 ...
Using planes nr 0,1,2...
Sorry for such a big snippet of code, ask questions, will respond asap.
Here is my code:
public class FragmentDecoder extends Fragment
implements FragmentCompat.OnRequestPermissionsResultCallback {
private static boolean accessGranted = true;
private static boolean showingText = false;
private ImageView camera_guide_image;
private TextView decoderText;
private ImageButton flashButton;
private static final int MAX_PREVIEW_WIDTH = 1920;
private static final int MAX_PREVIEW_HEIGHT = 1080;
private int mSensorOrientation;
private boolean mFlashSupported;
private static final String TAG = FragmentDecoder.class.getName();
private final CameraCaptureSession.CaptureCallback mCaptureCallback =
new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
}
#Override
public void onCaptureProgressed(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request,
#NonNull CaptureResult partialResult) {
process(partialResult);
}
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
process(result);
}
};
private final TextureView.SurfaceTextureListener mSurfaceTextureListener =
new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
};
private QRCodeReader mQrReader;
private String mCameraId;
private AutoFitTextureView mTextureView;
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Image img = null;
Result rawResult = null;
try {
img = reader.acquireLatestImage();
if (img == null) throw new NullPointerException("cannot be null");
ByteBuffer buffer = img.getPlanes()[0].getBuffer();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
int width = img.getWidth();
int height = img.getHeight();
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
rawResult = mQrReader.decode(bitmap);
if (rawResult == null) {
throw new NullPointerException("no QR code");
}
String decoded = rawResult.getText();
if (accessGranted) {
Log.e(TAG, "entered the accessGranted area!");
accessGranted = false;
boolean isPrivKey = BRWalletManager.getInstance(getActivity()).confirmSweep(getActivity(), decoded);
if (isPrivKey) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
BRAnimator.hideDecoderFragment();
}
});
return;
}
String validationString = validateResult(decoded);
if (Objects.equals(validationString, BRConstants.TEXT_EMPTY)) {
onQRCodeRead((MainActivity) getActivity(), rawResult.getText());
} else {
if (!showingText) {
showingText = true;
setCameraGuide(BRConstants.CAMERA_GUIDE_RED);
setGuideText(validationString);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
showingText = false;
}
}, 1000);
}
accessGranted = true;
}
}
} catch (ReaderException | NullPointerException | IllegalStateException ignored) {
if (!showingText)
setCameraGuide(BRConstants.CAMERA_GUIDE);
// Log.e(TAG, "Reader shows an exception! ", ignored);
/* Ignored */
} finally {
mQrReader.reset();
if (img != null)
img.close();
}
if (rawResult == null) {
if (!showingText)
setCameraGuide(BRConstants.CAMERA_GUIDE);
}
}
};
private CameraCaptureSession mCaptureSession;
private CameraDevice mCameraDevice;
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice cameraDevice) {
// This method is called when the camera is opened. We start camera preview here.
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
getActivity().onBackPressed();
}
};
private Size mPreviewSize;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private ImageReader mImageReader;
private CaptureRequest.Builder mPreviewRequestBuilder;
private CaptureRequest mPreviewRequest;
private final Semaphore mCameraOpenCloseLock = new Semaphore(1);
private int flashButtonCount;
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
List<Size> bigEnough = new ArrayList<>();
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
// Pick the smallest of those big enough. If there is no one big enough, pick the
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_decoder, container, false);
mQrReader = new QRCodeReader();
mTextureView = new AutoFitTextureView(getActivity());
RelativeLayout layout = (RelativeLayout) rootView.findViewById(R.id.fragment_decoder_layout);
camera_guide_image = (ImageView) rootView.findViewById(R.id.decoder_camera_guide_image);
decoderText = (TextView) rootView.findViewById(R.id.decoder_text);
flashButton = (ImageButton) rootView.findViewById(R.id.button_flash);
flashButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
if (mPreviewRequestBuilder == null || mCaptureSession == null)
return;
if (++flashButtonCount % 2 != 0) {
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null);
flashButton.setBackgroundResource(R.drawable.flash_on);
SpringAnimator.showAnimation(flashButton);
} else {
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null);
flashButton.setBackgroundResource(R.drawable.flash_off);
SpringAnimator.showAnimation(flashButton);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
});
layout.addView(mTextureView, 0);
startBackgroundThread();
return rootView;
}
#Override
public void onResume() {
super.onResume();
accessGranted = true;
showingText = false;
new Handler().post(new Runnable() {
#Override
public void run() {
if (camera_guide_image != null)
SpringAnimator.showExpandCameraGuide(camera_guide_image);
}
});
((BreadWalletApp) getActivity().getApplication()).hideKeyboard(getActivity());
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
#Override
public void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
private void setUpCameraOutputs(int width, int height) {
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}
// For still image captures, we use the largest available size.
Size largest = Collections.max(
Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)),
new CompareSizesByArea());
mImageReader = ImageReader.newInstance(largest.getWidth()/2, largest.getHeight()/2,
ImageFormat.YUV_420_888, /*maxImages*/2);
mImageReader.setOnImageAvailableListener(
mOnImageAvailableListener, mBackgroundHandler);
// Find out if we need to swap dimension to get the preview size relative to sensor
// coordinate.
int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
//noinspection ConstantConditions
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
swappedDimensions = true;
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
swappedDimensions = true;
}
break;
default:
Log.e(TAG, "Display rotation is invalid: " + displayRotation);
}
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
int rotatedPreviewWidth = width;
int rotatedPreviewHeight = height;
int maxPreviewWidth = displaySize.x;
int maxPreviewHeight = displaySize.y;
if (swappedDimensions) {
rotatedPreviewWidth = height;
rotatedPreviewHeight = width;
maxPreviewWidth = displaySize.y;
maxPreviewHeight = displaySize.x;
}
if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
maxPreviewWidth = MAX_PREVIEW_WIDTH;
}
if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
}
// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
maxPreviewHeight, largest);
// We fit the aspect ratio of TextureView to the size of preview we picked.
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(
mPreviewSize.getWidth(), mPreviewSize.getHeight());
} else {
mTextureView.setAspectRatio(
mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
// Check if the flash is supported.
Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mFlashSupported = available == null ? false : available;
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera(int width, int height) {
setUpCameraOutputs(width, height);
configureTransform(width, height);
CameraManager manager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
if (mCameraId != null)
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
if (mCaptureSession != null) {
mCaptureSession.close();
mCaptureSession = null;
}
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
if (mImageReader != null) {
mImageReader.close();
mImageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void stopBackgroundThread() {
try {
mBackgroundThread.quitSafely();
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException | NullPointerException e) {
e.printStackTrace();
mBackgroundThread = null;
mBackgroundHandler = null;
}
}
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface surface = new Surface(texture);
Surface mImageSurface = mImageReader.getSurface();
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(mImageSurface);
mPreviewRequestBuilder.addTarget(surface);
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(mImageSurface, surface),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
// Log.e(TAG, "onConfigured");
if (mCameraDevice == null) return;
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CONTROL_AF_MODE, CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.failed),
Toast.LENGTH_SHORT).show();
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void configureTransform(int viewWidth, int viewHeight) {
if (mTextureView == null || mPreviewSize == null) return;
int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
}
mTextureView.setTransform(matrix);
}
private static synchronized void onQRCodeRead(final MainActivity app, final String text) {
app.runOnUiThread(new Runnable() {
#Override
public void run() {
if (text != null) {
BRAnimator.hideDecoderFragment();
Log.e(TAG, "BEFORE processRequest");
RequestHandler.processRequest(app, text);
}
}
});
}
private static class CompareSizesByArea implements Comparator<Size> {
#Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
private int getStatusBarHeight() {
Rect rectangle = new Rect();
Window window = getActivity().getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
int statusBarHeight = rectangle.top;
int contentViewTop =
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight = contentViewTop - statusBarHeight;
return statusBarHeight + titleBarHeight;
}
private String validateResult(String str) {
RequestObject obj = null;
try {
obj = RequestHandler.getRequestFromString(str);
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
if (obj == null) {
return getActivity().getResources().getString(R.string.fragmentdecoder_not_a_bitcoin_qr_code);
}
if (obj.r != null) {
return BRConstants.TEXT_EMPTY;
}
if (obj.address != null) {
if (BRWalletManager.validateAddress(obj.address)) {
return BRConstants.TEXT_EMPTY;
} else {
return getActivity().getResources().getString(R.string.fragmentdecoder_not_valid_bitcoin_address);
}
}
return getActivity().getResources().getString(R.string.fragmentdecoder_not_a_bitcoin_qr_code);
}
private void setCameraGuide(final String str) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (str.equalsIgnoreCase(BRConstants.CAMERA_GUIDE)) {
camera_guide_image.setImageResource(R.drawable.cameraguide);
setGuideText(BRConstants.TEXT_EMPTY);
} else if (str.equalsIgnoreCase(BRConstants.CAMERA_GUIDE_RED)) {
camera_guide_image.setImageResource(R.drawable.cameraguide_red);
} else {
throw new IllegalArgumentException("CAMERA_GUIDE and CAMERA_GUIDE_RED only");
}
}
});
}
private void setGuideText(final String str) {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
decoderText.setText(str);
}
});
}
}

How can I show image taken from camera

I'm trying to write an android app, that works with the camera.
I show a preview of the camera in a textureview, that is working. If you press a button the camera will take a picture and show it on an imageview on the second half of the screen.
But everytime I press the button my app stops working, it tells me the error
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
So I looked it up, and it seems I can't change the image of the imageview as I try to. But I don't know how else I could solve my problem. Can you give me some advise? Here is my code: The image is changed in the "ImageReader.OnImageAvailableListener" in the method takePicture().
public class MainActivityOld extends Activity {
private TextureView mTextureView;
private ImageView mImageView;
private CameraDevice mCameraDevice;
private Size mPreviewSize;
private CaptureRequest.Builder mPreviewBuilder;
private CameraCaptureSession mPreviewSession;
private Button mBtnShot;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//no titlebar
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
mTextureView = (TextureView) findViewById(R.id.texture);
mTextureView.setSurfaceTextureListener(mSurfaceListener);
mImageView = (ImageView) findViewById(R.id.lastPicture);
mBtnShot = (Button) findViewById(R.id.btn_takepicture);
mBtnShot.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
takePicture();
}
});
}
private void takePicture() {
Log.e("MyTag", "Take picture");
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());
Size[] jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
int width = jpegSizes[0].getWidth();
int 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(mTextureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){
#Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mImageView.setImageBitmap(bitmap);
}
};
HandlerThread thread = new HandlerThread("CameraPicture");
thread.start();
final Handler backgroundHandler = new Handler(thread.getLooper());
reader.setOnImageAvailableListener(readerListener,backgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
startPreview();
}
};
mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];
manager.openCamera(cameraId, mStateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e("MyTag", "openCamera");
}
private TextureView.SurfaceTextureListener mSurfaceListener = new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Log.e("myLog", "onSurfaceTextureAvailable, width=" + width + ",height=" + 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 mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice camera) {
Log.e("myTag", "onOpened");
mCameraDevice = camera;
startPreview();
}
#Override
public void onDisconnected(CameraDevice camera) {
Log.e("myTag", "onDisconnected");
}
#Override
public void onError(CameraDevice camera, int error) {
Log.e("myTag", "onDisconnected");
}
};
protected void startPreview() {
if (mCameraDevice == null || mTextureView.isAvailable() || mPreviewSize == null) {
Log.e("MyTag", "startPreview failed, still working, so just ignore it");
// return;
}
SurfaceTexture texture = mTextureView.getSurfaceTexture();
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface surface = new Surface(texture);
try {
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
} catch (CameraAccessException e) {
e.printStackTrace();
}
mPreviewBuilder.addTarget(surface);
try {
mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
mPreviewSession = session;
updatePreview();
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
Toast.makeText(MainActivityOld.this, "onConfigureFailed", Toast.LENGTH_LONG).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
protected void updatePreview() {
mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
HandlerThread thread = new HandlerThread("CameraPreview");
thread.start();
Handler backgroundHandler = new Handler(thread.getLooper());
try {
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
As the Exception says CalledFromWrongThreadException, your readerListener is working on another thread, from where you cannot change your views.
Change your code to:
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){
#Override
public void onImageAvailable(final ImageReader reader) {
MainActivityOld.this.runOnUIThread(new Runnable() {
#Override
public void run() {
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mImageView.setImageBitmap(bitmap);
}
});
}
};
I think you will be better of trying to stream to a surface view, not sure if this can even be done with a imageview.
try this tutorial it should get you going in the right direction
or this for a more up to date example provided by google

Categories

Resources