Camera muting via sensor test pattern
Currently enabled/disabled via
adb shell cmd media.camera set-camera-mute <1/0>
TODO:
- Connect to the wider sensor muting feature
This is suitable for testing apps to see how they react, and how Pixel phones
implement test patterns.
Test: GoogleCameraApp and AOSP Camera2 on sunfish appear to act as if they were in a dark room,
no crashes, after calling 'adb shell cmd media.camera set-camera-mute 1'
Bug: 170156750
Change-Id: I85e1d2d6ee7d9bf1aee99c4bc8d5f98d36754228
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 385bfd6..7606d7d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -357,6 +357,15 @@
mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
}
+ camera_metadata_entry_t availableTestPatternModes = mDeviceInfo.find(
+ ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES);
+ for (size_t i = 0; i < availableTestPatternModes.count; i++) {
+ if (availableTestPatternModes.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
+ mSupportCameraMute = true;
+ break;
+ }
+ }
+
return OK;
}
@@ -2388,6 +2397,26 @@
newRequest->mZoomRatioIs1x = false;
}
+ if (mSupportCameraMute) {
+ auto testPatternModeEntry =
+ newRequest->mSettingsList.begin()->metadata.find(ANDROID_SENSOR_TEST_PATTERN_MODE);
+ newRequest->mOriginalTestPatternMode = testPatternModeEntry.count > 0 ?
+ testPatternModeEntry.data.i32[0] :
+ ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
+
+ auto testPatternDataEntry =
+ newRequest->mSettingsList.begin()->metadata.find(ANDROID_SENSOR_TEST_PATTERN_DATA);
+ if (testPatternDataEntry.count > 0) {
+ memcpy(newRequest->mOriginalTestPatternData, testPatternModeEntry.data.i32,
+ sizeof(newRequest->mOriginalTestPatternData));
+ } else {
+ newRequest->mOriginalTestPatternData[0] = 0;
+ newRequest->mOriginalTestPatternData[1] = 0;
+ newRequest->mOriginalTestPatternData[2] = 0;
+ newRequest->mOriginalTestPatternData[3] = 0;
+ }
+ }
+
return newRequest;
}
@@ -3860,6 +3889,8 @@
mCurrentAfTriggerId(0),
mCurrentPreCaptureTriggerId(0),
mRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_NONE),
+ mCameraMute(false),
+ mCameraMuteChanged(false),
mRepeatingLastFrameNumber(
hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES),
mPrepareVideoStream(false),
@@ -4484,10 +4515,13 @@
mPrevTriggers = triggerCount;
bool rotateAndCropChanged = overrideAutoRotateAndCrop(captureRequest);
+ bool testPatternChanged = overrideTestPattern(captureRequest);
- // If the request is the same as last, or we had triggers last time
+ // If the request is the same as last, or we had triggers now or last time or
+ // changing overrides this time
bool newRequest =
- (mPrevRequest != captureRequest || triggersMixedIn || rotateAndCropChanged) &&
+ (mPrevRequest != captureRequest || triggersMixedIn ||
+ rotateAndCropChanged || testPatternChanged) &&
// Request settings are all the same within one batch, so only treat the first
// request in a batch as new
!(batchedRequest && i > 0);
@@ -4952,6 +4986,16 @@
return OK;
}
+status_t Camera3Device::RequestThread::setCameraMute(bool enabled) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mTriggerMutex);
+ if (enabled != mCameraMute) {
+ mCameraMute = enabled;
+ mCameraMuteChanged = true;
+ }
+ return OK;
+}
+
nsecs_t Camera3Device::getExpectedInFlightDuration() {
ATRACE_CALL();
std::lock_guard<std::mutex> l(mInFlightLock);
@@ -5504,6 +5548,61 @@
return false;
}
+bool Camera3Device::RequestThread::overrideTestPattern(
+ const sp<CaptureRequest> &request) {
+ ATRACE_CALL();
+
+ Mutex::Autolock l(mTriggerMutex);
+
+ bool changed = false;
+
+ int32_t testPatternMode = request->mOriginalTestPatternMode;
+ int32_t testPatternData[4] = {
+ request->mOriginalTestPatternData[0],
+ request->mOriginalTestPatternData[1],
+ request->mOriginalTestPatternData[2],
+ request->mOriginalTestPatternData[3]
+ };
+
+ if (mCameraMute) {
+ testPatternMode = ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR;
+ testPatternData[0] = 0;
+ testPatternData[1] = 0;
+ testPatternData[2] = 0;
+ testPatternData[3] = 0;
+ }
+
+ CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
+
+ auto testPatternEntry = metadata.find(ANDROID_SENSOR_TEST_PATTERN_MODE);
+ if (testPatternEntry.count > 0) {
+ if (testPatternEntry.data.i32[0] != testPatternMode) {
+ testPatternEntry.data.i32[0] = testPatternMode;
+ changed = true;
+ }
+ } else {
+ metadata.update(ANDROID_SENSOR_TEST_PATTERN_MODE,
+ &testPatternMode, 1);
+ changed = true;
+ }
+
+ auto testPatternColor = metadata.find(ANDROID_SENSOR_TEST_PATTERN_DATA);
+ if (testPatternColor.count > 0) {
+ for (size_t i = 0; i < 4; i++) {
+ if (testPatternColor.data.i32[i] != (int32_t)testPatternData[i]) {
+ testPatternColor.data.i32[i] = testPatternData[i];
+ changed = true;
+ }
+ }
+ } else {
+ metadata.update(ANDROID_SENSOR_TEST_PATTERN_DATA,
+ (int32_t*)testPatternData, 4);
+ changed = true;
+ }
+
+ return changed;
+}
+
/**
* PreparerThread inner class methods
*/
@@ -6129,4 +6228,22 @@
return mRequestThread->setRotateAndCropAutoBehavior(rotateAndCropValue);
}
+bool Camera3Device::supportsCameraMute() {
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ return mSupportCameraMute;
+}
+
+status_t Camera3Device::setCameraMute(bool enabled) {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ if (mRequestThread == nullptr || !mSupportCameraMute) {
+ return INVALID_OPERATION;
+ }
+ return mRequestThread->setCameraMute(enabled);
+}
+
}; // namespace android