i was reading about many reports about this, but still couldn't find the answer for me.
Sometimes, after capturing with camera2, an exception is throwing: java.lang.IllegalStateException: Session has been closed; further changes are illegal.
I tried to check all the sessions not being null, when was doing something, but still get this.
Any suggestion ? anything else should i handle?=, which i didn't ?
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
if(touchFocusEnabled) {
letSetCaptureSessionOnce = true;
mState = STATE_WAITING_LOCK;
try {
// Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mHandler);
} catch (CameraAccessException e) {
L.e("CameraLolipop --- CameraCaptureSession.CaptureCallback " + e);
}
} else {
if(letSetCaptureSessionOnce) {
try {
if ((null != mCaptureSession) && (isCameraOpen)) {
mState = STATE_PREVIEW;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mHandler);
letSetCaptureSessionOnce = true;
}
} catch (CameraAccessException e) {
L.e("CameraLolipop --- CameraCaptureSession.CaptureCallback " + e);
}
}
}
break;
}
case STATE_WAITING_LOCK: {
if(touchFocusEnabled) {
mState = STATE_PICTURE_TAKEN;
touchFocusEnabled = false;
try {
if((mCaptureSession != null) && (isCameraOpen)){
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mHandler);
}
} catch (CameraAccessException e) {
L.e("CameraLolipop --- STATE_WAITING_LOCK " + e);
}
return;
}
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
L.d("Focus state ", "STATE_WAITING_LOCK");
boolean fixedFocus = isFixedFocus();
if (afState == null) {
// if ((burstMode) && (getSupportedHardwareLevel() == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
// captureStillPictureBurst();
// } else {
captureStillPicture();
// }
} else if ((CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) || fixedFocus) {
L.d("Focus state ", "CONTROL_AF_STATE_FOCUSED_LOCKED or CONTROL_AF_STATE_NOT_FOCUSED_LOCKED");
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
if ((burstMode) && (getSupportedHardwareLevel() == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
// captureStillPictureBurst();
captureStillPicture();
} else {
captureStillPicture();
}
} else {
runPrecaptureSequence();
}
}
break;
}
case STATE_WAITING_PRECAPTURE: {
L.d("Focus state ", "STATE_WAITING_PRECAPTURE");
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED || isFixedFocus()) {
mState = STATE_WAITING_NON_PRECAPTURE;
}
break;
}
case STATE_WAITING_NON_PRECAPTURE: {
L.d("Focus state ", "STATE_WAITING_NON_PRECAPTURE");
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_PICTURE_TAKEN;
if ((burstMode) && (getSupportedHardwareLevel() == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
// captureStillPictureBurst();
captureStillPicture();
} else {
captureStillPicture();
}
}
break;
}
case STATE_PICTURE_TAKEN: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
L.d("TOUCH", " afState " + afState);
mState = STATE_PREVIEW;
if(afState == 4) {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
}
if(afState == 0) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mPreviewRequestBuilder
.set(CaptureRequest.CONTROL_AF_REGIONS, null);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
}
}, 2500);
}
break;
}
}
}
#Override
public void onCaptureProgressed(CameraCaptureSession session,
CaptureRequest request,
CaptureResult partialResult) {
super.onCaptureProgressed(session, request, partialResult);
// process(partialResult);
}
#Override
public void onCaptureCompleted(CameraCaptureSession session,
CaptureRequest request,
TotalCaptureResult result) {
// if ((mState != STATE_PREVIEW) || (touchFocusEnabled)) {
super.onCaptureCompleted(session, request, result);
if(session != null) {
process(result);
}
}
};
and here is where session is being created:
private CameraCaptureSession.StateCallback mSessionPreviewStateCallback = new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
L.i("Thread", "onConfigured---->" + Thread.currentThread().getName());
// The camera is already closed
if(null == mCameraDevice) {
return;
}
try {
mCaptureSession = cameraCaptureSession;
mCameraSessionIsClosed = false;
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
if((isCameraOpen) && (mCaptureSession != null)){
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mHandler);
}
L.d("ex0003", "Test... mSessionPreviewStateCallback ");
} catch (CameraAccessException e) {
L.e("CameraLolipop --- openCamera() " + e);
}
}
#Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Toast.makeText(getActivity(), "onConfigureFailed---Preview", Toast.LENGTH_SHORT).show();
}
};
and in onPause closeCamera() is being called:
try {
if(mCameraDevice == null && mCameraIsClosed) {
return;
}
if((mCaptureSession != null) && (isCameraOpen)) {
try {
mCaptureSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
mCameraOpenCloseLock.acquire();
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
mCameraSessionIsClosed = true;
}
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
isCameraOpen = false;
mCameraIsClosed = true;
}
if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}
and after stopBackgroundThread() and super.onPause() are being called.
In my case problem was createCaptureRequest being called multiple when another is already in process(onConfigured/onConfigureFailed called). What I end up was creating a boolean variable that keeps track if camera_preview is already in process, if so then do not make another createCaptureRequest.
Check if all the camera configurations have been set with a flag, as #Rohit suggested or give some delay to the repeatingRequest of your mCaptureSession while it setting the configuration for you in parallel in the background. In my case I solved this exception by giving a delay of 500 mS to set the repeatingRequest like this:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
try {
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
mCaptureCallback, null);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to start camera preview because it couldn't access camera", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Failed to start camera preview.", e);
}
}
}, 500);
Also, the same problem occurs when you first time grant permissions and initially start your camera preview(app crashes), but there you will get CameraAccessException stating "Failed to start camera session". In that case, you should give the same amount of delay while creating capture sessions like below:
void startCaptureSession() {
if (!isCameraOpened() || !mPreview.isReady() || mImageReader == null) {
return;
}
previewSize = chooseOptimalSize();
mPreview.setBufferSize(previewSize.getWidth(), previewSize.getHeight());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
try {
Surface surface = mPreview.getSurface();
mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
mSessionCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
throw new RuntimeException("Failed to start camera session");
}
}
}, 500);
}
I hope it helps.
In the documentation it says:
if this session is no longer active, either because the session was explicitly closed, a new session has been created or the camera device has been closed.
If you are using the camera2api sample-project, this means: You either call openCamera(), createCameraPreviewSession() or closeCamera() while another createCameraPreviewSession() was called aswell.
I solved this with a global variable, that is always set to true, when the function createCameraPreviewSession() is called; and is set to false, 10MS after createCameraPreviewSession() was finished. If this variable is true, I block all new createCameraPreviewSession() calls and also all closeCamera() calls.
This solution worked for me. However, I don't know if there is a fundamental reason, why you should not use this. If somebody knows better, please let me know.
I'm not sure if this will work, but try it and let me know if it worked.
private CameraCaptureSession.StateCallback mSessionPreviewStateCallback = new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
L.i("Thread", "onConfigured---->" + Thread.currentThread().getName());
// The camera is already closed
if(null == mCameraDevice) {
return;
}
try {
mCaptureSession = cameraCaptureSession;
mCameraSessionIsClosed = false;
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
if((isCameraOpen) && (mCaptureSession != null)){
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mHandler);
}
L.d("ex0003", "Test... mSessionPreviewStateCallback ");
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to start camera preview because it couldn't access camera", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Failed to start camera preview.", e);
}
}
#Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Toast.makeText(getActivity(), "onConfigureFailed---Preview", Toast.LENGTH_SHORT).show();
}
#Override
public void onClosed(#NonNull CameraCaptureSession session) {
if (mCaptureSession != null && mCaptureSession.equals(session)) {
mCaptureSession = null;
}
}
};
This error occurs if the camera is opened before setting all the configuration to the preview request builder. Hence you must first set all the parameters like the TextureView size, camera output size etc.
Here is code from google's sample app:
setUpCameraOutputs(width, height);
configureTransform(width, height);
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
Related
I am not able to get a constant framerate with the camera2 API using MediaRecorder on the Galaxy S9 front camera.
Essentially I am using the example Project from https://github.com/googlesamples/android-Camera2Video but stripped it down to find the error. I removed the mTextureView and use only the mediaRecorder surface.
Here are the relevant code snippets:
#Override
protected void setUpMediaRecorder() throws IOException {
final Activity activity = getActivity();
if (null == activity) {
return;
}
// Camcorder Profile QUALITY_HIGH doenst work
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncodingBitRate(30000000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(2560, 1440);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.prepare();
}
#Override
protected void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
Range<Integer> range = getRange();
builder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, range);
}
// get highest range
private Range<Integer> getRange() {
CameraManager mCameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics chars = null;
try {
chars = mCameraManager.getCameraCharacteristics(mCameraManager.getCameraIdList()[1]);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Range<Integer>[] ranges = chars.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
Range<Integer> result = null;
for (Range<Integer> range : ranges) {
if (result == null) {
result = range;
} else {
int upper = range.getUpper();
int lower = range.getLower();
if (upper >= result.getUpper() && lower >= result.getLower()) {
result = range;
}
}
}
return result;
}
protected void startRecordingVideo() {
if (null == mCameraDevice) {
return;
}
try {
closeCaptureSession();
setUpMediaRecorder();
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
List<Surface> surfaces = new ArrayList<>();
// Set up Surface for the MediaRecorder
Surface recorderSurface = mMediaRecorder.getSurface();
surfaces.add(recorderSurface);
mPreviewBuilder.addTarget(recorderSurface);
// Start a capture session
// Once the session starts, we can update the UI and start recording
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
mCaptureSession = cameraCaptureSession;
setUpCaptureRequestBuilder(mPreviewBuilder);
if (null == mCameraDevice) {
return;
}
try {
mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// UI
mButtonVideo.setText(R.string.stop);
mIsRecordingVideo = true;
// Start recording
mMediaRecorder.start();
}
});
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Activity activity = getActivity();
if (null != activity) {
Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}
}
}, mBackgroundHandler);
} catch (CameraAccessException | IOException e) {
e.printStackTrace();
}
}
getRange() returns a Range of [30,30]. So it should record at 30fps. If I move the camera to some darker areas the frame rate suddenly drops. If locking the AE while moving to a light area the framerate is stable, even in dark areas.
So it seems to have something to do with AE but can not figure out what. Any help?
I have a camera app. My problem is that when i'm recording and the app goes in bacground the file that mediarecorder had is void. I want to save the file is saved first. I have tried the same code that i use when a click the stop button, but it does not work.
Any suggestions?
This is my onPause() method
#Override
public void onPause() {
if (isRecording) {
stopRecordingVideo();
Log.d("YUI", "true");
fileQueue.addToQueue(mCurrentFile);
} else {
Log.d("YUI", "false");
mMediaRecorder = null;
closeCamera();
}
counter--;
stopBackgroundThread();
// if (mCurrentFile != null) {
// mCurrentFile.delete(); // delete empty file
// }
super.onPause();
}
public void stopRecordingVideo() {
stopRecordingVideo(false);
}
private void stopRecordingVideo(boolean kill) {
// UI
isRecording = false;
// Stop Recording
closeCamera();
if (!kill) {
openCamera(mCameraLayout.getWidth(), mCameraLayout.getHeight());
}
}
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
if (mPreviewSession != null) {
mPreviewSession.close();
mPreviewSession = null;
}
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
}
} catch (InterruptedException ie) {
Crashlytics.log("closeCamera error");
Crashlytics.logException(ie);
ie.printStackTrace();
getCam2Listener().onInterruptedException(ie);
throw new RuntimeException("Interrupted while trying to lock camera closing.");
} catch (Exception exc) {
Crashlytics.log("closeCamera error");
Crashlytics.logException(exc);
}
finally {
mCameraOpenCloseLock.release();
}
}
I need to use Camera2 API on my application. (Api21+)
I found the next sample:
https://github.com/googlesamples/android-Camera2Basic
I downloaded it and started on my phone. When I pressed the "Picture" Button, it's call the takePhoto method.
private void takePicture() {
lockFocus();
}
It is a State machine. Sometimes this machine stuck on STATE_WAITING_LOCK.
My device is waiting for Focus, but nothing happens! (Yes, my device is support auto focus)
case STATE_WAITING_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
} else {
runPrecaptureSequence();
}
}
break;
}
What is the good solution for this problem?
And this program sometimes crashed here:
private void unlockFocus() {
try {
// Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
setAutoFlash(mPreviewRequestBuilder);
/*HERE*/ 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();
}
}
Why can't focus my device?
It seems that your program stucks sometimes in CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED where according to documentation "The AF algorithm has been unable to focus. The lens is not moving." link
Try to cancel the AF_TRIGGER and start it again. Something like this:
if (afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
getRidOfNotFocusedLock();
}
And:
private void getRidOfNotFocusedLock(){
try {
mPreviewRequestBuilder.set(
CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
mCaptureSession.capture(
captureRequestBuilder.build(), captureSessionCaptureCallback, backgroundHandler);
mPreviewRequestBuilder.set(
CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
When I found Lautern's answer, I had to adjust it a little, as it wasn't working for me.
As the program stucks sometimes in CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED, you can try to restart the AF_TRIGGER:
if (afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
restartFocus();
}
private void restartFocus(){
try {
mPreviewRequestBuilder.set(
CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
mCaptureSession.capture(
captureRequestBuilder.build(),
captureSessionCaptureCallback,
mBackgroundHandler);
lockFocus();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void lockFocus() {
try {
mPreviewRequestBuilder.set(
CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_TRIGGER_START);
mState = STATE_WAIT_LOCK;
mCaptureSession.capture(
mPreviewRequestBuilder.build(),
mPreviewCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
As some time has passed, since I implemented this, I'm not entirely sure why I had to restart the capture session. But without it, it doesn't work for me.
I developed app with Camera2 api support. App provides preview on camera and do some realtime processing. On most devices everythings work fine. But On Samsung S5 mini I'm getting just 2 frames per second. I can't imagine why ?! Do you have any suggestions ?
EDIT:
Open previewing:
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);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Flash is automatically enabled when necessary.
mCameraInfo.setRequestParameters(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed - configure camera");
getActivity().finish();
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
Capture callback:
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
if(mOverlaySurfaceView.isImageBorderLocked()){
takePicture();
}
// We have nothing to do when the camera preview is working normally.
break;
}
case STATE_WAITING_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
} else {
runPrecaptureSequence();
}
}
else{
runPrecaptureSequence();
}
break;
}
case STATE_WAITING_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WAITING_NON_PRECAPTURE;
}
break;
}
case STATE_WAITING_NON_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
}
}
#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);
}
#Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
Log.e(LOG_TITLE, "Capture failed");
super.onCaptureFailed(session, request, failure);
}
};
Thank you for any help.
EDIT 2:
I found the reason of slow performance. In the preview mode I called mTextureView.getBitmap() inside onSurfaceTextureUpdated. This operation is too expensive. Because when new frame was arrived I constructed new Bitmap. I canceled this call and now is everything running smoothly.
guys who can give me an example how to use camera2 characteristics in android?
F.e. how to use CONTROL_EFFECT_MODE_SEPIA effect ?
Have tried to use characteristics.get(CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA), but it gave me an The method get(CameraCharacteristics.Key<T>) in the type CameraCharacteristics is not applicable for the arguments (int).
Thanks.
Neither first one nor second one didn't work for me. I am sure i am doing something wrong, so i want to show my code, and hope you can help me to find a solution.
#Override
public void openCamera() {
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "openCamera E");
try {
String cameraId = manager.getCameraIdList()[0];
characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];
Log.e(TAG, "Preview size is: " + mPreviewSize.toString());
manager.openCamera(cameraId, mStateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e(TAG, "openCamera X");
}
public void updatePreview() {
if(null == mCameraDevice) {
Log.e(TAG, "updatePreview error, return");
}
mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_OFF);
HandlerThread thread = new HandlerThread("CameraPreview");
thread.start();
backgroundHandler = new Handler(thread.getLooper());
try {
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void startPreview() {
if(null == mCameraDevice || !myTexture.isAvailable() || null == mPreviewSize) {
Log.e(TAG, "startPreview fail, return");
}
SurfaceTexture texture = myTexture.getSurfaceTexture();
if(null == texture) {
Log.e(TAG,"texture is null, return");
return;
}
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) {
Log.e(TAG,"onConfiguration failed.");
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice camera) {
Log.e(TAG, "onOpened");
mCameraDevice = camera;
startPreview();
}
#Override
public void onDisconnected(CameraDevice camera) {
Log.e(TAG, "onDisconnected");
}
#Override
public void onError(CameraDevice camera, int error) {
Log.e(TAG, "onError");
}
};
You need to set the effect mode in your CaptureRequest; CameraCharacteristics will tell you what effect modes are supported.
Roughly, use:
int[] supportedEffects = characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS);
int selectedEffect = supportedEffects[0]; // select effect you want here
requestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, selectedEffect);
captureSession.setRepeatingRequest(requestBuilder.build());
mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mPreviewBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_NEGATIVE);
mCameraCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), mPreviewSessionCallback, mHandler);
exaple:https://github.com/pinguo-yuyidong/Camera2/blob/master/app/src/main/java/us/yydcdut/androidltest/listener/EffectItemClickListener.java