I have an android application that takes a photo and then displays the image. On my device, which I originally developed the app on, the image capture behaves as expected. However, when I have tried running it on other devices, on some devices it seems that the image is rotated 90 degrees. I have been able to determine that this is not an issue with the image preview, and that the image itself is rotated. The code for the image capture is here:
public void takePicture(){
if(null == cameraDevice) {
return;
}
try {
System.out.println("Taking Picture");
getCameraCharacteristics();
ImageReader reader = ImageReader.newInstance(1920, 1440, ImageFormat.JPEG, 1);
//ImageReader reader = ImageReader.newInstance(camera_width, camera_height, ImageFormat.RAW_SENSOR, 1);
List<Surface> outputSurfaces = buildOutputSurfaces(reader);
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 rotation = parent.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
ImageReader.OnImageAvailableListener readerListener = reader1 -> getImageFromBuffer(reader1);
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);
}
catch (CameraAccessException e) {
e.printStackTrace();
}
}
Regardless of device, the value for rotation is always 0. I have tried manually setting the JPEG_ORIENTATION to different values, but it does not seem to make a difference.
I have seen other StackOverflow questions with similar issues, but the fixes in those questions did not seem to make a difference here.
Can anyone suggest what might be causing this?
EDIT: to add some more details to the requirements for the app. The issue isn't just with displaying the image but with handling it afterwards. The user has to select a point in the image and then pair of point and image are sent to a server for processing. As a result, I need to orientation of the underlying image to be consistent between devices, its not enough to simply compensate when displaying the image.
Unfortunately I cant switch my application over to using a CameraIntent for image capture, as the application needs to be able to observe behaviour during photo capture and provide continuous feedback.
Use Glide to load and display your taken picture:
Glide.with(context).load(imageUri).into(imageView)
Demo:
https://youtu.be/tPwr2yYxlA4
Helpful reading:
Captured image will be displayed horizontally:
https://stackoverflow.com/a/47630783/3466808
Okay, I found a solution to this issue from a blogpost here. Essentially rather than relying on setting the JPEG rotation in the capture builder, you compute it yourself and incorporate the sensor data to determine how many degrees you have to rotate the image by.
// Orientation
int deviceRotation = parent.getWindowManager().getDefaultDisplay().getRotation();
int surfaceRotation = ORIENTATIONS.get(deviceRotation);
jpegOrientation = (surfaceRotation + sensorOrientation + 270) % 360;
I then decode the image into a bitmap, rotate it by the computed value, and then encoded it back into a ByteArray.
Related
Issue:-
Camera Preview different from Image Captured using Camera2 Api. And the problem occurs only in landscape mode.
Requirement:-
My requirement is to capture an image in landscape mode using camera2 api.Camera Preview should be in full screen.
I have followed the following github sample :-
https://github.com/googlesamples/android-Camera2Basic
This sample works fine in portrait mode as well as in landscape mode if Texture View is wrap_content as the aspect ratio is maintained.
But to display the camera preview in full screen, i changed TextureView to match_parent. By doing that the output got changed. Now preview of camera is different from the image captured.
Please check the images attached here.
1.Camera Preview:-Screenshot of camera preview
2.Image Captured:-On Tapping Picture button
Following is my code snippet:-
fragment_camera2_basic.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.android.camera2basic.AutoFitTextureView
android:id="#+id/texture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<FrameLayout
android:id="#+id/control"
android:layout_width="match_parent"
android:layout_height="112dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:background="#color/control_background">
<Button
android:id="#+id/picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/picture" />
<ImageButton
android:id="#+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:padding="20dp"
android:src="#drawable/ic_action_info" />
</FrameLayout>
</RelativeLayout>
Following is the code to capture image:-
/**
* Initiate a still image capture.
*/
private void takePicture() {
lockFocus();
}
/**
* Lock the focus as the first step for a still image capture.
*/
private void lockFocus() {
try {
// This is how to tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_START);
// Tell #mCaptureCallback to wait for the lock.
mState = STATE_WAITING_LOCK;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* Run the precapture sequence for capturing a still image. This method should be called when
* we get a response in {#link #mCaptureCallback} from {#link #lockFocus()}.
*/
private void runPrecaptureSequence() {
try {
// This is how to tell the camera to trigger.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
// Tell #mCaptureCallback to wait for the precapture sequence to be set.
mState = STATE_WAITING_PRECAPTURE;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* Capture a still picture. This method should be called when we get a response in
* {#link #mCaptureCallback} from both {#link #lockFocus()}.
*/
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// Orientation
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.abortCaptures();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* Retrieves the JPEG orientation from the specified screen rotation.
*
* #param rotation The screen rotation.
* #return The JPEG orientation (one of 0, 90, 270, and 360)
*/
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;
}
/**
* Unlock the focus. This method should be called when still image capture sequence is
* finished.
*/
private void unlockFocus() {
try {
// Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
setAutoFlash(mPreviewRequestBuilder);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
// After this, the camera will go back to the normal state of preview.
mState = STATE_PREVIEW;
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
I tried to set CaptureRequest.SCALER_CROP_REGION in camera preview builder and image reader as well but it did not work as expected.
The TextureView is probably partially outside the display, in terms of the layout.
So it's being cut off.
You may want to confirm that with Android Studio's layout tools
In general, you can't get identical images unless you match aspect ratios, so if you want full-screen preview, you'll have to select a JPEG aspect ratio that matches the screen.
That may not available directly from the camera, so you may need to crop the JPEG yourself. But most likely you can at least get 16:9 preview and still capture relatively easily, which will have relatively small black bars, compared to the 4:3 maximum still capture size.
I'm unable to get the touch to focus to work properly on Camera2 API. On touching I just seem to focus for a second and then it becomes extremely blurred. The phone is a Nexus 5X. Here is my code for touch to focus.
private void refocus(MotionEvent event, View view){
//Handler for autofocus callback
CameraCaptureSession.CaptureCallback captureCallbackHandler = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
if (request.getTag() == "FOCUS_TAG") {
//the focus trigger is complete -
//resume repeating (preview surface will get frames), clear AF trigger
previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, null);
try{
mSession.setRepeatingRequest(previewRequest.build(), null, null);}
catch (Exception e){
}
}
}
#Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Log.e(TAG, "Manual AF failure: " + failure); }
};
try {
final Rect sensorArraySize = manager.getCameraCharacteristics(mCameraDevice.getId()).get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
//Find area size
int x = (int)(event.getX()/(float)view.getWidth() * (float)sensorArraySize.width());
int y = (int)(event.getY()/(float)view.getHeight() * (float)sensorArraySize.height());
final int halfTouchWidth = 150; //(int)motionEvent.getTouchMajor(); //TODO: this doesn't represent actual touch size in pixel. Values range in [3, 10]...
final int halfTouchHeight = 150; //(int)motionEvent.getTouchMinor();
MeteringRectangle rect = new MeteringRectangle(Math.max(x - halfTouchWidth, 0),
Math.max(y - halfTouchHeight, 0),
halfTouchWidth * 2,
halfTouchHeight * 2,
MeteringRectangle.METERING_WEIGHT_MAX - 1);
mSession.stopRepeating();
transparentLayer.drawFeedback(rect);
//Cancel requests
previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
previewRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
mSession.capture(previewRequest.build(), captureCallbackHandler, null);
//Now add a new AF trigger with focus region
if (isMeteringAreaAFSupported()) {
previewRequest.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{rect});
}
previewRequest.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
previewRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
previewRequest.setTag("FOCUS_TAG"); //we'll capture this later for resuming the preview
//then we ask for a single request (not repeating!)
mSession.capture(previewRequest.build(), captureCallbackHandler, null);
}catch (Exception e){
e.printStackTrace();
}
}
Also have another helper function:
private boolean isMeteringAreaAFSupported() {
try {
return manager.getCameraCharacteristics(mCameraDevice.getId()).get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) >= 1;
}catch (Exception e){
return false;
}
}
What could be the possible reason for the focus working for a brief second, and then restarting, or getting completely blurry? There is no solution that I can find which is helpful.
Thanks all!
I would try setting AF_TRIGGER to IDLE in onCaptureCompleted - removing it entirely isn't totally well-specified.
Beyond that, it's not clear to me how you're converting from the screen touch coordinates to the camera active array coordinates for the metering regions. It looks like you're assuming the coordinates are identical, which isn't true. That shouldn't cause blurriness, but will cause you to focus on a different area than you think.
You need to scale the x and y correctly (based on the current crop region which defines the visible field of view when using digital zoom, and the active array rectangle)
This is how I instantiate the ImageReader.
Size[] sizes = configs.getOutputSizes(ImageFormat.YUV_420_888);
mImageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null);
Surface rgbCaptureSurface = mImageReader.getSurface();
List<Surface> surfaces = new ArrayList<Surface>();
surfaces.add(rgbCaptureSurface);
//surfaces.add(surface);
mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
//mPreviewRequestBuilder.addTarget(surface);
mPreviewRequestBuilder.addTarget(rgbCaptureSurface);
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO);
// Flash is automatically enabled when necessary.
//setAutoFlash(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
Reading is done like this:
public void onImageAvailable(ImageReader reader) {
Image image;
while (true) {
image = reader.acquireLatestImage();
if (image == null) return;
Image.Plane Y = image.getPlanes()[0];
Image.Plane U = image.getPlanes()[1];
Image.Plane V = image.getPlanes()[2];
int Yb = Y.getBuffer().remaining();
int Ub = U.getBuffer().remaining();
int Vb = V.getBuffer().remaining();
byte[] data = new byte[Yb + Ub + Vb];
Y.getBuffer().get(data, 0, Yb);
U.getBuffer().get(data, Yb, Ub);
V.getBuffer().get(data, Yb + Ub, Vb);
I tried several different ImageFormats. I'm testing on LG G3, API 21 and the problem occurs.On Nexus 4 I do not have the problem, API 22.
I upgraded to API 23 and the same code worked fine. Also tested on API 22 and it also worked.
Same as : Using Camera2 API with ImageReader
Your observation is correct. API 21 does not properly support Camera2. This has been found by several people independently here on SO, see e.g. Camera2 API21 not working
So it is reasonable to start using Camera2 not before API22. It is not understandable why documentation hasn't been amended in the meantime.
Personally I am continuing to perform Camera2 studies, but I am still reluctant to use Camera2 in my app now. I first want to test it on many many devices first and for the near future I don't expect "Camera1" not being supported anymore by new devices.
How to enable front camera on Camera2 API.Can anyone help ? I have this Camera2 API code .This only sets Main camera of the device ,I want to enable both front and rear camera on a button click.What is LENS_FACING_FRONT,I am new to android programming.
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.JPEG)),
new CompareSizesByArea());
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
ImageFormat.JPEG, /*maxImages*/2);
mImageReader.setOnImageAvailableListener(
mOnImageAvailableListener, mBackgroundHandler);
// 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),
width, height, 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());
}
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (NullPointerException e) {
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
ErrorDialog.newInstance(getString(R.string.camera_error))
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
}
}
We can use CameraManager to iterate all the cameras that are available in the system, each with a designated cameraId. Using the cameraId, we can get the properties of the specified camera device. Those properties are represented by class CameraCharacteristics. Things like "is it front or back camera", "output resolutions supported" can be queried there.
You can get official sample application here
This example found in Google Git repo will demo for you checking the permission before launching camera in new Marshmallow using Camera2 API
Give a look at this article for more about it.
I'm working on an android app that is processing the input image from the camera and displays it to the user. This is fairly simple, I register a PreviewCallback on the camera object with the setPreviewCallbackWithBuffer.
This is easy and works smoothly with the old camera API
public void onPreviewFrame(byte[] data, Camera cam) {
// custom image data processing
}
I'm trying to port my app to take advantage of the new Camera2 API and I'm not sure how exactly shall I do that. I followed the Camera2Video in L Preview samples that allows to record a video. However, there is no direct image data transfer in the sample, so I don't understand where exactly shall I get the image pixel data and how to process it.
Could anybody help me or suggest the way how one can get the the functionality of PreviewCallback in android L, or how it's possible to process preview data from the camera before displaying it to the screen? (there is no preview callback on the camera object)
Thank you!
Combining a few answers into a more digestible one because #VP's answer, while technically clear, is difficult to understand if it's your first time moving from Camera to Camera2:
Using https://github.com/googlesamples/android-Camera2Basic as a starting point, modify the following:
In createCameraPreviewSession() init a new Surface from mImageReader
Surface mImageSurface = mImageReader.getSurface();
Add that new surface as a output target of your CaptureRequest.Builder variable. Using the Camera2Basic sample, the variable will be mPreviewRequestBuilder
mPreviewRequestBuilder.addTarget(mImageSurface);
Here's the snippet with the new lines (see my #AngeloS comments):
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());
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
//#AngeloS - Our new output surface for preview frame data
Surface mImageSurface = mImageReader.getSurface();
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
//#AngeloS - Add the new target to our CaptureRequest.Builder
mPreviewRequestBuilder.addTarget(mImageSurface);
mPreviewRequestBuilder.addTarget(surface);
...
Next, in setUpCameraOutputs(), change the format from ImageFormat.JPEG to ImageFormat.YUV_420_888 when you init your ImageReader. (PS, I also recommend dropping your preview size for smoother operation - one nice feature of Camera2)
mImageReader = ImageReader.newInstance(largest.getWidth() / 16, largest.getHeight() / 16, ImageFormat.YUV_420_888, 2);
Finally, in your onImageAvailable() method of ImageReader.OnImageAvailableListener, be sure to use #Kamala's suggestion because the preview will stop after a few frames if you don't close it
#Override
public void onImageAvailable(ImageReader reader) {
Log.d(TAG, "I'm an image frame!");
Image image = reader.acquireNextImage();
...
if (image != null)
image.close();
}
Since the Camera2 API is very different from the current Camera API, it might help to go through the documentation.
A good starting point is camera2basic example. It demonstrates how to use Camera2 API and configure ImageReader to get JPEG images and register ImageReader.OnImageAvailableListener to receive those images
To receive preview frames, you need to add your ImageReader's surface to setRepeatingRequest's CaptureRequest.Builder.
Also, you should set ImageReader's format to YUV_420_888, which will give you 30fps at 8MP (The documentation guarantees 30fps at 8MP for Nexus 5).
In the ImageReader.OnImageAvailableListener class, close the image after reading as shown below (this will release the buffer for next capture). You will have to handle exception on close
Image image = imageReader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
image.close();
I needed the same thing, so I used their example and added a call to a new function when the camera is in preview state.
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback()
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
if (buttonPressed){
savePreviewShot();
}
break;
}
The savePreviewShot() is simply a recycled version of the original captureStillPicture() adapted to use the preview template.
private void savePreviewShot(){
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureBuilder.addTarget(mImageReader.getSurface());
// Orientation
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
TotalCaptureResult result) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss:SSS");
Date resultdate = new Date(System.currentTimeMillis());
String mFileName = sdf.format(resultdate);
mFile = new File(getActivity().getExternalFilesDir(null), "pic "+mFileName+" preview.jpg");
Log.i("Saved file", ""+mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (Exception e) {
e.printStackTrace();
}
};
It's better to init ImageReader with max image buffer is 2 then use reader.acquireLatestImage() inside onImageAvailable().
Because acquireLatestImage() will acquire the latest Image from the ImageReader's queue, dropping older one. This function is recommended to use over acquireNextImage() for most use-cases, as it's more suited for real-time processing. Note that max image buffer should be at least 2.
And remember to close() your image after processing.