summaryrefslogtreecommitdiffstats
path: root/services/camera/libcameraservice/device3
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2013-10-11 09:51:09 -0700
committerEino-Ville Talvala <etalvala@google.com>2013-11-06 18:22:22 -0800
commitfd6ecdd39bd83ea020f78b425e96310380d66c35 (patch)
tree74b1aaa8fdcbf75681f72fb93b96db4ab48fa34c /services/camera/libcameraservice/device3
parent48b6cd98b23b2cf9dee88f075f7575ecb5aaf545 (diff)
downloadframeworks_av-fd6ecdd39bd83ea020f78b425e96310380d66c35.zip
frameworks_av-fd6ecdd39bd83ea020f78b425e96310380d66c35.tar.gz
frameworks_av-fd6ecdd39bd83ea020f78b425e96310380d66c35.tar.bz2
Camera HAL3/API1: Add support for the partial result quirk.
- Camera2Client: - Detect partial result quirk - Camera3Device: - Accumulate all partial results together - Fire off 3A-only result once all 3A states are available - FrameProcessorBase: - Filter out partials, don't send to listeners - FrameProcessor: - Skip face detect on partials - Make sure to only handle a 3A update for a given frame once - Trigger AF notifications when AF mode or trigger changes, to properly detect all AF transitions. Bug: 11115603 Change-Id: Iea8aa73c568701562a46071f7ea100624251d10b
Diffstat (limited to 'services/camera/libcameraservice/device3')
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.cpp243
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.h30
2 files changed, 265 insertions, 8 deletions
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index c320d6c..cb72e0e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -55,6 +55,7 @@ Camera3Device::Camera3Device(int id):
mId(id),
mHal3Device(NULL),
mStatus(STATUS_UNINITIALIZED),
+ mUsePartialResultQuirk(false),
mNextResultFrameNumber(0),
mNextShutterFrameNumber(0),
mListener(NULL)
@@ -193,6 +194,15 @@ status_t Camera3Device::initialize(camera_module_t *module)
mNeedConfig = true;
mPauseStateNotify = false;
+ /** Check for quirks */
+
+ // Will the HAL be sending in early partial result metadata?
+ camera_metadata_entry partialResultsQuirk =
+ mDeviceInfo.find(ANDROID_QUIRKS_USE_PARTIAL_RESULT);
+ if (partialResultsQuirk.count > 0 && partialResultsQuirk.data.u8[0] == 1) {
+ mUsePartialResultQuirk = true;
+ }
+
return OK;
}
@@ -1391,6 +1401,168 @@ status_t Camera3Device::registerInFlight(int32_t frameNumber,
}
/**
+ * QUIRK(partial results)
+ * Check if all 3A fields are ready, and send off a partial 3A-only result
+ * to the output frame queue
+ */
+bool Camera3Device::processPartial3AQuirk(int32_t frameNumber,
+ const CameraMetadata& partial) {
+
+ // Check if all 3A states are present
+ // The full list of fields is
+ // android.control.afMode
+ // android.control.awbMode
+ // android.control.aeState
+ // android.control.awbState
+ // android.control.afState
+ // android.control.afTriggerID
+ // android.control.aePrecaptureID
+ // TODO: Add android.control.aeMode
+
+ bool gotAllStates = true;
+
+ uint8_t afMode;
+ uint8_t awbMode;
+ uint8_t aeState;
+ uint8_t afState;
+ uint8_t awbState;
+ int32_t afTriggerId;
+ int32_t aeTriggerId;
+
+ gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AF_MODE,
+ &afMode, frameNumber);
+
+ gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AWB_MODE,
+ &awbMode, frameNumber);
+
+ gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AE_STATE,
+ &aeState, frameNumber);
+
+ gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AF_STATE,
+ &afState, frameNumber);
+
+ gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AWB_STATE,
+ &awbState, frameNumber);
+
+ gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AF_TRIGGER_ID,
+ &afTriggerId, frameNumber);
+
+ gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AE_PRECAPTURE_ID,
+ &aeTriggerId, frameNumber);
+
+ if (!gotAllStates) return false;
+
+ ALOGVV("%s: Camera %d: Frame %d: AF mode %d, AWB mode %d, "
+ "AF state %d, AE state %d, AWB state %d, "
+ "AF trigger %d, AE precapture trigger %d",
+ __FUNCTION__, mId, frameNumber,
+ afMode, awbMode,
+ afState, aeState, awbState,
+ afTriggerId, aeTriggerId);
+
+ // Got all states, so construct a minimal result to send
+ // In addition to the above fields, this means adding in
+ // android.request.frameCount
+ // android.quirks.partialResult
+
+ const size_t kMinimal3AResultEntries = 7;
+
+ Mutex::Autolock l(mOutputLock);
+
+ CameraMetadata& min3AResult =
+ *mResultQueue.insert(
+ mResultQueue.end(),
+ CameraMetadata(kMinimal3AResultEntries, /*dataCapacity*/ 0));
+
+ if (!insert3AResult(min3AResult, ANDROID_REQUEST_FRAME_COUNT,
+ &frameNumber, frameNumber)) {
+ return false;
+ }
+
+ static const uint8_t partialResult = ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL;
+ if (!insert3AResult(min3AResult, ANDROID_QUIRKS_PARTIAL_RESULT,
+ &partialResult, frameNumber)) {
+ return false;
+ }
+
+ if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_MODE,
+ &afMode, frameNumber)) {
+ return false;
+ }
+
+ if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_MODE,
+ &awbMode, frameNumber)) {
+ return false;
+ }
+
+ if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_STATE,
+ &aeState, frameNumber)) {
+ return false;
+ }
+
+ if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_STATE,
+ &afState, frameNumber)) {
+ return false;
+ }
+
+ if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_STATE,
+ &awbState, frameNumber)) {
+ return false;
+ }
+
+ if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_TRIGGER_ID,
+ &afTriggerId, frameNumber)) {
+ return false;
+ }
+
+ if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_PRECAPTURE_ID,
+ &aeTriggerId, frameNumber)) {
+ return false;
+ }
+
+ mResultSignal.signal();
+
+ return true;
+}
+
+template<typename T>
+bool Camera3Device::get3AResult(const CameraMetadata& result, int32_t tag,
+ T* value, int32_t frameNumber) {
+ (void) frameNumber;
+
+ camera_metadata_ro_entry_t entry;
+
+ entry = result.find(tag);
+ if (entry.count == 0) {
+ ALOGVV("%s: Camera %d: Frame %d: No %s provided by HAL!", __FUNCTION__,
+ mId, frameNumber, get_camera_metadata_tag_name(tag));
+ return false;
+ }
+
+ if (sizeof(T) == sizeof(uint8_t)) {
+ *value = entry.data.u8[0];
+ } else if (sizeof(T) == sizeof(int32_t)) {
+ *value = entry.data.i32[0];
+ } else {
+ ALOGE("%s: Unexpected type", __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+template<typename T>
+bool Camera3Device::insert3AResult(CameraMetadata& result, int32_t tag,
+ const T* value, int32_t frameNumber) {
+ if (result.update(tag, value, 1) != NO_ERROR) {
+ mResultQueue.erase(--mResultQueue.end(), mResultQueue.end());
+ SET_ERR("Frame %d: Failed to set %s in partial metadata",
+ frameNumber, get_camera_metadata_tag_name(tag));
+ return false;
+ }
+ return true;
+}
+
+/**
* Camera HAL device callback methods
*/
@@ -1405,6 +1577,8 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
frameNumber);
return;
}
+ bool partialResultQuirk = false;
+ CameraMetadata collectedQuirkResult;
// Get capture timestamp from list of in-flight requests, where it was added
// by the shutter notification for this frame. Then update the in-flight
@@ -1420,24 +1594,57 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
return;
}
InFlightRequest &request = mInFlightMap.editValueAt(idx);
+
+ // Check if this result carries only partial metadata
+ if (mUsePartialResultQuirk && result->result != NULL) {
+ camera_metadata_ro_entry_t partialResultEntry;
+ res = find_camera_metadata_ro_entry(result->result,
+ ANDROID_QUIRKS_PARTIAL_RESULT, &partialResultEntry);
+ if (res != NAME_NOT_FOUND &&
+ partialResultEntry.count > 0 &&
+ partialResultEntry.data.u8[0] ==
+ ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
+ // A partial result. Flag this as such, and collect this
+ // set of metadata into the in-flight entry.
+ partialResultQuirk = true;
+ request.partialResultQuirk.collectedResult.append(
+ result->result);
+ request.partialResultQuirk.collectedResult.erase(
+ ANDROID_QUIRKS_PARTIAL_RESULT);
+ // Fire off a 3A-only result if possible
+ if (!request.partialResultQuirk.haveSent3A) {
+ request.partialResultQuirk.haveSent3A =
+ processPartial3AQuirk(frameNumber,
+ request.partialResultQuirk.collectedResult);
+ }
+ }
+ }
+
timestamp = request.captureTimestamp;
/**
- * One of the following must happen before it's legal to call process_capture_result:
+ * One of the following must happen before it's legal to call process_capture_result,
+ * unless partial metadata is being provided:
* - CAMERA3_MSG_SHUTTER (expected during normal operation)
* - CAMERA3_MSG_ERROR (expected during flush)
*/
- if (request.requestStatus == OK && timestamp == 0) {
+ if (request.requestStatus == OK && timestamp == 0 && !partialResultQuirk) {
SET_ERR("Called before shutter notify for frame %d",
frameNumber);
return;
}
- if (result->result != NULL) {
+ // Did we get the (final) result metadata for this capture?
+ if (result->result != NULL && !partialResultQuirk) {
if (request.haveResultMetadata) {
SET_ERR("Called multiple times with metadata for frame %d",
frameNumber);
return;
}
+ if (mUsePartialResultQuirk &&
+ !request.partialResultQuirk.collectedResult.isEmpty()) {
+ collectedQuirkResult.acquire(
+ request.partialResultQuirk.collectedResult);
+ }
request.haveResultMetadata = true;
}
@@ -1449,6 +1656,7 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
return;
}
+ // Check if everything has arrived for this result (buffers and metadata)
if (request.haveResultMetadata && request.numBuffersLeft == 0) {
ATRACE_ASYNC_END("frame capture", frameNumber);
mInFlightMap.removeItemsAt(idx, 1);
@@ -1463,9 +1671,12 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
}
// Process the result metadata, if provided
- if (result->result != NULL) {
+ bool gotResult = false;
+ if (result->result != NULL && !partialResultQuirk) {
Mutex::Autolock l(mOutputLock);
+ gotResult = true;
+
if (frameNumber != mNextResultFrameNumber) {
SET_ERR("Out-of-order capture result metadata submitted! "
"(got frame number %d, expecting %d)",
@@ -1474,19 +1685,26 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
}
mNextResultFrameNumber++;
- CameraMetadata &captureResult =
- *mResultQueue.insert(mResultQueue.end(), CameraMetadata());
-
+ CameraMetadata captureResult;
captureResult = result->result;
+
if (captureResult.update(ANDROID_REQUEST_FRAME_COUNT,
(int32_t*)&frameNumber, 1) != OK) {
SET_ERR("Failed to set frame# in metadata (%d)",
frameNumber);
+ gotResult = false;
} else {
ALOGVV("%s: Camera %d: Set frame# in metadata (%d)",
__FUNCTION__, mId, frameNumber);
}
+ // Append any previous partials to form a complete result
+ if (mUsePartialResultQuirk && !collectedQuirkResult.isEmpty()) {
+ captureResult.append(collectedQuirkResult);
+ }
+
+ captureResult.sort();
+
// Check that there's a timestamp in the result metadata
camera_metadata_entry entry =
@@ -1494,10 +1712,19 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
if (entry.count == 0) {
SET_ERR("No timestamp provided by HAL for frame %d!",
frameNumber);
+ gotResult = false;
} else if (timestamp != entry.data.i64[0]) {
SET_ERR("Timestamp mismatch between shutter notify and result"
" metadata for frame %d (%lld vs %lld respectively)",
frameNumber, timestamp, entry.data.i64[0]);
+ gotResult = false;
+ }
+
+ if (gotResult) {
+ // Valid result, insert into queue
+ CameraMetadata& queuedResult =
+ *mResultQueue.insert(mResultQueue.end(), CameraMetadata());
+ queuedResult.swap(captureResult);
}
} // scope for mOutputLock
@@ -1517,7 +1744,7 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
// Finally, signal any waiters for new frames
- if (result->result != NULL) {
+ if (gotResult) {
mResultSignal.signal();
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 12252c8..4a24a88 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -188,6 +188,9 @@ class Camera3Device :
// Need to hold on to stream references until configure completes.
Vector<sp<camera3::Camera3StreamInterface> > mDeletedStreams;
+ // Whether quirk ANDROID_QUIRKS_USE_PARTIAL_RESULT is enabled
+ bool mUsePartialResultQuirk;
+
/**** End scope for mLock ****/
class CaptureRequest : public LightRefBase<CaptureRequest> {
@@ -445,6 +448,18 @@ class Camera3Device :
// buffers
int numBuffersLeft;
+ // Fields used by the partial result quirk only
+ struct PartialResultQuirkInFlight {
+ // Set by process_capture_result once 3A has been sent to clients
+ bool haveSent3A;
+ // Result metadata collected so far, when partial results are in use
+ CameraMetadata collectedResult;
+
+ PartialResultQuirkInFlight():
+ haveSent3A(false) {
+ }
+ } partialResultQuirk;
+
// Default constructor needed by KeyedVector
InFlightRequest() :
requestId(0),
@@ -472,6 +487,21 @@ class Camera3Device :
int32_t numBuffers);
/**
+ * For the partial result quirk, check if all 3A state fields are available
+ * and if so, queue up 3A-only result to the client. Returns true if 3A
+ * is sent.
+ */
+ bool processPartial3AQuirk(int32_t frameNumber, const CameraMetadata& partial);
+
+ // Helpers for reading and writing 3A metadata into to/from partial results
+ template<typename T>
+ bool get3AResult(const CameraMetadata& result, int32_t tag,
+ T* value, int32_t frameNumber);
+
+ template<typename T>
+ bool insert3AResult(CameraMetadata &result, int32_t tag, const T* value,
+ int32_t frameNumber);
+ /**
* Tracking for idle detection
*/
sp<camera3::StatusTracker> mStatusTracker;