am d782ce53: am 979c03a2: Merge "camera2: Avoid spurious IDLE transitions." into lmp-dev
* commit 'd782ce534d57c69cb280313b89180dac742937a8': camera2: Avoid spurious IDLE transitions.
This commit is contained in:
@@ -16,8 +16,8 @@
|
||||
|
||||
package android.hardware.camera2.legacy;
|
||||
|
||||
import android.hardware.camera2.impl.CameraDeviceImpl;
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.utils.CameraBinderDecorator;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -53,7 +53,7 @@ public class CameraDeviceState {
|
||||
"CAPTURING"};
|
||||
|
||||
private int mCurrentState = STATE_UNCONFIGURED;
|
||||
private int mCurrentError = CameraBinderDecorator.NO_ERROR;
|
||||
private int mCurrentError = NO_CAPTURE_ERROR;
|
||||
|
||||
private RequestHolder mCurrentRequest = null;
|
||||
|
||||
@@ -87,7 +87,7 @@ public class CameraDeviceState {
|
||||
* </p>
|
||||
*
|
||||
* @param error the error to set. Should be one of the error codes defined in
|
||||
* {@link android.hardware.camera2.utils.CameraBinderDecorator}.
|
||||
* {@link CameraDeviceImpl.CameraDeviceCallbacks}.
|
||||
*/
|
||||
public synchronized void setError(int error) {
|
||||
mCurrentError = error;
|
||||
@@ -102,11 +102,11 @@ public class CameraDeviceState {
|
||||
* {@link CameraDeviceStateListener#onConfiguring()} will be called.
|
||||
* </p>
|
||||
*
|
||||
* @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
|
||||
* @return {@code false} if an error has occurred.
|
||||
*/
|
||||
public synchronized int setConfiguring() {
|
||||
public synchronized boolean setConfiguring() {
|
||||
doStateTransition(STATE_CONFIGURING);
|
||||
return mCurrentError;
|
||||
return mCurrentError == NO_CAPTURE_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,11 +117,11 @@ public class CameraDeviceState {
|
||||
* {@link CameraDeviceStateListener#onIdle()} will be called.
|
||||
* </p>
|
||||
*
|
||||
* @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
|
||||
* @return {@code false} if an error has occurred.
|
||||
*/
|
||||
public synchronized int setIdle() {
|
||||
public synchronized boolean setIdle() {
|
||||
doStateTransition(STATE_IDLE);
|
||||
return mCurrentError;
|
||||
return mCurrentError == NO_CAPTURE_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,13 +137,13 @@ public class CameraDeviceState {
|
||||
* @param captureError Report a recoverable error for a single request using a valid
|
||||
* error code for {@code ICameraDeviceCallbacks}, or
|
||||
* {@link #NO_CAPTURE_ERROR}
|
||||
* @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
|
||||
* @return {@code false} if an error has occurred.
|
||||
*/
|
||||
public synchronized int setCaptureStart(final RequestHolder request, long timestamp,
|
||||
public synchronized boolean setCaptureStart(final RequestHolder request, long timestamp,
|
||||
int captureError) {
|
||||
mCurrentRequest = request;
|
||||
doStateTransition(STATE_CAPTURING, timestamp, captureError);
|
||||
return mCurrentError;
|
||||
return mCurrentError == NO_CAPTURE_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,16 +161,16 @@ public class CameraDeviceState {
|
||||
* @param captureError Report a recoverable error for a single buffer or result using a valid
|
||||
* error code for {@code ICameraDeviceCallbacks}, or
|
||||
* {@link #NO_CAPTURE_ERROR}.
|
||||
* @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
|
||||
* @return {@code false} if an error has occurred.
|
||||
*/
|
||||
public synchronized int setCaptureResult(final RequestHolder request,
|
||||
public synchronized boolean setCaptureResult(final RequestHolder request,
|
||||
final CameraMetadataNative result,
|
||||
final int captureError) {
|
||||
if (mCurrentState != STATE_CAPTURING) {
|
||||
Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
|
||||
mCurrentError = CameraBinderDecorator.INVALID_OPERATION;
|
||||
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
|
||||
doStateTransition(STATE_ERROR);
|
||||
return mCurrentError;
|
||||
return mCurrentError == NO_CAPTURE_ERROR;
|
||||
}
|
||||
|
||||
if (mCurrentHandler != null && mCurrentListener != null) {
|
||||
@@ -190,7 +190,7 @@ public class CameraDeviceState {
|
||||
});
|
||||
}
|
||||
}
|
||||
return mCurrentError;
|
||||
return mCurrentError == NO_CAPTURE_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +206,7 @@ public class CameraDeviceState {
|
||||
}
|
||||
|
||||
private void doStateTransition(int newState) {
|
||||
doStateTransition(newState, /*timestamp*/0, CameraBinderDecorator.NO_ERROR);
|
||||
doStateTransition(newState, /*timestamp*/0, NO_CAPTURE_ERROR);
|
||||
}
|
||||
|
||||
private void doStateTransition(int newState, final long timestamp, final int error) {
|
||||
@@ -233,7 +233,7 @@ public class CameraDeviceState {
|
||||
case STATE_CONFIGURING:
|
||||
if (mCurrentState != STATE_UNCONFIGURED && mCurrentState != STATE_IDLE) {
|
||||
Log.e(TAG, "Cannot call configure while in state: " + mCurrentState);
|
||||
mCurrentError = CameraBinderDecorator.INVALID_OPERATION;
|
||||
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
|
||||
doStateTransition(STATE_ERROR);
|
||||
break;
|
||||
}
|
||||
@@ -255,7 +255,7 @@ public class CameraDeviceState {
|
||||
|
||||
if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) {
|
||||
Log.e(TAG, "Cannot call idle while in state: " + mCurrentState);
|
||||
mCurrentError = CameraBinderDecorator.INVALID_OPERATION;
|
||||
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
|
||||
doStateTransition(STATE_ERROR);
|
||||
break;
|
||||
}
|
||||
@@ -274,7 +274,7 @@ public class CameraDeviceState {
|
||||
case STATE_CAPTURING:
|
||||
if (mCurrentState != STATE_IDLE && mCurrentState != STATE_CAPTURING) {
|
||||
Log.e(TAG, "Cannot call capture while in state: " + mCurrentState);
|
||||
mCurrentError = CameraBinderDecorator.INVALID_OPERATION;
|
||||
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
|
||||
doStateTransition(STATE_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.hardware.camera2.legacy;
|
||||
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.camera2.impl.CameraDeviceImpl;
|
||||
import android.os.ConditionVariable;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
@@ -42,6 +43,8 @@ public class GLThreadManager {
|
||||
|
||||
private CaptureCollector mCaptureCollector;
|
||||
|
||||
private final CameraDeviceState mDeviceState;
|
||||
|
||||
private final SurfaceTextureRenderer mTextureRenderer;
|
||||
|
||||
private final RequestHandlerThread mGLHandlerThread;
|
||||
@@ -76,42 +79,47 @@ public class GLThreadManager {
|
||||
if (mCleanup) {
|
||||
return true;
|
||||
}
|
||||
switch (msg.what) {
|
||||
case MSG_NEW_CONFIGURATION:
|
||||
ConfigureHolder configure = (ConfigureHolder) msg.obj;
|
||||
mTextureRenderer.cleanupEGLContext();
|
||||
mTextureRenderer.configureSurfaces(configure.surfaces);
|
||||
mCaptureCollector = checkNotNull(configure.collector);
|
||||
configure.condition.open();
|
||||
mConfigured = true;
|
||||
break;
|
||||
case MSG_NEW_FRAME:
|
||||
if (mDroppingFrames) {
|
||||
Log.w(TAG, "Ignoring frame.");
|
||||
try {
|
||||
switch (msg.what) {
|
||||
case MSG_NEW_CONFIGURATION:
|
||||
ConfigureHolder configure = (ConfigureHolder) msg.obj;
|
||||
mTextureRenderer.cleanupEGLContext();
|
||||
mTextureRenderer.configureSurfaces(configure.surfaces);
|
||||
mCaptureCollector = checkNotNull(configure.collector);
|
||||
configure.condition.open();
|
||||
mConfigured = true;
|
||||
break;
|
||||
}
|
||||
if (DEBUG) {
|
||||
mPrevCounter.countAndLog();
|
||||
}
|
||||
if (!mConfigured) {
|
||||
Log.e(TAG, "Dropping frame, EGL context not configured!");
|
||||
}
|
||||
mTextureRenderer.drawIntoSurfaces(mCaptureCollector);
|
||||
break;
|
||||
case MSG_CLEANUP:
|
||||
mTextureRenderer.cleanupEGLContext();
|
||||
mCleanup = true;
|
||||
mConfigured = false;
|
||||
break;
|
||||
case MSG_DROP_FRAMES:
|
||||
mDroppingFrames = true;
|
||||
break;
|
||||
case MSG_ALLOW_FRAMES:
|
||||
mDroppingFrames = false;
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unhandled message " + msg.what + " on GLThread.");
|
||||
break;
|
||||
case MSG_NEW_FRAME:
|
||||
if (mDroppingFrames) {
|
||||
Log.w(TAG, "Ignoring frame.");
|
||||
break;
|
||||
}
|
||||
if (DEBUG) {
|
||||
mPrevCounter.countAndLog();
|
||||
}
|
||||
if (!mConfigured) {
|
||||
Log.e(TAG, "Dropping frame, EGL context not configured!");
|
||||
}
|
||||
mTextureRenderer.drawIntoSurfaces(mCaptureCollector);
|
||||
break;
|
||||
case MSG_CLEANUP:
|
||||
mTextureRenderer.cleanupEGLContext();
|
||||
mCleanup = true;
|
||||
mConfigured = false;
|
||||
break;
|
||||
case MSG_DROP_FRAMES:
|
||||
mDroppingFrames = true;
|
||||
break;
|
||||
case MSG_ALLOW_FRAMES:
|
||||
mDroppingFrames = false;
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unhandled message " + msg.what + " on GLThread.");
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Received exception on GL render thread: ", e);
|
||||
mDeviceState.setError(CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -122,11 +130,13 @@ public class GLThreadManager {
|
||||
*
|
||||
* @param cameraId the camera id for this thread.
|
||||
* @param facing direction the camera is facing.
|
||||
* @param state {@link CameraDeviceState} to use for error handling.
|
||||
*/
|
||||
public GLThreadManager(int cameraId, int facing) {
|
||||
public GLThreadManager(int cameraId, int facing, CameraDeviceState state) {
|
||||
mTextureRenderer = new SurfaceTextureRenderer(facing);
|
||||
TAG = String.format("CameraDeviceGLThread-%d", cameraId);
|
||||
mGLHandlerThread = new RequestHandlerThread(TAG, mGLHandlerCb);
|
||||
mDeviceState = state;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.hardware.camera2.ICameraDeviceCallbacks;
|
||||
import android.hardware.camera2.params.StreamConfiguration;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
import android.hardware.camera2.utils.ArrayUtils;
|
||||
import android.hardware.camera2.utils.CameraBinderDecorator;
|
||||
import android.hardware.camera2.utils.LongParcelable;
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.utils.CameraRuntimeException;
|
||||
@@ -288,17 +289,18 @@ public class LegacyCameraDevice implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
int error = mDeviceState.setConfiguring();
|
||||
if (error == NO_ERROR) {
|
||||
boolean success = false;
|
||||
if (mDeviceState.setConfiguring()) {
|
||||
mRequestThreadManager.configure(outputs);
|
||||
error = mDeviceState.setIdle();
|
||||
success = mDeviceState.setIdle();
|
||||
}
|
||||
|
||||
if (error == NO_ERROR) {
|
||||
if (success) {
|
||||
mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
|
||||
} else {
|
||||
return CameraBinderDecorator.INVALID_OPERATION;
|
||||
}
|
||||
|
||||
return error;
|
||||
return CameraBinderDecorator.NO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,6 +98,7 @@ public class RequestThreadManager {
|
||||
private SurfaceTexture mDummyTexture;
|
||||
private Surface mDummySurface;
|
||||
|
||||
private final Object mIdleLock = new Object();
|
||||
private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview");
|
||||
private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests");
|
||||
|
||||
@@ -173,6 +174,14 @@ public class RequestThreadManager {
|
||||
}
|
||||
}
|
||||
|
||||
private final Camera.ErrorCallback mErrorCallback = new Camera.ErrorCallback() {
|
||||
@Override
|
||||
public void onError(int i, Camera camera) {
|
||||
Log.e(TAG, "Received error " + i + " from the Camera1 ErrorCallback");
|
||||
mDeviceState.setError(CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
|
||||
}
|
||||
};
|
||||
|
||||
private final ConditionVariable mReceivedJpeg = new ConditionVariable(false);
|
||||
|
||||
private final Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
|
||||
@@ -405,7 +414,7 @@ public class RequestThreadManager {
|
||||
|
||||
// TODO: Detect and optimize single-output paths here to skip stream teeing.
|
||||
if (mGLThreadManager == null) {
|
||||
mGLThreadManager = new GLThreadManager(mCameraId, facing);
|
||||
mGLThreadManager = new GLThreadManager(mCameraId, facing, mDeviceState);
|
||||
mGLThreadManager.start();
|
||||
}
|
||||
mGLThreadManager.waitUntilStarted();
|
||||
@@ -617,9 +626,20 @@ public class RequestThreadManager {
|
||||
CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
|
||||
break;
|
||||
}
|
||||
mDeviceState.setIdle();
|
||||
break;
|
||||
} else {
|
||||
|
||||
synchronized (mIdleLock) {
|
||||
// Retry the the request queue.
|
||||
nextBurst = mRequestQueue.getNext();
|
||||
|
||||
// If we still have no queued requests, go idle.
|
||||
if (nextBurst == null) {
|
||||
mDeviceState.setIdle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nextBurst != null) {
|
||||
// Queue another capture if we did not get the last burst.
|
||||
handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
|
||||
}
|
||||
@@ -831,6 +851,7 @@ public class RequestThreadManager {
|
||||
mFaceDetectMapper = new LegacyFaceDetectMapper(mCamera, mCharacteristics);
|
||||
mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState);
|
||||
mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb);
|
||||
mCamera.setErrorCallback(mErrorCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -883,8 +904,11 @@ public class RequestThreadManager {
|
||||
public int submitCaptureRequests(List<CaptureRequest> requests, boolean repeating,
|
||||
/*out*/LongParcelable frameNumber) {
|
||||
Handler handler = mRequestThread.waitAndGetHandler();
|
||||
int ret = mRequestQueue.submit(requests, repeating, frameNumber);
|
||||
handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
|
||||
int ret;
|
||||
synchronized (mIdleLock) {
|
||||
ret = mRequestQueue.submit(requests, repeating, frameNumber);
|
||||
handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user