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:
Ruben Brunk
2014-09-22 23:41:58 +00:00
committed by Android Git Automerger
4 changed files with 105 additions and 69 deletions

View File

@@ -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;
}

View File

@@ -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;
}
/**

View File

@@ -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;
}
/**

View File

@@ -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;
}