Loading services/camera/libcameraservice/device3/Camera3Device.cpp +255 −13 Original line number Diff line number Diff line Loading @@ -194,8 +194,14 @@ status_t Camera3Device::initializeCommonLocked() { mTagMonitor.initialize(mVendorTagId); Vector<int32_t> sessionParamKeys; camera_metadata_entry_t sessionKeysEntry = mDeviceInfo.find( ANDROID_REQUEST_AVAILABLE_SESSION_KEYS); if (sessionKeysEntry.count > 0) { sessionParamKeys.insertArrayAt(sessionKeysEntry.data.i32, 0, sessionKeysEntry.count); } /** Start up request queue thread */ mRequestThread = new RequestThread(this, mStatusTracker, mInterface); mRequestThread = new RequestThread(this, mStatusTracker, mInterface, sessionParamKeys); res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string()); if (res != OK) { SET_ERR_L("Unable to start request queue thread: %s (%d)", Loading Loading @@ -1104,7 +1110,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked( if (mStatus == STATUS_UNCONFIGURED || mNeedConfig) { // This point should only be reached via API1 (API2 must explicitly call configureStreams) // so unilaterally select normal operating mode. res = configureStreamsLocked(CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE, mSessionParams); res = filterParamsAndConfigureLocked(request, CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE); // Stream configuration failed. Client might try other configuraitons. if (res != OK) { CLOGE("Can't set up streams: %s (%d)", strerror(-res), res); Loading Loading @@ -1508,11 +1514,20 @@ status_t Camera3Device::configureStreams(const CameraMetadata& sessionParams, in Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); return filterParamsAndConfigureLocked(sessionParams, operatingMode); } status_t Camera3Device::filterParamsAndConfigureLocked(const CameraMetadata& sessionParams, int operatingMode) { //Filter out any incoming session parameters const CameraMetadata params(sessionParams); CameraMetadata filteredParams; camera_metadata_entry_t availableSessionKeys = mDeviceInfo.find( ANDROID_REQUEST_AVAILABLE_SESSION_KEYS); CameraMetadata filteredParams(availableSessionKeys.count); camera_metadata_t *meta = const_cast<camera_metadata_t *>( filteredParams.getAndLock()); set_camera_metadata_vendor_id(meta, mVendorTagId); filteredParams.unlock(meta); if (availableSessionKeys.count > 0) { for (size_t i = 0; i < availableSessionKeys.count; i++) { camera_metadata_ro_entry entry = params.find( Loading Loading @@ -2203,10 +2218,47 @@ void Camera3Device::cancelStreamsConfigurationLocked() { // properly clean things up internalUpdateStatusLocked(STATUS_UNCONFIGURED); mNeedConfig = true; res = mPreparerThread->resume(); if (res != OK) { ALOGE("%s: Camera %s: Preparer thread failed to resume!", __FUNCTION__, mId.string()); } } bool Camera3Device::reconfigureCamera(const CameraMetadata& sessionParams) { ATRACE_CALL(); bool ret = false; Mutex::Autolock il(mInterfaceLock); nsecs_t maxExpectedDuration = getExpectedInFlightDuration(); Mutex::Autolock l(mLock); auto rc = internalPauseAndWaitLocked(maxExpectedDuration); if (rc == NO_ERROR) { mNeedConfig = true; rc = configureStreamsLocked(mOperatingMode, sessionParams, /*notifyRequestThread*/ false); if (rc == NO_ERROR) { ret = true; mPauseStateNotify = false; //Moving to active state while holding 'mLock' is important. //There could be pending calls to 'create-/deleteStream' which //will trigger another stream configuration while the already //present streams end up with outstanding buffers that will //not get drained. internalUpdateStatusLocked(STATUS_ACTIVE); } else { setErrorStateLocked("%s: Failed to re-configure camera: %d", __FUNCTION__, rc); } } else { ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc); } return ret; } status_t Camera3Device::configureStreamsLocked(int operatingMode, const CameraMetadata& sessionParams) { const CameraMetadata& sessionParams, bool notifyRequestThread) { ATRACE_CALL(); status_t res; Loading Loading @@ -2247,6 +2299,8 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, // Start configuring the streams ALOGV("%s: Camera %s: Starting stream configuration", __FUNCTION__, mId.string()); mPreparerThread->pause(); camera3_stream_configuration config; config.operation_mode = mOperatingMode; config.num_streams = (mInputStream != NULL) + mOutputStreams.size(); Loading Loading @@ -2338,7 +2392,9 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, // Request thread needs to know to avoid using repeat-last-settings protocol // across configure_streams() calls mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration); if (notifyRequestThread) { mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration, sessionParams); } char value[PROPERTY_VALUE_MAX]; property_get("camera.fifo.disable", value, "0"); Loading Loading @@ -2376,6 +2432,12 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, // tear down the deleted streams after configure streams. mDeletedStreams.clear(); auto rc = mPreparerThread->resume(); if (rc != OK) { SET_ERR_L("%s: Camera %s: Preparer thread failed to resume!", __FUNCTION__, mId.string()); return rc; } return OK; } Loading Loading @@ -3747,7 +3809,7 @@ void Camera3Device::HalInterface::onBufferFreed( Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, sp<StatusTracker> statusTracker, sp<HalInterface> interface) : sp<HalInterface> interface, const Vector<int32_t>& sessionParamKeys) : Thread(/*canCallJava*/false), mParent(parent), mStatusTracker(statusTracker), Loading @@ -3764,7 +3826,9 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, mRepeatingLastFrameNumber( hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES), mPrepareVideoStream(false), mRequestLatency(kRequestLatencyBinSize) { mRequestLatency(kRequestLatencyBinSize), mSessionParamKeys(sessionParamKeys), mLatestSessionParams(sessionParamKeys.size()) { mStatusId = statusTracker->addComponent(); } Loading @@ -3777,10 +3841,12 @@ void Camera3Device::RequestThread::setNotificationListener( mListener = listener; } void Camera3Device::RequestThread::configurationComplete(bool isConstrainedHighSpeed) { void Camera3Device::RequestThread::configurationComplete(bool isConstrainedHighSpeed, const CameraMetadata& sessionParams) { ATRACE_CALL(); Mutex::Autolock l(mRequestLock); mReconfigured = true; mLatestSessionParams = sessionParams; // Prepare video stream for high speed recording. mPrepareVideoStream = isConstrainedHighSpeed; } Loading Loading @@ -4191,6 +4257,52 @@ nsecs_t Camera3Device::RequestThread::calculateMaxExpectedDuration(const camera_ return maxExpectedDuration; } bool Camera3Device::RequestThread::updateSessionParameters(const CameraMetadata& settings) { ATRACE_CALL(); bool updatesDetected = false; for (auto tag : mSessionParamKeys) { camera_metadata_ro_entry entry = settings.find(tag); camera_metadata_entry lastEntry = mLatestSessionParams.find(tag); if (entry.count > 0) { bool isDifferent = false; if (lastEntry.count > 0) { // Have a last value, compare to see if changed if (lastEntry.type == entry.type && lastEntry.count == entry.count) { // Same type and count, compare values size_t bytesPerValue = camera_metadata_type_size[lastEntry.type]; size_t entryBytes = bytesPerValue * lastEntry.count; int cmp = memcmp(entry.data.u8, lastEntry.data.u8, entryBytes); if (cmp != 0) { isDifferent = true; } } else { // Count or type has changed isDifferent = true; } } else { // No last entry, so always consider to be different isDifferent = true; } if (isDifferent) { ALOGV("%s: Session parameter tag id %d changed", __FUNCTION__, tag); mLatestSessionParams.update(entry); updatesDetected = true; } } else if (lastEntry.count > 0) { // Value has been removed ALOGV("%s: Session parameter tag id %d removed", __FUNCTION__, tag); mLatestSessionParams.erase(tag); updatesDetected = true; } } return updatesDetected; } bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; Loading @@ -4217,6 +4329,49 @@ bool Camera3Device::RequestThread::threadLoop() { latestRequestId = NAME_NOT_FOUND; } // 'mNextRequests' will at this point contain either a set of HFR batched requests // or a single request from streaming or burst. In either case the first element // should contain the latest camera settings that we need to check for any session // parameter updates. if (updateSessionParameters(mNextRequests[0].captureRequest->mSettings)) { res = OK; //Input stream buffers are already acquired at this point so an input stream //will not be able to move to idle state unless we force it. if (mNextRequests[0].captureRequest->mInputStream != nullptr) { res = mNextRequests[0].captureRequest->mInputStream->forceToIdle(); if (res != OK) { ALOGE("%s: Failed to force idle input stream: %d", __FUNCTION__, res); cleanUpFailedRequests(/*sendRequestError*/ false); return false; } } if (res == OK) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE); sp<Camera3Device> parent = mParent.promote(); if (parent != nullptr) { mReconfigured |= parent->reconfigureCamera(mLatestSessionParams); } statusTracker->markComponentActive(mStatusId); setPaused(false); } if (mNextRequests[0].captureRequest->mInputStream != nullptr) { mNextRequests[0].captureRequest->mInputStream->restoreConfiguredState(); if (res != OK) { ALOGE("%s: Failed to restore configured input stream: %d", __FUNCTION__, res); cleanUpFailedRequests(/*sendRequestError*/ false); return false; } } } } // Prepare a batch of HAL requests and output buffers. res = prepareHalRequests(); if (res == TIMED_OUT) { Loading Loading @@ -4980,7 +5135,7 @@ status_t Camera3Device::RequestThread::addDummyTriggerIds( Camera3Device::PreparerThread::PreparerThread() : Thread(/*canCallJava*/false), mListener(nullptr), mActive(false), mCancelNow(false) { mActive(false), mCancelNow(false), mCurrentMaxCount(0), mCurrentPrepareComplete(false) { } Camera3Device::PreparerThread::~PreparerThread() { Loading Loading @@ -5031,18 +5186,101 @@ status_t Camera3Device::PreparerThread::prepare(int maxCount, sp<Camera3StreamIn } // queue up the work mPendingStreams.push_back(stream); mPendingStreams.emplace(maxCount, stream); ALOGV("%s: Stream %d queued for preparing", __FUNCTION__, stream->getId()); return OK; } void Camera3Device::PreparerThread::pause() { ATRACE_CALL(); Mutex::Autolock l(mLock); std::unordered_map<int, sp<camera3::Camera3StreamInterface> > pendingStreams; pendingStreams.insert(mPendingStreams.begin(), mPendingStreams.end()); sp<camera3::Camera3StreamInterface> currentStream = mCurrentStream; int currentMaxCount = mCurrentMaxCount; mPendingStreams.clear(); mCancelNow = true; while (mActive) { auto res = mThreadActiveSignal.waitRelative(mLock, kActiveTimeout); if (res == TIMED_OUT) { ALOGE("%s: Timed out waiting on prepare thread!", __FUNCTION__); return; } else if (res != OK) { ALOGE("%s: Encountered an error: %d waiting on prepare thread!", __FUNCTION__, res); return; } } //Check whether the prepare thread was able to complete the current //stream. In case work is still pending emplace it along with the rest //of the streams in the pending list. if (currentStream != nullptr) { if (!mCurrentPrepareComplete) { pendingStreams.emplace(currentMaxCount, currentStream); } } mPendingStreams.insert(pendingStreams.begin(), pendingStreams.end()); for (const auto& it : mPendingStreams) { it.second->cancelPrepare(); } } status_t Camera3Device::PreparerThread::resume() { ATRACE_CALL(); status_t res; Mutex::Autolock l(mLock); sp<NotificationListener> listener = mListener.promote(); if (mActive) { ALOGE("%s: Trying to resume an already active prepare thread!", __FUNCTION__); return NO_INIT; } auto it = mPendingStreams.begin(); for (; it != mPendingStreams.end();) { res = it->second->startPrepare(it->first); if (res == OK) { if (listener != NULL) { listener->notifyPrepared(it->second->getId()); } it = mPendingStreams.erase(it); } else if (res != NOT_ENOUGH_DATA) { ALOGE("%s: Unable to start preparer stream: %d (%s)", __FUNCTION__, res, strerror(-res)); it = mPendingStreams.erase(it); } else { it++; } } if (mPendingStreams.empty()) { return OK; } res = Thread::run("C3PrepThread", PRIORITY_BACKGROUND); if (res != OK) { ALOGE("%s: Unable to start preparer stream: %d (%s)", __FUNCTION__, res, strerror(-res)); return res; } mCancelNow = false; mActive = true; ALOGV("%s: Preparer stream started", __FUNCTION__); return OK; } status_t Camera3Device::PreparerThread::clear() { ATRACE_CALL(); Mutex::Autolock l(mLock); for (const auto& stream : mPendingStreams) { stream->cancelPrepare(); for (const auto& it : mPendingStreams) { it.second->cancelPrepare(); } mPendingStreams.clear(); mCancelNow = true; Loading @@ -5067,12 +5305,15 @@ bool Camera3Device::PreparerThread::threadLoop() { // threadLoop _must not_ re-acquire mLock after it sets mActive to false; would // cause deadlock with prepare()'s requestExitAndWait triggered by !mActive. mActive = false; mThreadActiveSignal.signal(); return false; } // Get next stream to prepare auto it = mPendingStreams.begin(); mCurrentStream = *it; mCurrentStream = it->second; mCurrentMaxCount = it->first; mCurrentPrepareComplete = false; mPendingStreams.erase(it); ATRACE_ASYNC_BEGIN("stream prepare", mCurrentStream->getId()); ALOGV("%s: Preparing stream %d", __FUNCTION__, mCurrentStream->getId()); Loading Loading @@ -5107,6 +5348,7 @@ bool Camera3Device::PreparerThread::threadLoop() { ATRACE_ASYNC_END("stream prepare", mCurrentStream->getId()); mCurrentStream.clear(); mCurrentPrepareComplete = true; return true; } Loading services/camera/libcameraservice/device3/Camera3Device.h +39 −4 Original line number Diff line number Diff line Loading @@ -551,12 +551,24 @@ class Camera3Device : sp<CaptureRequest> createCaptureRequest(const CameraMetadata &request, const SurfaceMap &surfaceMap); /** * Internally re-configure camera device using new session parameters. * This will get triggered by the request thread. */ bool reconfigureCamera(const CameraMetadata& sessionParams); /** * Filter stream session parameters and configure camera HAL. */ status_t filterParamsAndConfigureLocked(const CameraMetadata& sessionParams, int operatingMode); /** * Take the currently-defined set of streams and configure the HAL to use * them. This is a long-running operation (may be several hundered ms). */ status_t configureStreamsLocked(int operatingMode, const CameraMetadata& sessionParams); const CameraMetadata& sessionParams, bool notifyRequestThread = true); /** * Cancel stream configuration that did not finish successfully. Loading Loading @@ -655,7 +667,7 @@ class Camera3Device : RequestThread(wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker, sp<HalInterface> interface); sp<HalInterface> interface, const Vector<int32_t>& sessionParamKeys); ~RequestThread(); void setNotificationListener(wp<NotificationListener> listener); Loading @@ -663,7 +675,8 @@ class Camera3Device : /** * Call after stream (re)-configuration is completed. */ void configurationComplete(bool isConstrainedHighSpeed); void configurationComplete(bool isConstrainedHighSpeed, const CameraMetadata& sessionParams); /** * Set or clear the list of repeating requests. Does not block Loading Loading @@ -812,6 +825,12 @@ class Camera3Device : // Calculate the expected maximum duration for a request nsecs_t calculateMaxExpectedDuration(const camera_metadata_t *request); // Check and update latest session parameters based on the current request settings. bool updateSessionParameters(const CameraMetadata& settings); // Re-configure camera using the latest session parameters. bool reconfigureCamera(); wp<Camera3Device> mParent; wp<camera3::StatusTracker> mStatusTracker; sp<HalInterface> mInterface; Loading Loading @@ -869,6 +888,9 @@ class Camera3Device : static const int32_t kRequestLatencyBinSize = 40; // in ms CameraLatencyHistogram mRequestLatency; Vector<int32_t> mSessionParamKeys; CameraMetadata mLatestSessionParams; }; sp<RequestThread> mRequestThread; Loading Loading @@ -1006,21 +1028,34 @@ class Camera3Device : */ status_t clear(); /** * Pause all preparation activities */ void pause(); /** * Resume preparation activities */ status_t resume(); private: Mutex mLock; Condition mThreadActiveSignal; virtual bool threadLoop(); // Guarded by mLock wp<NotificationListener> mListener; List<sp<camera3::Camera3StreamInterface> > mPendingStreams; std::unordered_map<int, sp<camera3::Camera3StreamInterface> > mPendingStreams; bool mActive; bool mCancelNow; // Only accessed by threadLoop and the destructor sp<camera3::Camera3StreamInterface> mCurrentStream; int mCurrentMaxCount; bool mCurrentPrepareComplete; }; sp<PreparerThread> mPreparerThread; Loading services/camera/libcameraservice/device3/Camera3Stream.cpp +82 −1 Original line number Diff line number Diff line Loading @@ -140,6 +140,75 @@ android_dataspace Camera3Stream::getOriginalDataSpace() const { return mOriginalDataSpace; } status_t Camera3Stream::forceToIdle() { ATRACE_CALL(); Mutex::Autolock l(mLock); status_t res; switch (mState) { case STATE_ERROR: case STATE_CONSTRUCTED: case STATE_IN_CONFIG: case STATE_PREPARING: case STATE_IN_RECONFIG: ALOGE("%s: Invalid state: %d", __FUNCTION__, mState); res = NO_INIT; break; case STATE_CONFIGURED: if (hasOutstandingBuffersLocked()) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE); } } mState = STATE_IN_IDLE; res = OK; break; default: ALOGE("%s: Unknown state %d", __FUNCTION__, mState); res = NO_INIT; } return res; } status_t Camera3Stream::restoreConfiguredState() { ATRACE_CALL(); Mutex::Autolock l(mLock); status_t res; switch (mState) { case STATE_ERROR: case STATE_CONSTRUCTED: case STATE_IN_CONFIG: case STATE_PREPARING: case STATE_IN_RECONFIG: case STATE_CONFIGURED: ALOGE("%s: Invalid state: %d", __FUNCTION__, mState); res = NO_INIT; break; case STATE_IN_IDLE: if (hasOutstandingBuffersLocked()) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentActive(mStatusId); } } mState = STATE_CONFIGURED; res = OK; break; default: ALOGE("%s: Unknown state %d", __FUNCTION__, mState); res = NO_INIT; } return res; } camera3_stream* Camera3Stream::startConfiguration() { ATRACE_CALL(); Mutex::Autolock l(mLock); Loading @@ -150,6 +219,7 @@ camera3_stream* Camera3Stream::startConfiguration() { ALOGE("%s: In error state", __FUNCTION__); return NULL; case STATE_CONSTRUCTED: case STATE_IN_IDLE: // OK break; case STATE_IN_CONFIG: Loading Loading @@ -179,6 +249,11 @@ camera3_stream* Camera3Stream::startConfiguration() { return NULL; } if (mState == STATE_IN_IDLE) { // Skip configuration. return this; } // Stop tracking if currently doing so if (mStatusId != StatusTracker::NO_STATUS_ID) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); Loading Loading @@ -219,6 +294,9 @@ status_t Camera3Stream::finishConfiguration() { ALOGE("%s: Cannot finish configuration that hasn't been started", __FUNCTION__); return INVALID_OPERATION; case STATE_IN_IDLE: //Skip configuration in this state return OK; default: ALOGE("%s: Unknown state", __FUNCTION__); return INVALID_OPERATION; Loading Loading @@ -267,6 +345,7 @@ status_t Camera3Stream::cancelConfiguration() { return INVALID_OPERATION; case STATE_IN_CONFIG: case STATE_IN_RECONFIG: case STATE_IN_IDLE: // OK break; case STATE_CONSTRUCTED: Loading @@ -282,7 +361,9 @@ status_t Camera3Stream::cancelConfiguration() { mUsage = mOldUsage; camera3_stream::max_buffers = mOldMaxBuffers; mState = (mState == STATE_IN_RECONFIG) ? STATE_CONFIGURED : STATE_CONSTRUCTED; mState = ((mState == STATE_IN_RECONFIG) || (mState == STATE_IN_IDLE)) ? STATE_CONFIGURED : STATE_CONSTRUCTED; return OK; } Loading services/camera/libcameraservice/device3/Camera3Stream.h +29 −2 Original line number Diff line number Diff line Loading @@ -68,6 +68,12 @@ namespace camera3 { * duration. In this state, only prepareNextBuffer() and cancelPrepare() * may be called. * * STATE_IN_IDLE: This is a temporary state only intended to be used for input * streams and only for the case where we need to re-configure the camera device * while the input stream has an outstanding buffer. All other streams should not * be able to switch to this state. For them this is invalid and should be handled * as an unknown state. * * Transition table: * * <none> => STATE_CONSTRUCTED: Loading Loading @@ -98,6 +104,11 @@ namespace camera3 { * all stream buffers, or cancelPrepare is called. * STATE_CONFIGURED => STATE_ABANDONED: * When the buffer queue of the stream is abandoned. * STATE_CONFIGURED => STATE_IN_IDLE: * Only for an input stream which has an outstanding buffer. * STATE_IN_IDLE => STATE_CONFIGURED: * After the internal re-configuration, the input should revert back to * the configured state. * * Status Tracking: * Each stream is tracked by StatusTracker as a separate component, Loading @@ -108,7 +119,9 @@ namespace camera3 { * * - ACTIVE: One or more buffers have been handed out (with #getBuffer). * - IDLE: All buffers have been returned (with #returnBuffer), and their * respective release_fence(s) have been signaled. * respective release_fence(s) have been signaled. The only exception to this * rule is an input stream that moves to "STATE_IN_IDLE" during internal * re-configuration. * * A typical use case is output streams. When the HAL has any buffers * dequeued, the stream is marked ACTIVE. When the HAL returns all buffers Loading Loading @@ -386,6 +399,19 @@ class Camera3Stream : */ bool isAbandoned() const; /** * Switch a configured stream with possibly outstanding buffers in idle * state. Configuration for such streams will be skipped assuming there * are no changes to the stream parameters. */ status_t forceToIdle(); /** * Restore a forced idle stream to configured state, marking it active * in case it contains outstanding buffers. */ status_t restoreConfiguredState(); protected: const int mId; /** Loading Loading @@ -414,7 +440,8 @@ class Camera3Stream : STATE_IN_RECONFIG, STATE_CONFIGURED, STATE_PREPARING, STATE_ABANDONED STATE_ABANDONED, STATE_IN_IDLE } mState; mutable Mutex mLock; Loading Loading
services/camera/libcameraservice/device3/Camera3Device.cpp +255 −13 Original line number Diff line number Diff line Loading @@ -194,8 +194,14 @@ status_t Camera3Device::initializeCommonLocked() { mTagMonitor.initialize(mVendorTagId); Vector<int32_t> sessionParamKeys; camera_metadata_entry_t sessionKeysEntry = mDeviceInfo.find( ANDROID_REQUEST_AVAILABLE_SESSION_KEYS); if (sessionKeysEntry.count > 0) { sessionParamKeys.insertArrayAt(sessionKeysEntry.data.i32, 0, sessionKeysEntry.count); } /** Start up request queue thread */ mRequestThread = new RequestThread(this, mStatusTracker, mInterface); mRequestThread = new RequestThread(this, mStatusTracker, mInterface, sessionParamKeys); res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string()); if (res != OK) { SET_ERR_L("Unable to start request queue thread: %s (%d)", Loading Loading @@ -1104,7 +1110,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked( if (mStatus == STATUS_UNCONFIGURED || mNeedConfig) { // This point should only be reached via API1 (API2 must explicitly call configureStreams) // so unilaterally select normal operating mode. res = configureStreamsLocked(CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE, mSessionParams); res = filterParamsAndConfigureLocked(request, CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE); // Stream configuration failed. Client might try other configuraitons. if (res != OK) { CLOGE("Can't set up streams: %s (%d)", strerror(-res), res); Loading Loading @@ -1508,11 +1514,20 @@ status_t Camera3Device::configureStreams(const CameraMetadata& sessionParams, in Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); return filterParamsAndConfigureLocked(sessionParams, operatingMode); } status_t Camera3Device::filterParamsAndConfigureLocked(const CameraMetadata& sessionParams, int operatingMode) { //Filter out any incoming session parameters const CameraMetadata params(sessionParams); CameraMetadata filteredParams; camera_metadata_entry_t availableSessionKeys = mDeviceInfo.find( ANDROID_REQUEST_AVAILABLE_SESSION_KEYS); CameraMetadata filteredParams(availableSessionKeys.count); camera_metadata_t *meta = const_cast<camera_metadata_t *>( filteredParams.getAndLock()); set_camera_metadata_vendor_id(meta, mVendorTagId); filteredParams.unlock(meta); if (availableSessionKeys.count > 0) { for (size_t i = 0; i < availableSessionKeys.count; i++) { camera_metadata_ro_entry entry = params.find( Loading Loading @@ -2203,10 +2218,47 @@ void Camera3Device::cancelStreamsConfigurationLocked() { // properly clean things up internalUpdateStatusLocked(STATUS_UNCONFIGURED); mNeedConfig = true; res = mPreparerThread->resume(); if (res != OK) { ALOGE("%s: Camera %s: Preparer thread failed to resume!", __FUNCTION__, mId.string()); } } bool Camera3Device::reconfigureCamera(const CameraMetadata& sessionParams) { ATRACE_CALL(); bool ret = false; Mutex::Autolock il(mInterfaceLock); nsecs_t maxExpectedDuration = getExpectedInFlightDuration(); Mutex::Autolock l(mLock); auto rc = internalPauseAndWaitLocked(maxExpectedDuration); if (rc == NO_ERROR) { mNeedConfig = true; rc = configureStreamsLocked(mOperatingMode, sessionParams, /*notifyRequestThread*/ false); if (rc == NO_ERROR) { ret = true; mPauseStateNotify = false; //Moving to active state while holding 'mLock' is important. //There could be pending calls to 'create-/deleteStream' which //will trigger another stream configuration while the already //present streams end up with outstanding buffers that will //not get drained. internalUpdateStatusLocked(STATUS_ACTIVE); } else { setErrorStateLocked("%s: Failed to re-configure camera: %d", __FUNCTION__, rc); } } else { ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc); } return ret; } status_t Camera3Device::configureStreamsLocked(int operatingMode, const CameraMetadata& sessionParams) { const CameraMetadata& sessionParams, bool notifyRequestThread) { ATRACE_CALL(); status_t res; Loading Loading @@ -2247,6 +2299,8 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, // Start configuring the streams ALOGV("%s: Camera %s: Starting stream configuration", __FUNCTION__, mId.string()); mPreparerThread->pause(); camera3_stream_configuration config; config.operation_mode = mOperatingMode; config.num_streams = (mInputStream != NULL) + mOutputStreams.size(); Loading Loading @@ -2338,7 +2392,9 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, // Request thread needs to know to avoid using repeat-last-settings protocol // across configure_streams() calls mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration); if (notifyRequestThread) { mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration, sessionParams); } char value[PROPERTY_VALUE_MAX]; property_get("camera.fifo.disable", value, "0"); Loading Loading @@ -2376,6 +2432,12 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, // tear down the deleted streams after configure streams. mDeletedStreams.clear(); auto rc = mPreparerThread->resume(); if (rc != OK) { SET_ERR_L("%s: Camera %s: Preparer thread failed to resume!", __FUNCTION__, mId.string()); return rc; } return OK; } Loading Loading @@ -3747,7 +3809,7 @@ void Camera3Device::HalInterface::onBufferFreed( Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, sp<StatusTracker> statusTracker, sp<HalInterface> interface) : sp<HalInterface> interface, const Vector<int32_t>& sessionParamKeys) : Thread(/*canCallJava*/false), mParent(parent), mStatusTracker(statusTracker), Loading @@ -3764,7 +3826,9 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, mRepeatingLastFrameNumber( hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES), mPrepareVideoStream(false), mRequestLatency(kRequestLatencyBinSize) { mRequestLatency(kRequestLatencyBinSize), mSessionParamKeys(sessionParamKeys), mLatestSessionParams(sessionParamKeys.size()) { mStatusId = statusTracker->addComponent(); } Loading @@ -3777,10 +3841,12 @@ void Camera3Device::RequestThread::setNotificationListener( mListener = listener; } void Camera3Device::RequestThread::configurationComplete(bool isConstrainedHighSpeed) { void Camera3Device::RequestThread::configurationComplete(bool isConstrainedHighSpeed, const CameraMetadata& sessionParams) { ATRACE_CALL(); Mutex::Autolock l(mRequestLock); mReconfigured = true; mLatestSessionParams = sessionParams; // Prepare video stream for high speed recording. mPrepareVideoStream = isConstrainedHighSpeed; } Loading Loading @@ -4191,6 +4257,52 @@ nsecs_t Camera3Device::RequestThread::calculateMaxExpectedDuration(const camera_ return maxExpectedDuration; } bool Camera3Device::RequestThread::updateSessionParameters(const CameraMetadata& settings) { ATRACE_CALL(); bool updatesDetected = false; for (auto tag : mSessionParamKeys) { camera_metadata_ro_entry entry = settings.find(tag); camera_metadata_entry lastEntry = mLatestSessionParams.find(tag); if (entry.count > 0) { bool isDifferent = false; if (lastEntry.count > 0) { // Have a last value, compare to see if changed if (lastEntry.type == entry.type && lastEntry.count == entry.count) { // Same type and count, compare values size_t bytesPerValue = camera_metadata_type_size[lastEntry.type]; size_t entryBytes = bytesPerValue * lastEntry.count; int cmp = memcmp(entry.data.u8, lastEntry.data.u8, entryBytes); if (cmp != 0) { isDifferent = true; } } else { // Count or type has changed isDifferent = true; } } else { // No last entry, so always consider to be different isDifferent = true; } if (isDifferent) { ALOGV("%s: Session parameter tag id %d changed", __FUNCTION__, tag); mLatestSessionParams.update(entry); updatesDetected = true; } } else if (lastEntry.count > 0) { // Value has been removed ALOGV("%s: Session parameter tag id %d removed", __FUNCTION__, tag); mLatestSessionParams.erase(tag); updatesDetected = true; } } return updatesDetected; } bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; Loading @@ -4217,6 +4329,49 @@ bool Camera3Device::RequestThread::threadLoop() { latestRequestId = NAME_NOT_FOUND; } // 'mNextRequests' will at this point contain either a set of HFR batched requests // or a single request from streaming or burst. In either case the first element // should contain the latest camera settings that we need to check for any session // parameter updates. if (updateSessionParameters(mNextRequests[0].captureRequest->mSettings)) { res = OK; //Input stream buffers are already acquired at this point so an input stream //will not be able to move to idle state unless we force it. if (mNextRequests[0].captureRequest->mInputStream != nullptr) { res = mNextRequests[0].captureRequest->mInputStream->forceToIdle(); if (res != OK) { ALOGE("%s: Failed to force idle input stream: %d", __FUNCTION__, res); cleanUpFailedRequests(/*sendRequestError*/ false); return false; } } if (res == OK) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE); sp<Camera3Device> parent = mParent.promote(); if (parent != nullptr) { mReconfigured |= parent->reconfigureCamera(mLatestSessionParams); } statusTracker->markComponentActive(mStatusId); setPaused(false); } if (mNextRequests[0].captureRequest->mInputStream != nullptr) { mNextRequests[0].captureRequest->mInputStream->restoreConfiguredState(); if (res != OK) { ALOGE("%s: Failed to restore configured input stream: %d", __FUNCTION__, res); cleanUpFailedRequests(/*sendRequestError*/ false); return false; } } } } // Prepare a batch of HAL requests and output buffers. res = prepareHalRequests(); if (res == TIMED_OUT) { Loading Loading @@ -4980,7 +5135,7 @@ status_t Camera3Device::RequestThread::addDummyTriggerIds( Camera3Device::PreparerThread::PreparerThread() : Thread(/*canCallJava*/false), mListener(nullptr), mActive(false), mCancelNow(false) { mActive(false), mCancelNow(false), mCurrentMaxCount(0), mCurrentPrepareComplete(false) { } Camera3Device::PreparerThread::~PreparerThread() { Loading Loading @@ -5031,18 +5186,101 @@ status_t Camera3Device::PreparerThread::prepare(int maxCount, sp<Camera3StreamIn } // queue up the work mPendingStreams.push_back(stream); mPendingStreams.emplace(maxCount, stream); ALOGV("%s: Stream %d queued for preparing", __FUNCTION__, stream->getId()); return OK; } void Camera3Device::PreparerThread::pause() { ATRACE_CALL(); Mutex::Autolock l(mLock); std::unordered_map<int, sp<camera3::Camera3StreamInterface> > pendingStreams; pendingStreams.insert(mPendingStreams.begin(), mPendingStreams.end()); sp<camera3::Camera3StreamInterface> currentStream = mCurrentStream; int currentMaxCount = mCurrentMaxCount; mPendingStreams.clear(); mCancelNow = true; while (mActive) { auto res = mThreadActiveSignal.waitRelative(mLock, kActiveTimeout); if (res == TIMED_OUT) { ALOGE("%s: Timed out waiting on prepare thread!", __FUNCTION__); return; } else if (res != OK) { ALOGE("%s: Encountered an error: %d waiting on prepare thread!", __FUNCTION__, res); return; } } //Check whether the prepare thread was able to complete the current //stream. In case work is still pending emplace it along with the rest //of the streams in the pending list. if (currentStream != nullptr) { if (!mCurrentPrepareComplete) { pendingStreams.emplace(currentMaxCount, currentStream); } } mPendingStreams.insert(pendingStreams.begin(), pendingStreams.end()); for (const auto& it : mPendingStreams) { it.second->cancelPrepare(); } } status_t Camera3Device::PreparerThread::resume() { ATRACE_CALL(); status_t res; Mutex::Autolock l(mLock); sp<NotificationListener> listener = mListener.promote(); if (mActive) { ALOGE("%s: Trying to resume an already active prepare thread!", __FUNCTION__); return NO_INIT; } auto it = mPendingStreams.begin(); for (; it != mPendingStreams.end();) { res = it->second->startPrepare(it->first); if (res == OK) { if (listener != NULL) { listener->notifyPrepared(it->second->getId()); } it = mPendingStreams.erase(it); } else if (res != NOT_ENOUGH_DATA) { ALOGE("%s: Unable to start preparer stream: %d (%s)", __FUNCTION__, res, strerror(-res)); it = mPendingStreams.erase(it); } else { it++; } } if (mPendingStreams.empty()) { return OK; } res = Thread::run("C3PrepThread", PRIORITY_BACKGROUND); if (res != OK) { ALOGE("%s: Unable to start preparer stream: %d (%s)", __FUNCTION__, res, strerror(-res)); return res; } mCancelNow = false; mActive = true; ALOGV("%s: Preparer stream started", __FUNCTION__); return OK; } status_t Camera3Device::PreparerThread::clear() { ATRACE_CALL(); Mutex::Autolock l(mLock); for (const auto& stream : mPendingStreams) { stream->cancelPrepare(); for (const auto& it : mPendingStreams) { it.second->cancelPrepare(); } mPendingStreams.clear(); mCancelNow = true; Loading @@ -5067,12 +5305,15 @@ bool Camera3Device::PreparerThread::threadLoop() { // threadLoop _must not_ re-acquire mLock after it sets mActive to false; would // cause deadlock with prepare()'s requestExitAndWait triggered by !mActive. mActive = false; mThreadActiveSignal.signal(); return false; } // Get next stream to prepare auto it = mPendingStreams.begin(); mCurrentStream = *it; mCurrentStream = it->second; mCurrentMaxCount = it->first; mCurrentPrepareComplete = false; mPendingStreams.erase(it); ATRACE_ASYNC_BEGIN("stream prepare", mCurrentStream->getId()); ALOGV("%s: Preparing stream %d", __FUNCTION__, mCurrentStream->getId()); Loading Loading @@ -5107,6 +5348,7 @@ bool Camera3Device::PreparerThread::threadLoop() { ATRACE_ASYNC_END("stream prepare", mCurrentStream->getId()); mCurrentStream.clear(); mCurrentPrepareComplete = true; return true; } Loading
services/camera/libcameraservice/device3/Camera3Device.h +39 −4 Original line number Diff line number Diff line Loading @@ -551,12 +551,24 @@ class Camera3Device : sp<CaptureRequest> createCaptureRequest(const CameraMetadata &request, const SurfaceMap &surfaceMap); /** * Internally re-configure camera device using new session parameters. * This will get triggered by the request thread. */ bool reconfigureCamera(const CameraMetadata& sessionParams); /** * Filter stream session parameters and configure camera HAL. */ status_t filterParamsAndConfigureLocked(const CameraMetadata& sessionParams, int operatingMode); /** * Take the currently-defined set of streams and configure the HAL to use * them. This is a long-running operation (may be several hundered ms). */ status_t configureStreamsLocked(int operatingMode, const CameraMetadata& sessionParams); const CameraMetadata& sessionParams, bool notifyRequestThread = true); /** * Cancel stream configuration that did not finish successfully. Loading Loading @@ -655,7 +667,7 @@ class Camera3Device : RequestThread(wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker, sp<HalInterface> interface); sp<HalInterface> interface, const Vector<int32_t>& sessionParamKeys); ~RequestThread(); void setNotificationListener(wp<NotificationListener> listener); Loading @@ -663,7 +675,8 @@ class Camera3Device : /** * Call after stream (re)-configuration is completed. */ void configurationComplete(bool isConstrainedHighSpeed); void configurationComplete(bool isConstrainedHighSpeed, const CameraMetadata& sessionParams); /** * Set or clear the list of repeating requests. Does not block Loading Loading @@ -812,6 +825,12 @@ class Camera3Device : // Calculate the expected maximum duration for a request nsecs_t calculateMaxExpectedDuration(const camera_metadata_t *request); // Check and update latest session parameters based on the current request settings. bool updateSessionParameters(const CameraMetadata& settings); // Re-configure camera using the latest session parameters. bool reconfigureCamera(); wp<Camera3Device> mParent; wp<camera3::StatusTracker> mStatusTracker; sp<HalInterface> mInterface; Loading Loading @@ -869,6 +888,9 @@ class Camera3Device : static const int32_t kRequestLatencyBinSize = 40; // in ms CameraLatencyHistogram mRequestLatency; Vector<int32_t> mSessionParamKeys; CameraMetadata mLatestSessionParams; }; sp<RequestThread> mRequestThread; Loading Loading @@ -1006,21 +1028,34 @@ class Camera3Device : */ status_t clear(); /** * Pause all preparation activities */ void pause(); /** * Resume preparation activities */ status_t resume(); private: Mutex mLock; Condition mThreadActiveSignal; virtual bool threadLoop(); // Guarded by mLock wp<NotificationListener> mListener; List<sp<camera3::Camera3StreamInterface> > mPendingStreams; std::unordered_map<int, sp<camera3::Camera3StreamInterface> > mPendingStreams; bool mActive; bool mCancelNow; // Only accessed by threadLoop and the destructor sp<camera3::Camera3StreamInterface> mCurrentStream; int mCurrentMaxCount; bool mCurrentPrepareComplete; }; sp<PreparerThread> mPreparerThread; Loading
services/camera/libcameraservice/device3/Camera3Stream.cpp +82 −1 Original line number Diff line number Diff line Loading @@ -140,6 +140,75 @@ android_dataspace Camera3Stream::getOriginalDataSpace() const { return mOriginalDataSpace; } status_t Camera3Stream::forceToIdle() { ATRACE_CALL(); Mutex::Autolock l(mLock); status_t res; switch (mState) { case STATE_ERROR: case STATE_CONSTRUCTED: case STATE_IN_CONFIG: case STATE_PREPARING: case STATE_IN_RECONFIG: ALOGE("%s: Invalid state: %d", __FUNCTION__, mState); res = NO_INIT; break; case STATE_CONFIGURED: if (hasOutstandingBuffersLocked()) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE); } } mState = STATE_IN_IDLE; res = OK; break; default: ALOGE("%s: Unknown state %d", __FUNCTION__, mState); res = NO_INIT; } return res; } status_t Camera3Stream::restoreConfiguredState() { ATRACE_CALL(); Mutex::Autolock l(mLock); status_t res; switch (mState) { case STATE_ERROR: case STATE_CONSTRUCTED: case STATE_IN_CONFIG: case STATE_PREPARING: case STATE_IN_RECONFIG: case STATE_CONFIGURED: ALOGE("%s: Invalid state: %d", __FUNCTION__, mState); res = NO_INIT; break; case STATE_IN_IDLE: if (hasOutstandingBuffersLocked()) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentActive(mStatusId); } } mState = STATE_CONFIGURED; res = OK; break; default: ALOGE("%s: Unknown state %d", __FUNCTION__, mState); res = NO_INIT; } return res; } camera3_stream* Camera3Stream::startConfiguration() { ATRACE_CALL(); Mutex::Autolock l(mLock); Loading @@ -150,6 +219,7 @@ camera3_stream* Camera3Stream::startConfiguration() { ALOGE("%s: In error state", __FUNCTION__); return NULL; case STATE_CONSTRUCTED: case STATE_IN_IDLE: // OK break; case STATE_IN_CONFIG: Loading Loading @@ -179,6 +249,11 @@ camera3_stream* Camera3Stream::startConfiguration() { return NULL; } if (mState == STATE_IN_IDLE) { // Skip configuration. return this; } // Stop tracking if currently doing so if (mStatusId != StatusTracker::NO_STATUS_ID) { sp<StatusTracker> statusTracker = mStatusTracker.promote(); Loading Loading @@ -219,6 +294,9 @@ status_t Camera3Stream::finishConfiguration() { ALOGE("%s: Cannot finish configuration that hasn't been started", __FUNCTION__); return INVALID_OPERATION; case STATE_IN_IDLE: //Skip configuration in this state return OK; default: ALOGE("%s: Unknown state", __FUNCTION__); return INVALID_OPERATION; Loading Loading @@ -267,6 +345,7 @@ status_t Camera3Stream::cancelConfiguration() { return INVALID_OPERATION; case STATE_IN_CONFIG: case STATE_IN_RECONFIG: case STATE_IN_IDLE: // OK break; case STATE_CONSTRUCTED: Loading @@ -282,7 +361,9 @@ status_t Camera3Stream::cancelConfiguration() { mUsage = mOldUsage; camera3_stream::max_buffers = mOldMaxBuffers; mState = (mState == STATE_IN_RECONFIG) ? STATE_CONFIGURED : STATE_CONSTRUCTED; mState = ((mState == STATE_IN_RECONFIG) || (mState == STATE_IN_IDLE)) ? STATE_CONFIGURED : STATE_CONSTRUCTED; return OK; } Loading
services/camera/libcameraservice/device3/Camera3Stream.h +29 −2 Original line number Diff line number Diff line Loading @@ -68,6 +68,12 @@ namespace camera3 { * duration. In this state, only prepareNextBuffer() and cancelPrepare() * may be called. * * STATE_IN_IDLE: This is a temporary state only intended to be used for input * streams and only for the case where we need to re-configure the camera device * while the input stream has an outstanding buffer. All other streams should not * be able to switch to this state. For them this is invalid and should be handled * as an unknown state. * * Transition table: * * <none> => STATE_CONSTRUCTED: Loading Loading @@ -98,6 +104,11 @@ namespace camera3 { * all stream buffers, or cancelPrepare is called. * STATE_CONFIGURED => STATE_ABANDONED: * When the buffer queue of the stream is abandoned. * STATE_CONFIGURED => STATE_IN_IDLE: * Only for an input stream which has an outstanding buffer. * STATE_IN_IDLE => STATE_CONFIGURED: * After the internal re-configuration, the input should revert back to * the configured state. * * Status Tracking: * Each stream is tracked by StatusTracker as a separate component, Loading @@ -108,7 +119,9 @@ namespace camera3 { * * - ACTIVE: One or more buffers have been handed out (with #getBuffer). * - IDLE: All buffers have been returned (with #returnBuffer), and their * respective release_fence(s) have been signaled. * respective release_fence(s) have been signaled. The only exception to this * rule is an input stream that moves to "STATE_IN_IDLE" during internal * re-configuration. * * A typical use case is output streams. When the HAL has any buffers * dequeued, the stream is marked ACTIVE. When the HAL returns all buffers Loading Loading @@ -386,6 +399,19 @@ class Camera3Stream : */ bool isAbandoned() const; /** * Switch a configured stream with possibly outstanding buffers in idle * state. Configuration for such streams will be skipped assuming there * are no changes to the stream parameters. */ status_t forceToIdle(); /** * Restore a forced idle stream to configured state, marking it active * in case it contains outstanding buffers. */ status_t restoreConfiguredState(); protected: const int mId; /** Loading Loading @@ -414,7 +440,8 @@ class Camera3Stream : STATE_IN_RECONFIG, STATE_CONFIGURED, STATE_PREPARING, STATE_ABANDONED STATE_ABANDONED, STATE_IN_IDLE } mState; mutable Mutex mLock; Loading