Loading services/camera/libcameraservice/device3/Camera3Device.cpp +318 −186 Original line number Diff line number Diff line Loading @@ -565,6 +565,18 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); } // Setup batch size if this is a high speed video recording request. if (mIsConstrainedHighSpeedConfiguration && requestList->size() > 0) { auto firstRequest = requestList->begin(); for (auto& outputStream : (*firstRequest)->mOutputStreams) { if (outputStream->isVideoStream()) { (*firstRequest)->mBatchSize = requestList->size(); break; } } } return OK; } Loading Loading @@ -1406,7 +1418,7 @@ status_t Camera3Device::flush(int64_t *frameNumber) { status_t res; if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { res = mHal3Device->ops->flush(mHal3Device); res = mRequestThread->flush(); } else { Mutex::Autolock l(mLock); res = waitUntilDrainedLocked(); Loading Loading @@ -1595,6 +1607,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( newRequest->mOutputStreams.push(stream); } newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); newRequest->mBatchSize = 1; return newRequest; } Loading Loading @@ -2766,6 +2779,17 @@ status_t Camera3Device::RequestThread::clear( return OK; } status_t Camera3Device::RequestThread::flush() { ATRACE_CALL(); Mutex::Autolock l(mFlushLock); if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { return mHal3Device->ops->flush(mHal3Device); } return -ENOTSUP; } void Camera3Device::RequestThread::setPaused(bool paused) { Mutex::Autolock l(mPauseLock); mDoPause = paused; Loading Loading @@ -2856,7 +2880,7 @@ void Camera3Device::overrideResultForPrecaptureCancel( } bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; // Handle paused state. Loading @@ -2864,79 +2888,184 @@ bool Camera3Device::RequestThread::threadLoop() { return true; } // Get work to do sp<CaptureRequest> nextRequest = waitForNextRequest(); if (nextRequest == NULL) { // Get next batch of requests. Vector<NextRequest> nextRequests; waitForNextRequestBatch(&nextRequests); const size_t numRequests = nextRequests.size(); if (numRequests == 0) { return true; } // Create request to HAL camera3_capture_request_t request = camera3_capture_request_t(); request.frame_number = nextRequest->mResultExtras.frameNumber; Vector<camera3_stream_buffer_t> outputBuffers; // Get the request ID, if any int requestId; camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); // Get the latest request ID, if any int latestRequestId; camera_metadata_entry_t requestIdEntry = nextRequests[nextRequests.size() - 1]. captureRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { requestId = requestIdEntry.data.i32[0]; latestRequestId = requestIdEntry.data.i32[0]; } else { ALOGW("%s: Did not have android.request.id set in the request", __FUNCTION__); requestId = NAME_NOT_FOUND; ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__); latestRequestId = NAME_NOT_FOUND; } // Prepare a batch of HAL requests and output buffers. res = prepareHalRequests(&nextRequests); if (res == TIMED_OUT) { // Not a fatal error if getting output buffers time out. cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ true); return true; } else if (res != OK) { cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); return false; } // Inform waitUntilRequestProcessed thread of a new request ID { Mutex::Autolock al(mLatestRequestMutex); mLatestRequestId = latestRequestId; mLatestRequestSignal.signal(); } // Submit a batch of requests to HAL. // Use flush lock only when submitting multilple requests in a batch. // TODO: The problem with flush lock is flush() will be blocked by process_capture_request() // which may take a long time to finish so synchronizing flush() and // process_capture_request() defeats the purpose of cancelling requests ASAP with flush(). // For now, only synchronize for high speed recording and we should figure something out for // removing the synchronization. bool useFlushLock = nextRequests.size() > 1; if (useFlushLock) { mFlushLock.lock(); } ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__, nextRequests.size()); for (auto& nextRequest : nextRequests) { // Submit request and block until ready for next one ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number); ATRACE_BEGIN("camera3->process_capture_request"); res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest); ATRACE_END(); if (res != OK) { // Should only get a failure here for malformed requests or device-level // errors, so consider all errors fatal. Bad metadata failures should // come through notify. SET_ERR("RequestThread: Unable to submit capture request %d to HAL" " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), res); cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); if (useFlushLock) { mFlushLock.unlock(); } return false; } // Mark that the request has be submitted successfully. nextRequest.submitted = true; // Update the latest request sent to HAL if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged Mutex::Autolock al(mLatestRequestMutex); camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings); mLatestRequest.acquire(cloned); } if (nextRequest.halRequest.settings != NULL) { nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings); } // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { SET_ERR("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), res); cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); if (useFlushLock) { mFlushLock.unlock(); } return false; } } if (useFlushLock) { mFlushLock.unlock(); } // Unset as current request { Mutex::Autolock l(mRequestLock); mNextRequests.clear(); } return true; } status_t Camera3Device::RequestThread::prepareHalRequests(Vector<NextRequest> *nextRequests) { ATRACE_CALL(); if (nextRequests == nullptr) { return BAD_VALUE; } for (auto& nextRequest : *nextRequests) { sp<CaptureRequest> captureRequest = nextRequest.captureRequest; camera3_capture_request_t* halRequest = &nextRequest.halRequest; Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers; // Prepare a request to HAL halRequest->frame_number = captureRequest->mResultExtras.frameNumber; // Insert any queued triggers (before metadata is locked) int32_t triggerCount; res = insertTriggers(nextRequest); status_t res = insertTriggers(captureRequest); if (res < 0) { SET_ERR("RequestThread: Unable to insert triggers " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; halRequest->frame_number, strerror(-res), res); return INVALID_OPERATION; } triggerCount = res; int triggerCount = res; bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); mPrevTriggers = triggerCount; // If the request is the same as last, or we had triggers last time if (mPrevRequest != nextRequest || triggersMixedIn) { if (mPrevRequest != captureRequest || triggersMixedIn) { /** * HAL workaround: * Insert a dummy trigger ID if a trigger is set but no trigger ID is */ res = addDummyTriggerIds(nextRequest); res = addDummyTriggerIds(captureRequest); if (res != OK) { SET_ERR("RequestThread: Unable to insert dummy trigger IDs " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; halRequest->frame_number, strerror(-res), res); return INVALID_OPERATION; } /** * The request should be presorted so accesses in HAL * are O(logn). Sidenote, sorting a sorted metadata is nop. */ nextRequest->mSettings.sort(); request.settings = nextRequest->mSettings.getAndLock(); mPrevRequest = nextRequest; captureRequest->mSettings.sort(); halRequest->settings = captureRequest->mSettings.getAndLock(); mPrevRequest = captureRequest; ALOGVV("%s: Request settings are NEW", __FUNCTION__); IF_ALOGV() { camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); find_camera_metadata_ro_entry( request.settings, halRequest->settings, ANDROID_CONTROL_AF_TRIGGER, &e ); if (e.count > 0) { ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", __FUNCTION__, request.frame_number, halRequest->frame_number, e.data.u8[0]); } } Loading @@ -2949,118 +3078,56 @@ bool Camera3Device::RequestThread::threadLoop() { uint32_t totalNumBuffers = 0; // Fill in buffers if (nextRequest->mInputStream != NULL) { request.input_buffer = &nextRequest->mInputBuffer; if (captureRequest->mInputStream != NULL) { halRequest->input_buffer = &captureRequest->mInputBuffer; totalNumBuffers += 1; } else { request.input_buffer = NULL; halRequest->input_buffer = NULL; } outputBuffers.insertAt(camera3_stream_buffer_t(), 0, nextRequest->mOutputStreams.size()); request.output_buffers = outputBuffers.array(); for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) { res = nextRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers.editItemAt(i)); outputBuffers->insertAt(camera3_stream_buffer_t(), 0, captureRequest->mOutputStreams.size()); halRequest->output_buffers = outputBuffers->array(); for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) { res = captureRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers->editItemAt(i)); if (res != OK) { // Can't get output buffer from gralloc queue - this could be due to // abandoned queue or other consumer misbehavior, so not a fatal // error ALOGE("RequestThread: Can't get output buffer, skipping request:" " %s (%d)", strerror(-res), res); { Mutex::Autolock l(mRequestLock); if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, nextRequest->mResultExtras); } } cleanUpFailedRequest(request, nextRequest, outputBuffers); return true; return TIMED_OUT; } request.num_output_buffers++; halRequest->num_output_buffers++; } totalNumBuffers += request.num_output_buffers; totalNumBuffers += halRequest->num_output_buffers; // Log request in the in-flight queue sp<Camera3Device> parent = mParent.promote(); if (parent == NULL) { // Should not happen, and nowhere to send errors to, so just log it CLOGE("RequestThread: Parent is gone"); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; return INVALID_OPERATION; } res = parent->registerInFlight(request.frame_number, totalNumBuffers, nextRequest->mResultExtras, /*hasInput*/request.input_buffer != NULL, nextRequest->mAeTriggerCancelOverride); res = parent->registerInFlight(halRequest->frame_number, totalNumBuffers, captureRequest->mResultExtras, /*hasInput*/halRequest->input_buffer != NULL, captureRequest->mAeTriggerCancelOverride); ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 ", burstId = %" PRId32 ".", __FUNCTION__, nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, nextRequest->mResultExtras.burstId); captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber, captureRequest->mResultExtras.burstId); if (res != OK) { SET_ERR("RequestThread: Unable to register new in-flight request:" " %s (%d)", strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } // Inform waitUntilRequestProcessed thread of a new request ID { Mutex::Autolock al(mLatestRequestMutex); mLatestRequestId = requestId; mLatestRequestSignal.signal(); } // Submit request and block until ready for next one ATRACE_ASYNC_BEGIN("frame capture", request.frame_number); ATRACE_BEGIN("camera3->process_capture_request"); res = mHal3Device->ops->process_capture_request(mHal3Device, &request); ATRACE_END(); if (res != OK) { // Should only get a failure here for malformed requests or device-level // errors, so consider all errors fatal. Bad metadata failures should // come through notify. SET_ERR("RequestThread: Unable to submit capture request %d to HAL" " device: %s (%d)", request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } // Update the latest request sent to HAL if (request.settings != NULL) { // Don't update them if they were unchanged Mutex::Autolock al(mLatestRequestMutex); camera_metadata_t* cloned = clone_camera_metadata(request.settings); mLatestRequest.acquire(cloned); } if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); } // Unset as current request { Mutex::Autolock l(mRequestLock); mNextRequest.clear(); return INVALID_OPERATION; } // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { SET_ERR("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); return false; } mPrevTriggers = triggerCount; return true; return OK; } CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { Loading @@ -3075,11 +3142,11 @@ bool Camera3Device::RequestThread::isStreamPending( sp<Camera3StreamInterface>& stream) { Mutex::Autolock l(mRequestLock); if (mNextRequest != nullptr) { for (const auto& s : mNextRequest->mOutputStreams) { for (const auto& nextRequest : mNextRequests) { for (const auto& s : nextRequest->mOutputStreams) { if (stream == s) return true; } if (stream == mNextRequest->mInputStream) return true; if (stream == nextRequest->mInputStream) return true; } for (const auto& request : mRequestQueue) { Loading @@ -3099,37 +3166,104 @@ bool Camera3Device::RequestThread::isStreamPending( return false; } void Camera3Device::RequestThread::cleanUpFailedRequest( camera3_capture_request_t &request, sp<CaptureRequest> &nextRequest, Vector<camera3_stream_buffer_t> &outputBuffers) { void Camera3Device::RequestThread::cleanUpFailedRequests(Vector<NextRequest> *nextRequests, bool sendRequestError) { if (nextRequests == nullptr) { return; } for (auto& nextRequest : *nextRequests) { // Skip the ones that have been submitted successfully. if (nextRequest.submitted) { continue; } sp<CaptureRequest> captureRequest = nextRequest.captureRequest; camera3_capture_request_t* halRequest = &nextRequest.halRequest; Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers; if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); if (halRequest->settings != NULL) { captureRequest->mSettings.unlock(halRequest->settings); } if (nextRequest->mInputStream != NULL) { nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); if (captureRequest->mInputStream != NULL) { captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer); } for (size_t i = 0; i < request.num_output_buffers; i++) { outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( outputBuffers[i], 0); for (size_t i = 0; i < halRequest->num_output_buffers; i++) { outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0); } if (sendRequestError) { Mutex::Autolock l(mRequestLock); mNextRequest.clear(); if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, captureRequest->mResultExtras); } } } sp<Camera3Device::CaptureRequest> Camera3Device::RequestThread::waitForNextRequest() { status_t res; sp<CaptureRequest> nextRequest; Mutex::Autolock l(mRequestLock); mNextRequests.clear(); nextRequests->clear(); } void Camera3Device::RequestThread::waitForNextRequestBatch(Vector<NextRequest> *nextRequests) { if (nextRequests == nullptr) { return; } // Optimized a bit for the simple steady-state case (single repeating // request), to avoid putting that request in the queue temporarily. Mutex::Autolock l(mRequestLock); nextRequests->clear(); assert(mNextRequests.empty()); NextRequest nextRequest; nextRequest.captureRequest = waitForNextRequestLocked(); if (nextRequest.captureRequest == nullptr) { return; } nextRequest.halRequest = camera3_capture_request_t(); nextRequest.submitted = false; nextRequests->add(nextRequest); mNextRequests.push_back(nextRequest.captureRequest); // Wait for additional requests const size_t batchSize = nextRequest.captureRequest->mBatchSize; for (size_t i = 1; i < batchSize; i++) { NextRequest additionalRequest; additionalRequest.captureRequest = waitForNextRequestLocked(); if (additionalRequest.captureRequest == nullptr) { break; } additionalRequest.halRequest = camera3_capture_request_t(); additionalRequest.submitted = false; nextRequests->add(additionalRequest); mNextRequests.push_back(additionalRequest.captureRequest); } if (nextRequests->size() < batchSize) { ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.", nextRequests->size(), batchSize); cleanUpFailedRequests(nextRequests, /*sendRequestError*/true); } return; } sp<Camera3Device::CaptureRequest> Camera3Device::RequestThread::waitForNextRequestLocked() { status_t res; sp<CaptureRequest> nextRequest; while (mRequestQueue.empty()) { if (!mRepeatingRequests.empty()) { // Always atomically enqueue all requests in a repeating request Loading Loading @@ -3224,8 +3358,6 @@ sp<Camera3Device::CaptureRequest> handleAePrecaptureCancelRequest(nextRequest); mNextRequest = nextRequest; return nextRequest; } Loading services/camera/libcameraservice/device3/Camera3Device.h +36 −11 Original line number Diff line number Diff line Loading @@ -264,6 +264,11 @@ class Camera3Device : // Used to cancel AE precapture trigger for devices doesn't support // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL AeTriggerCancelOverride_t mAeTriggerCancelOverride; // The number of requests that should be submitted to HAL at a time. // For example, if batch size is 8, this request and the following 7 // requests will be submitted to HAL at a time. The batch size for // the following 7 requests will be ignored by the request thread. int mBatchSize; }; typedef List<sp<CaptureRequest> > RequestList; Loading Loading @@ -440,6 +445,11 @@ class Camera3Device : /*out*/ int64_t *lastFrameNumber = NULL); /** * Flush all pending requests in HAL. */ status_t flush(); /** * Queue a trigger to be dispatched with the next outgoing * process_capture_request. The settings for that request only Loading Loading @@ -501,16 +511,28 @@ class Camera3Device : static const nsecs_t kRequestTimeout = 50e6; // 50 ms // Waits for a request, or returns NULL if times out. sp<CaptureRequest> waitForNextRequest(); // Used to prepare a batch of requests. struct NextRequest { sp<CaptureRequest> captureRequest; camera3_capture_request_t halRequest; Vector<camera3_stream_buffer_t> outputBuffers; bool submitted; }; // Wait for the next batch of requests. void waitForNextRequestBatch(Vector<NextRequest> *nextRequests); // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold. sp<CaptureRequest> waitForNextRequestLocked(); // Return buffers, etc, for a request that couldn't be fully // constructed. The buffers will be returned in the ERROR state // to mark them as not having valid data. // All arguments will be modified. void cleanUpFailedRequest(camera3_capture_request_t &request, sp<CaptureRequest> &nextRequest, Vector<camera3_stream_buffer_t> &outputBuffers); // Prepare a HAL request and output buffers. Return TIMED_OUT if getting any output buffer // timed out. If an error is returned, the caller should clean up the pending request batch. status_t prepareHalRequests(Vector<NextRequest> *nextRequests); // Return buffers, etc, for a request that couldn't be fully constructed and send request // errors if sendRequestError is true. The buffers will be returned in the ERROR state // to mark them as not having valid data. nextRequests will be modified. void cleanUpFailedRequests(Vector<NextRequest> *nextRequests, bool sendRequestError); // Pause handling bool waitIfPaused(); Loading Loading @@ -539,10 +561,13 @@ class Camera3Device : Condition mRequestSignal; RequestList mRequestQueue; RequestList mRepeatingRequests; // The next request being prepped for submission to the HAL, no longer // The next requests being prepped for submission to the HAL, no longer // on the request queue. Read-only even with mRequestLock held, outside // of threadLoop sp<const CaptureRequest> mNextRequest; RequestList mNextRequests; // To protect flush() and sending a request batch to HAL. Mutex mFlushLock; bool mReconfigured; Loading services/camera/libcameraservice/device3/Camera3DummyStream.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const { return OK; } bool Camera3DummyStream::isVideoStream() const { return false; } }; // namespace camera3 }; // namespace android services/camera/libcameraservice/device3/Camera3DummyStream.h +5 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,11 @@ class Camera3DummyStream : status_t setTransform(int transform); /** * Return if this output stream is for video encoding. */ bool isVideoStream() const; protected: /** Loading services/camera/libcameraservice/device3/Camera3OutputStream.cpp +11 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/camera/libcameraservice/device3/Camera3Device.cpp +318 −186 Original line number Diff line number Diff line Loading @@ -565,6 +565,18 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); } // Setup batch size if this is a high speed video recording request. if (mIsConstrainedHighSpeedConfiguration && requestList->size() > 0) { auto firstRequest = requestList->begin(); for (auto& outputStream : (*firstRequest)->mOutputStreams) { if (outputStream->isVideoStream()) { (*firstRequest)->mBatchSize = requestList->size(); break; } } } return OK; } Loading Loading @@ -1406,7 +1418,7 @@ status_t Camera3Device::flush(int64_t *frameNumber) { status_t res; if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { res = mHal3Device->ops->flush(mHal3Device); res = mRequestThread->flush(); } else { Mutex::Autolock l(mLock); res = waitUntilDrainedLocked(); Loading Loading @@ -1595,6 +1607,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( newRequest->mOutputStreams.push(stream); } newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); newRequest->mBatchSize = 1; return newRequest; } Loading Loading @@ -2766,6 +2779,17 @@ status_t Camera3Device::RequestThread::clear( return OK; } status_t Camera3Device::RequestThread::flush() { ATRACE_CALL(); Mutex::Autolock l(mFlushLock); if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { return mHal3Device->ops->flush(mHal3Device); } return -ENOTSUP; } void Camera3Device::RequestThread::setPaused(bool paused) { Mutex::Autolock l(mPauseLock); mDoPause = paused; Loading Loading @@ -2856,7 +2880,7 @@ void Camera3Device::overrideResultForPrecaptureCancel( } bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; // Handle paused state. Loading @@ -2864,79 +2888,184 @@ bool Camera3Device::RequestThread::threadLoop() { return true; } // Get work to do sp<CaptureRequest> nextRequest = waitForNextRequest(); if (nextRequest == NULL) { // Get next batch of requests. Vector<NextRequest> nextRequests; waitForNextRequestBatch(&nextRequests); const size_t numRequests = nextRequests.size(); if (numRequests == 0) { return true; } // Create request to HAL camera3_capture_request_t request = camera3_capture_request_t(); request.frame_number = nextRequest->mResultExtras.frameNumber; Vector<camera3_stream_buffer_t> outputBuffers; // Get the request ID, if any int requestId; camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); // Get the latest request ID, if any int latestRequestId; camera_metadata_entry_t requestIdEntry = nextRequests[nextRequests.size() - 1]. captureRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { requestId = requestIdEntry.data.i32[0]; latestRequestId = requestIdEntry.data.i32[0]; } else { ALOGW("%s: Did not have android.request.id set in the request", __FUNCTION__); requestId = NAME_NOT_FOUND; ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__); latestRequestId = NAME_NOT_FOUND; } // Prepare a batch of HAL requests and output buffers. res = prepareHalRequests(&nextRequests); if (res == TIMED_OUT) { // Not a fatal error if getting output buffers time out. cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ true); return true; } else if (res != OK) { cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); return false; } // Inform waitUntilRequestProcessed thread of a new request ID { Mutex::Autolock al(mLatestRequestMutex); mLatestRequestId = latestRequestId; mLatestRequestSignal.signal(); } // Submit a batch of requests to HAL. // Use flush lock only when submitting multilple requests in a batch. // TODO: The problem with flush lock is flush() will be blocked by process_capture_request() // which may take a long time to finish so synchronizing flush() and // process_capture_request() defeats the purpose of cancelling requests ASAP with flush(). // For now, only synchronize for high speed recording and we should figure something out for // removing the synchronization. bool useFlushLock = nextRequests.size() > 1; if (useFlushLock) { mFlushLock.lock(); } ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__, nextRequests.size()); for (auto& nextRequest : nextRequests) { // Submit request and block until ready for next one ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number); ATRACE_BEGIN("camera3->process_capture_request"); res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest); ATRACE_END(); if (res != OK) { // Should only get a failure here for malformed requests or device-level // errors, so consider all errors fatal. Bad metadata failures should // come through notify. SET_ERR("RequestThread: Unable to submit capture request %d to HAL" " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), res); cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); if (useFlushLock) { mFlushLock.unlock(); } return false; } // Mark that the request has be submitted successfully. nextRequest.submitted = true; // Update the latest request sent to HAL if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged Mutex::Autolock al(mLatestRequestMutex); camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings); mLatestRequest.acquire(cloned); } if (nextRequest.halRequest.settings != NULL) { nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings); } // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { SET_ERR("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), res); cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); if (useFlushLock) { mFlushLock.unlock(); } return false; } } if (useFlushLock) { mFlushLock.unlock(); } // Unset as current request { Mutex::Autolock l(mRequestLock); mNextRequests.clear(); } return true; } status_t Camera3Device::RequestThread::prepareHalRequests(Vector<NextRequest> *nextRequests) { ATRACE_CALL(); if (nextRequests == nullptr) { return BAD_VALUE; } for (auto& nextRequest : *nextRequests) { sp<CaptureRequest> captureRequest = nextRequest.captureRequest; camera3_capture_request_t* halRequest = &nextRequest.halRequest; Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers; // Prepare a request to HAL halRequest->frame_number = captureRequest->mResultExtras.frameNumber; // Insert any queued triggers (before metadata is locked) int32_t triggerCount; res = insertTriggers(nextRequest); status_t res = insertTriggers(captureRequest); if (res < 0) { SET_ERR("RequestThread: Unable to insert triggers " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; halRequest->frame_number, strerror(-res), res); return INVALID_OPERATION; } triggerCount = res; int triggerCount = res; bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); mPrevTriggers = triggerCount; // If the request is the same as last, or we had triggers last time if (mPrevRequest != nextRequest || triggersMixedIn) { if (mPrevRequest != captureRequest || triggersMixedIn) { /** * HAL workaround: * Insert a dummy trigger ID if a trigger is set but no trigger ID is */ res = addDummyTriggerIds(nextRequest); res = addDummyTriggerIds(captureRequest); if (res != OK) { SET_ERR("RequestThread: Unable to insert dummy trigger IDs " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; halRequest->frame_number, strerror(-res), res); return INVALID_OPERATION; } /** * The request should be presorted so accesses in HAL * are O(logn). Sidenote, sorting a sorted metadata is nop. */ nextRequest->mSettings.sort(); request.settings = nextRequest->mSettings.getAndLock(); mPrevRequest = nextRequest; captureRequest->mSettings.sort(); halRequest->settings = captureRequest->mSettings.getAndLock(); mPrevRequest = captureRequest; ALOGVV("%s: Request settings are NEW", __FUNCTION__); IF_ALOGV() { camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); find_camera_metadata_ro_entry( request.settings, halRequest->settings, ANDROID_CONTROL_AF_TRIGGER, &e ); if (e.count > 0) { ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", __FUNCTION__, request.frame_number, halRequest->frame_number, e.data.u8[0]); } } Loading @@ -2949,118 +3078,56 @@ bool Camera3Device::RequestThread::threadLoop() { uint32_t totalNumBuffers = 0; // Fill in buffers if (nextRequest->mInputStream != NULL) { request.input_buffer = &nextRequest->mInputBuffer; if (captureRequest->mInputStream != NULL) { halRequest->input_buffer = &captureRequest->mInputBuffer; totalNumBuffers += 1; } else { request.input_buffer = NULL; halRequest->input_buffer = NULL; } outputBuffers.insertAt(camera3_stream_buffer_t(), 0, nextRequest->mOutputStreams.size()); request.output_buffers = outputBuffers.array(); for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) { res = nextRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers.editItemAt(i)); outputBuffers->insertAt(camera3_stream_buffer_t(), 0, captureRequest->mOutputStreams.size()); halRequest->output_buffers = outputBuffers->array(); for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) { res = captureRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers->editItemAt(i)); if (res != OK) { // Can't get output buffer from gralloc queue - this could be due to // abandoned queue or other consumer misbehavior, so not a fatal // error ALOGE("RequestThread: Can't get output buffer, skipping request:" " %s (%d)", strerror(-res), res); { Mutex::Autolock l(mRequestLock); if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, nextRequest->mResultExtras); } } cleanUpFailedRequest(request, nextRequest, outputBuffers); return true; return TIMED_OUT; } request.num_output_buffers++; halRequest->num_output_buffers++; } totalNumBuffers += request.num_output_buffers; totalNumBuffers += halRequest->num_output_buffers; // Log request in the in-flight queue sp<Camera3Device> parent = mParent.promote(); if (parent == NULL) { // Should not happen, and nowhere to send errors to, so just log it CLOGE("RequestThread: Parent is gone"); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; return INVALID_OPERATION; } res = parent->registerInFlight(request.frame_number, totalNumBuffers, nextRequest->mResultExtras, /*hasInput*/request.input_buffer != NULL, nextRequest->mAeTriggerCancelOverride); res = parent->registerInFlight(halRequest->frame_number, totalNumBuffers, captureRequest->mResultExtras, /*hasInput*/halRequest->input_buffer != NULL, captureRequest->mAeTriggerCancelOverride); ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 ", burstId = %" PRId32 ".", __FUNCTION__, nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, nextRequest->mResultExtras.burstId); captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber, captureRequest->mResultExtras.burstId); if (res != OK) { SET_ERR("RequestThread: Unable to register new in-flight request:" " %s (%d)", strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } // Inform waitUntilRequestProcessed thread of a new request ID { Mutex::Autolock al(mLatestRequestMutex); mLatestRequestId = requestId; mLatestRequestSignal.signal(); } // Submit request and block until ready for next one ATRACE_ASYNC_BEGIN("frame capture", request.frame_number); ATRACE_BEGIN("camera3->process_capture_request"); res = mHal3Device->ops->process_capture_request(mHal3Device, &request); ATRACE_END(); if (res != OK) { // Should only get a failure here for malformed requests or device-level // errors, so consider all errors fatal. Bad metadata failures should // come through notify. SET_ERR("RequestThread: Unable to submit capture request %d to HAL" " device: %s (%d)", request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } // Update the latest request sent to HAL if (request.settings != NULL) { // Don't update them if they were unchanged Mutex::Autolock al(mLatestRequestMutex); camera_metadata_t* cloned = clone_camera_metadata(request.settings); mLatestRequest.acquire(cloned); } if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); } // Unset as current request { Mutex::Autolock l(mRequestLock); mNextRequest.clear(); return INVALID_OPERATION; } // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { SET_ERR("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); return false; } mPrevTriggers = triggerCount; return true; return OK; } CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { Loading @@ -3075,11 +3142,11 @@ bool Camera3Device::RequestThread::isStreamPending( sp<Camera3StreamInterface>& stream) { Mutex::Autolock l(mRequestLock); if (mNextRequest != nullptr) { for (const auto& s : mNextRequest->mOutputStreams) { for (const auto& nextRequest : mNextRequests) { for (const auto& s : nextRequest->mOutputStreams) { if (stream == s) return true; } if (stream == mNextRequest->mInputStream) return true; if (stream == nextRequest->mInputStream) return true; } for (const auto& request : mRequestQueue) { Loading @@ -3099,37 +3166,104 @@ bool Camera3Device::RequestThread::isStreamPending( return false; } void Camera3Device::RequestThread::cleanUpFailedRequest( camera3_capture_request_t &request, sp<CaptureRequest> &nextRequest, Vector<camera3_stream_buffer_t> &outputBuffers) { void Camera3Device::RequestThread::cleanUpFailedRequests(Vector<NextRequest> *nextRequests, bool sendRequestError) { if (nextRequests == nullptr) { return; } for (auto& nextRequest : *nextRequests) { // Skip the ones that have been submitted successfully. if (nextRequest.submitted) { continue; } sp<CaptureRequest> captureRequest = nextRequest.captureRequest; camera3_capture_request_t* halRequest = &nextRequest.halRequest; Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers; if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); if (halRequest->settings != NULL) { captureRequest->mSettings.unlock(halRequest->settings); } if (nextRequest->mInputStream != NULL) { nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); if (captureRequest->mInputStream != NULL) { captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer); } for (size_t i = 0; i < request.num_output_buffers; i++) { outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( outputBuffers[i], 0); for (size_t i = 0; i < halRequest->num_output_buffers; i++) { outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0); } if (sendRequestError) { Mutex::Autolock l(mRequestLock); mNextRequest.clear(); if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, captureRequest->mResultExtras); } } } sp<Camera3Device::CaptureRequest> Camera3Device::RequestThread::waitForNextRequest() { status_t res; sp<CaptureRequest> nextRequest; Mutex::Autolock l(mRequestLock); mNextRequests.clear(); nextRequests->clear(); } void Camera3Device::RequestThread::waitForNextRequestBatch(Vector<NextRequest> *nextRequests) { if (nextRequests == nullptr) { return; } // Optimized a bit for the simple steady-state case (single repeating // request), to avoid putting that request in the queue temporarily. Mutex::Autolock l(mRequestLock); nextRequests->clear(); assert(mNextRequests.empty()); NextRequest nextRequest; nextRequest.captureRequest = waitForNextRequestLocked(); if (nextRequest.captureRequest == nullptr) { return; } nextRequest.halRequest = camera3_capture_request_t(); nextRequest.submitted = false; nextRequests->add(nextRequest); mNextRequests.push_back(nextRequest.captureRequest); // Wait for additional requests const size_t batchSize = nextRequest.captureRequest->mBatchSize; for (size_t i = 1; i < batchSize; i++) { NextRequest additionalRequest; additionalRequest.captureRequest = waitForNextRequestLocked(); if (additionalRequest.captureRequest == nullptr) { break; } additionalRequest.halRequest = camera3_capture_request_t(); additionalRequest.submitted = false; nextRequests->add(additionalRequest); mNextRequests.push_back(additionalRequest.captureRequest); } if (nextRequests->size() < batchSize) { ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.", nextRequests->size(), batchSize); cleanUpFailedRequests(nextRequests, /*sendRequestError*/true); } return; } sp<Camera3Device::CaptureRequest> Camera3Device::RequestThread::waitForNextRequestLocked() { status_t res; sp<CaptureRequest> nextRequest; while (mRequestQueue.empty()) { if (!mRepeatingRequests.empty()) { // Always atomically enqueue all requests in a repeating request Loading Loading @@ -3224,8 +3358,6 @@ sp<Camera3Device::CaptureRequest> handleAePrecaptureCancelRequest(nextRequest); mNextRequest = nextRequest; return nextRequest; } Loading
services/camera/libcameraservice/device3/Camera3Device.h +36 −11 Original line number Diff line number Diff line Loading @@ -264,6 +264,11 @@ class Camera3Device : // Used to cancel AE precapture trigger for devices doesn't support // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL AeTriggerCancelOverride_t mAeTriggerCancelOverride; // The number of requests that should be submitted to HAL at a time. // For example, if batch size is 8, this request and the following 7 // requests will be submitted to HAL at a time. The batch size for // the following 7 requests will be ignored by the request thread. int mBatchSize; }; typedef List<sp<CaptureRequest> > RequestList; Loading Loading @@ -440,6 +445,11 @@ class Camera3Device : /*out*/ int64_t *lastFrameNumber = NULL); /** * Flush all pending requests in HAL. */ status_t flush(); /** * Queue a trigger to be dispatched with the next outgoing * process_capture_request. The settings for that request only Loading Loading @@ -501,16 +511,28 @@ class Camera3Device : static const nsecs_t kRequestTimeout = 50e6; // 50 ms // Waits for a request, or returns NULL if times out. sp<CaptureRequest> waitForNextRequest(); // Used to prepare a batch of requests. struct NextRequest { sp<CaptureRequest> captureRequest; camera3_capture_request_t halRequest; Vector<camera3_stream_buffer_t> outputBuffers; bool submitted; }; // Wait for the next batch of requests. void waitForNextRequestBatch(Vector<NextRequest> *nextRequests); // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold. sp<CaptureRequest> waitForNextRequestLocked(); // Return buffers, etc, for a request that couldn't be fully // constructed. The buffers will be returned in the ERROR state // to mark them as not having valid data. // All arguments will be modified. void cleanUpFailedRequest(camera3_capture_request_t &request, sp<CaptureRequest> &nextRequest, Vector<camera3_stream_buffer_t> &outputBuffers); // Prepare a HAL request and output buffers. Return TIMED_OUT if getting any output buffer // timed out. If an error is returned, the caller should clean up the pending request batch. status_t prepareHalRequests(Vector<NextRequest> *nextRequests); // Return buffers, etc, for a request that couldn't be fully constructed and send request // errors if sendRequestError is true. The buffers will be returned in the ERROR state // to mark them as not having valid data. nextRequests will be modified. void cleanUpFailedRequests(Vector<NextRequest> *nextRequests, bool sendRequestError); // Pause handling bool waitIfPaused(); Loading Loading @@ -539,10 +561,13 @@ class Camera3Device : Condition mRequestSignal; RequestList mRequestQueue; RequestList mRepeatingRequests; // The next request being prepped for submission to the HAL, no longer // The next requests being prepped for submission to the HAL, no longer // on the request queue. Read-only even with mRequestLock held, outside // of threadLoop sp<const CaptureRequest> mNextRequest; RequestList mNextRequests; // To protect flush() and sending a request batch to HAL. Mutex mFlushLock; bool mReconfigured; Loading
services/camera/libcameraservice/device3/Camera3DummyStream.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const { return OK; } bool Camera3DummyStream::isVideoStream() const { return false; } }; // namespace camera3 }; // namespace android
services/camera/libcameraservice/device3/Camera3DummyStream.h +5 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,11 @@ class Camera3DummyStream : status_t setTransform(int transform); /** * Return if this output stream is for video encoding. */ bool isVideoStream() const; protected: /** Loading
services/camera/libcameraservice/device3/Camera3OutputStream.cpp +11 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes