Merge "Camera: Add proper buffer drop errors to LEGACY mode" into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ecfbb0a1bb
@@ -70,7 +70,7 @@ public class CameraDeviceState {
|
|||||||
* CameraDeviceStateListener callbacks to be called after state transitions.
|
* CameraDeviceStateListener callbacks to be called after state transitions.
|
||||||
*/
|
*/
|
||||||
public interface CameraDeviceStateListener {
|
public interface CameraDeviceStateListener {
|
||||||
void onError(int errorCode, RequestHolder holder);
|
void onError(int errorCode, Object errorArg, RequestHolder holder);
|
||||||
void onConfiguring();
|
void onConfiguring();
|
||||||
void onIdle();
|
void onIdle();
|
||||||
void onBusy();
|
void onBusy();
|
||||||
@@ -162,11 +162,12 @@ public class CameraDeviceState {
|
|||||||
* @param captureError Report a recoverable error for a single buffer or result using a valid
|
* @param captureError Report a recoverable error for a single buffer or result using a valid
|
||||||
* error code for {@code ICameraDeviceCallbacks}, or
|
* error code for {@code ICameraDeviceCallbacks}, or
|
||||||
* {@link #NO_CAPTURE_ERROR}.
|
* {@link #NO_CAPTURE_ERROR}.
|
||||||
|
* @param captureErrorArg An argument for some error captureError codes.
|
||||||
* @return {@code false} if an error has occurred.
|
* @return {@code false} if an error has occurred.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean setCaptureResult(final RequestHolder request,
|
public synchronized boolean setCaptureResult(final RequestHolder request,
|
||||||
final CameraMetadataNative result,
|
final CameraMetadataNative result,
|
||||||
final int captureError) {
|
final int captureError, final Object captureErrorArg) {
|
||||||
if (mCurrentState != STATE_CAPTURING) {
|
if (mCurrentState != STATE_CAPTURING) {
|
||||||
Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
|
Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
|
||||||
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
|
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
|
||||||
@@ -179,7 +180,7 @@ public class CameraDeviceState {
|
|||||||
mCurrentHandler.post(new Runnable() {
|
mCurrentHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mCurrentListener.onError(captureError, request);
|
mCurrentListener.onError(captureError, captureErrorArg, request);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -194,6 +195,11 @@ public class CameraDeviceState {
|
|||||||
return mCurrentError == NO_CAPTURE_ERROR;
|
return mCurrentError == NO_CAPTURE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized boolean setCaptureResult(final RequestHolder request,
|
||||||
|
final CameraMetadataNative result) {
|
||||||
|
return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the listener for state transition callbacks.
|
* Set the listener for state transition callbacks.
|
||||||
*
|
*
|
||||||
@@ -239,7 +245,7 @@ public class CameraDeviceState {
|
|||||||
mCurrentHandler.post(new Runnable() {
|
mCurrentHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mCurrentListener.onError(mCurrentError, mCurrentRequest);
|
mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -299,7 +305,7 @@ public class CameraDeviceState {
|
|||||||
mCurrentHandler.post(new Runnable() {
|
mCurrentHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mCurrentListener.onError(error, mCurrentRequest);
|
mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -480,19 +480,15 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
|
|||||||
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
|
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<Surface> surfaces = null;
|
SparseArray<Surface> surfaces = null;
|
||||||
synchronized(mConfigureLock) {
|
synchronized(mConfigureLock) {
|
||||||
if (!mConfiguring) {
|
if (!mConfiguring) {
|
||||||
String err = "Cannot end configure, no configuration change in progress.";
|
String err = "Cannot end configure, no configuration change in progress.";
|
||||||
Log.e(TAG, err);
|
Log.e(TAG, err);
|
||||||
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
|
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
|
||||||
}
|
}
|
||||||
int numSurfaces = mSurfaces.size();
|
if (mSurfaces != null) {
|
||||||
if (numSurfaces > 0) {
|
surfaces = mSurfaces.clone();
|
||||||
surfaces = new ArrayList<>();
|
|
||||||
for (int i = 0; i < numSurfaces; ++i) {
|
|
||||||
surfaces.add(mSurfaces.valueAt(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mConfiguring = false;
|
mConfiguring = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import android.hardware.camera2.impl.CameraDeviceImpl;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.MutableLong;
|
import android.util.MutableLong;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.view.Surface;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
@@ -95,22 +95,28 @@ public class CaptureCollector {
|
|||||||
} else {
|
} else {
|
||||||
// Send buffer dropped errors for each pending buffer if the request has
|
// Send buffer dropped errors for each pending buffer if the request has
|
||||||
// started.
|
// started.
|
||||||
if (mFailedPreview) {
|
for (Surface targetSurface : mRequest.getRequest().getTargets() ) {
|
||||||
Log.w(TAG, "Preview buffers dropped for request: " +
|
try {
|
||||||
mRequest.getRequestId());
|
if (mRequest.jpegType(targetSurface)) {
|
||||||
for (int i = 0; i < mRequest.numPreviewTargets(); i++) {
|
if (mFailedJpeg) {
|
||||||
CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
|
CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
|
||||||
/*result*/null,
|
/*result*/null,
|
||||||
CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
|
CameraDeviceImpl.CameraDeviceCallbacks.
|
||||||
}
|
ERROR_CAMERA_BUFFER,
|
||||||
}
|
targetSurface);
|
||||||
if (mFailedJpeg) {
|
}
|
||||||
Log.w(TAG, "Jpeg buffers dropped for request: " +
|
} else {
|
||||||
mRequest.getRequestId());
|
// preview buffer
|
||||||
for (int i = 0; i < mRequest.numJpegTargets(); i++) {
|
if (mFailedPreview) {
|
||||||
CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
|
CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
|
||||||
/*result*/null,
|
/*result*/null,
|
||||||
CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
|
CameraDeviceImpl.CameraDeviceCallbacks.
|
||||||
|
ERROR_CAMERA_BUFFER,
|
||||||
|
targetSurface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
|
||||||
|
Log.e(TAG, "Unexpected exception when querying Surface: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import android.os.ServiceSpecificException;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.Size;
|
import android.util.Size;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -64,7 +65,7 @@ public class LegacyCameraDevice implements AutoCloseable {
|
|||||||
private final CameraCharacteristics mStaticCharacteristics;
|
private final CameraCharacteristics mStaticCharacteristics;
|
||||||
private final ICameraDeviceCallbacks mDeviceCallbacks;
|
private final ICameraDeviceCallbacks mDeviceCallbacks;
|
||||||
private final CameraDeviceState mDeviceState = new CameraDeviceState();
|
private final CameraDeviceState mDeviceState = new CameraDeviceState();
|
||||||
private List<Surface> mConfiguredSurfaces;
|
private SparseArray<Surface> mConfiguredSurfaces;
|
||||||
private boolean mClosed = false;
|
private boolean mClosed = false;
|
||||||
|
|
||||||
private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
|
private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
|
||||||
@@ -89,13 +90,29 @@ public class LegacyCameraDevice implements AutoCloseable {
|
|||||||
public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
|
public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
|
||||||
|
|
||||||
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
|
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
|
||||||
|
return getExtrasFromRequest(holder,
|
||||||
|
/*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
|
||||||
|
int errorCode, Object errorArg) {
|
||||||
|
int errorStreamId = -1;
|
||||||
|
if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
|
||||||
|
Surface errorTarget = (Surface) errorArg;
|
||||||
|
int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
|
||||||
|
if (indexOfTarget < 0) {
|
||||||
|
Log.e(TAG, "Buffer drop error reported for unknown Surface");
|
||||||
|
} else {
|
||||||
|
errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (holder == null) {
|
if (holder == null) {
|
||||||
return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
|
return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
|
||||||
ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
|
ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
|
||||||
}
|
}
|
||||||
return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
|
return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
|
||||||
/*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
|
/*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
|
||||||
/*partialResultCount*/1, /*errorStreamId*/-1);
|
/*partialResultCount*/1, errorStreamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,9 +122,9 @@ public class LegacyCameraDevice implements AutoCloseable {
|
|||||||
private final CameraDeviceState.CameraDeviceStateListener mStateListener =
|
private final CameraDeviceState.CameraDeviceStateListener mStateListener =
|
||||||
new CameraDeviceState.CameraDeviceStateListener() {
|
new CameraDeviceState.CameraDeviceStateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onError(final int errorCode, final RequestHolder holder) {
|
public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "onError called, errorCode = " + errorCode);
|
Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
|
||||||
}
|
}
|
||||||
switch (errorCode) {
|
switch (errorCode) {
|
||||||
/*
|
/*
|
||||||
@@ -125,7 +142,7 @@ public class LegacyCameraDevice implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final CaptureResultExtras extras = getExtrasFromRequest(holder);
|
final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
|
||||||
mResultHandler.post(new Runnable() {
|
mResultHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -281,14 +298,17 @@ public class LegacyCameraDevice implements AutoCloseable {
|
|||||||
*
|
*
|
||||||
* <p>Every surface in {@code outputs} must be non-{@code null}.</p>
|
* <p>Every surface in {@code outputs} must be non-{@code null}.</p>
|
||||||
*
|
*
|
||||||
* @param outputs a list of surfaces to set.
|
* @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
|
||||||
|
* list; it must not be modified by the caller once it's passed in.
|
||||||
* @return an error code for this binder operation, or {@link NO_ERROR}
|
* @return an error code for this binder operation, or {@link NO_ERROR}
|
||||||
* on success.
|
* on success.
|
||||||
*/
|
*/
|
||||||
public int configureOutputs(List<Surface> outputs) {
|
public int configureOutputs(SparseArray<Surface> outputs) {
|
||||||
List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
|
List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
|
||||||
if (outputs != null) {
|
if (outputs != null) {
|
||||||
for (Surface output : outputs) {
|
int count = outputs.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
Surface output = outputs.valueAt(i);
|
||||||
if (output == null) {
|
if (output == null) {
|
||||||
Log.e(TAG, "configureOutputs - null outputs are not allowed");
|
Log.e(TAG, "configureOutputs - null outputs are not allowed");
|
||||||
return BAD_VALUE;
|
return BAD_VALUE;
|
||||||
@@ -353,7 +373,7 @@ public class LegacyCameraDevice implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
|
mConfiguredSurfaces = outputs;
|
||||||
} else {
|
} else {
|
||||||
return LegacyExceptionUtils.INVALID_OPERATION;
|
return LegacyExceptionUtils.INVALID_OPERATION;
|
||||||
}
|
}
|
||||||
@@ -659,6 +679,23 @@ public class LegacyCameraDevice implements AutoCloseable {
|
|||||||
return nativeGetSurfaceId(surface);
|
return nativeGetSurfaceId(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) {
|
||||||
|
if (surfaces == null) {
|
||||||
|
throw new NullPointerException("Null argument surfaces");
|
||||||
|
}
|
||||||
|
List<Long> surfaceIds = new ArrayList<>();
|
||||||
|
int count = surfaces.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
long id = getSurfaceId(surfaces.valueAt(i));
|
||||||
|
if (id == 0) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Configured surface had null native GraphicBufferProducer pointer!");
|
||||||
|
}
|
||||||
|
surfaceIds.add(id);
|
||||||
|
}
|
||||||
|
return surfaceIds;
|
||||||
|
}
|
||||||
|
|
||||||
static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
|
static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
|
||||||
if (surfaces == null) {
|
if (surfaces == null) {
|
||||||
throw new NullPointerException("Null argument surfaces");
|
throw new NullPointerException("Null argument surfaces");
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ public class RequestHolder {
|
|||||||
private final int mNumPreviewTargets;
|
private final int mNumPreviewTargets;
|
||||||
private volatile boolean mFailed = false;
|
private volatile boolean mFailed = false;
|
||||||
|
|
||||||
|
private final Collection<Long> mJpegSurfaceIds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder class for {@link RequestHolder} objects.
|
* A builder class for {@link RequestHolder} objects.
|
||||||
*
|
*
|
||||||
@@ -150,13 +152,13 @@ public class RequestHolder {
|
|||||||
*/
|
*/
|
||||||
public RequestHolder build(long frameNumber) {
|
public RequestHolder build(long frameNumber) {
|
||||||
return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
|
return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
|
||||||
mNumJpegTargets, mNumPreviewTargets);
|
mNumJpegTargets, mNumPreviewTargets, mJpegSurfaceIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
|
private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
|
||||||
boolean repeating, long frameNumber, int numJpegTargets,
|
boolean repeating, long frameNumber, int numJpegTargets,
|
||||||
int numPreviewTargets) {
|
int numPreviewTargets, Collection<Long> jpegSurfaceIds) {
|
||||||
mRepeating = repeating;
|
mRepeating = repeating;
|
||||||
mRequest = request;
|
mRequest = request;
|
||||||
mRequestId = requestId;
|
mRequestId = requestId;
|
||||||
@@ -164,6 +166,7 @@ public class RequestHolder {
|
|||||||
mFrameNumber = frameNumber;
|
mFrameNumber = frameNumber;
|
||||||
mNumJpegTargets = numJpegTargets;
|
mNumJpegTargets = numJpegTargets;
|
||||||
mNumPreviewTargets = numPreviewTargets;
|
mNumPreviewTargets = numPreviewTargets;
|
||||||
|
mJpegSurfaceIds = jpegSurfaceIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,6 +240,17 @@ public class RequestHolder {
|
|||||||
return mNumPreviewTargets;
|
return mNumPreviewTargets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given surface requires jpeg buffers.
|
||||||
|
*
|
||||||
|
* @param s a {@link android.view.Surface} to check.
|
||||||
|
* @return true if the surface requires a jpeg buffer.
|
||||||
|
*/
|
||||||
|
public boolean jpegType(Surface s)
|
||||||
|
throws LegacyExceptionUtils.BufferQueueAbandonedException {
|
||||||
|
return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark this request as failed.
|
* Mark this request as failed.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -908,8 +908,7 @@ public class RequestThreadManager {
|
|||||||
mFaceDetectMapper.mapResultFaces(result, mLastRequest);
|
mFaceDetectMapper.mapResultFaces(result, mLastRequest);
|
||||||
|
|
||||||
if (!holder.requestFailed()) {
|
if (!holder.requestFailed()) {
|
||||||
mDeviceState.setCaptureResult(holder, result,
|
mDeviceState.setCaptureResult(holder, result);
|
||||||
CameraDeviceState.NO_CAPTURE_ERROR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
|||||||
Reference in New Issue
Block a user