Loading services/camera/libcameraservice/device3/Camera3Device.cpp +318 −186 Original line number Original line Diff line number Diff line Loading @@ -565,6 +565,18 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); 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; return OK; } } Loading Loading @@ -1406,7 +1418,7 @@ status_t Camera3Device::flush(int64_t *frameNumber) { status_t res; status_t res; if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { res = mHal3Device->ops->flush(mHal3Device); res = mRequestThread->flush(); } else { } else { Mutex::Autolock l(mLock); Mutex::Autolock l(mLock); res = waitUntilDrainedLocked(); res = waitUntilDrainedLocked(); Loading Loading @@ -1595,6 +1607,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( newRequest->mOutputStreams.push(stream); newRequest->mOutputStreams.push(stream); } } newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); newRequest->mBatchSize = 1; return newRequest; return newRequest; } } Loading Loading @@ -2766,6 +2779,17 @@ status_t Camera3Device::RequestThread::clear( return OK; 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) { void Camera3Device::RequestThread::setPaused(bool paused) { Mutex::Autolock l(mPauseLock); Mutex::Autolock l(mPauseLock); mDoPause = paused; mDoPause = paused; Loading Loading @@ -2856,7 +2880,7 @@ void Camera3Device::overrideResultForPrecaptureCancel( } } bool Camera3Device::RequestThread::threadLoop() { bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; status_t res; // Handle paused state. // Handle paused state. Loading @@ -2864,79 +2888,184 @@ bool Camera3Device::RequestThread::threadLoop() { return true; return true; } } // Get work to do // Get next batch of requests. Vector<NextRequest> nextRequests; sp<CaptureRequest> nextRequest = waitForNextRequest(); waitForNextRequestBatch(&nextRequests); if (nextRequest == NULL) { const size_t numRequests = nextRequests.size(); if (numRequests == 0) { return true; return true; } } // Create request to HAL // Get the latest request ID, if any camera3_capture_request_t request = camera3_capture_request_t(); int latestRequestId; request.frame_number = nextRequest->mResultExtras.frameNumber; camera_metadata_entry_t requestIdEntry = nextRequests[nextRequests.size() - 1]. Vector<camera3_stream_buffer_t> outputBuffers; captureRequest->mSettings.find(ANDROID_REQUEST_ID); // Get the request ID, if any int requestId; camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { if (requestIdEntry.count > 0) { requestId = requestIdEntry.data.i32[0]; latestRequestId = requestIdEntry.data.i32[0]; } else { } else { ALOGW("%s: Did not have android.request.id set in the request", ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__); __FUNCTION__); latestRequestId = NAME_NOT_FOUND; requestId = 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) // Insert any queued triggers (before metadata is locked) int32_t triggerCount; status_t res = insertTriggers(captureRequest); res = insertTriggers(nextRequest); if (res < 0) { if (res < 0) { SET_ERR("RequestThread: Unable to insert triggers " SET_ERR("RequestThread: Unable to insert triggers " "(capture request %d, HAL device: %s (%d)", "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); halRequest->frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; return false; } } triggerCount = res; int triggerCount = res; bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); mPrevTriggers = triggerCount; // 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 last time if (mPrevRequest != nextRequest || triggersMixedIn) { if (mPrevRequest != captureRequest || triggersMixedIn) { /** /** * HAL workaround: * HAL workaround: * Insert a dummy trigger ID if a trigger is set but no trigger ID is * Insert a dummy trigger ID if a trigger is set but no trigger ID is */ */ res = addDummyTriggerIds(nextRequest); res = addDummyTriggerIds(captureRequest); if (res != OK) { if (res != OK) { SET_ERR("RequestThread: Unable to insert dummy trigger IDs " SET_ERR("RequestThread: Unable to insert dummy trigger IDs " "(capture request %d, HAL device: %s (%d)", "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); halRequest->frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; return false; } } /** /** * The request should be presorted so accesses in HAL * The request should be presorted so accesses in HAL * are O(logn). Sidenote, sorting a sorted metadata is nop. * are O(logn). Sidenote, sorting a sorted metadata is nop. */ */ nextRequest->mSettings.sort(); captureRequest->mSettings.sort(); request.settings = nextRequest->mSettings.getAndLock(); halRequest->settings = captureRequest->mSettings.getAndLock(); mPrevRequest = nextRequest; mPrevRequest = captureRequest; ALOGVV("%s: Request settings are NEW", __FUNCTION__); ALOGVV("%s: Request settings are NEW", __FUNCTION__); IF_ALOGV() { IF_ALOGV() { camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); find_camera_metadata_ro_entry( find_camera_metadata_ro_entry( request.settings, halRequest->settings, ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AF_TRIGGER, &e &e ); ); if (e.count > 0) { if (e.count > 0) { ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", __FUNCTION__, __FUNCTION__, request.frame_number, halRequest->frame_number, e.data.u8[0]); e.data.u8[0]); } } } } Loading @@ -2949,118 +3078,56 @@ bool Camera3Device::RequestThread::threadLoop() { uint32_t totalNumBuffers = 0; uint32_t totalNumBuffers = 0; // Fill in buffers // Fill in buffers if (nextRequest->mInputStream != NULL) { if (captureRequest->mInputStream != NULL) { request.input_buffer = &nextRequest->mInputBuffer; halRequest->input_buffer = &captureRequest->mInputBuffer; totalNumBuffers += 1; totalNumBuffers += 1; } else { } else { request.input_buffer = NULL; halRequest->input_buffer = NULL; } } outputBuffers.insertAt(camera3_stream_buffer_t(), 0, outputBuffers->insertAt(camera3_stream_buffer_t(), 0, nextRequest->mOutputStreams.size()); captureRequest->mOutputStreams.size()); request.output_buffers = outputBuffers.array(); halRequest->output_buffers = outputBuffers->array(); for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) { for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) { res = nextRequest->mOutputStreams.editItemAt(i)-> res = captureRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers.editItemAt(i)); getBuffer(&outputBuffers->editItemAt(i)); if (res != OK) { if (res != OK) { // Can't get output buffer from gralloc queue - this could be due to // Can't get output buffer from gralloc queue - this could be due to // abandoned queue or other consumer misbehavior, so not a fatal // abandoned queue or other consumer misbehavior, so not a fatal // error // error ALOGE("RequestThread: Can't get output buffer, skipping request:" ALOGE("RequestThread: Can't get output buffer, skipping request:" " %s (%d)", strerror(-res), res); " %s (%d)", strerror(-res), res); { Mutex::Autolock l(mRequestLock); return TIMED_OUT; if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, nextRequest->mResultExtras); } } cleanUpFailedRequest(request, nextRequest, outputBuffers); return true; } } 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 // Log request in the in-flight queue sp<Camera3Device> parent = mParent.promote(); sp<Camera3Device> parent = mParent.promote(); if (parent == NULL) { if (parent == NULL) { // Should not happen, and nowhere to send errors to, so just log it // Should not happen, and nowhere to send errors to, so just log it CLOGE("RequestThread: Parent is gone"); CLOGE("RequestThread: Parent is gone"); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; return false; } } res = parent->registerInFlight(halRequest->frame_number, res = parent->registerInFlight(request.frame_number, totalNumBuffers, captureRequest->mResultExtras, totalNumBuffers, nextRequest->mResultExtras, /*hasInput*/halRequest->input_buffer != NULL, /*hasInput*/request.input_buffer != NULL, captureRequest->mAeTriggerCancelOverride); nextRequest->mAeTriggerCancelOverride); ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 ", burstId = %" PRId32 ".", ", burstId = %" PRId32 ".", __FUNCTION__, __FUNCTION__, nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber, nextRequest->mResultExtras.burstId); captureRequest->mResultExtras.burstId); if (res != OK) { if (res != OK) { SET_ERR("RequestThread: Unable to register new in-flight request:" SET_ERR("RequestThread: Unable to register new in-flight request:" " %s (%d)", strerror(-res), res); " %s (%d)", strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; 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(); } } // 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 { CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { Loading @@ -3075,11 +3142,11 @@ bool Camera3Device::RequestThread::isStreamPending( sp<Camera3StreamInterface>& stream) { sp<Camera3StreamInterface>& stream) { Mutex::Autolock l(mRequestLock); Mutex::Autolock l(mRequestLock); if (mNextRequest != nullptr) { for (const auto& nextRequest : mNextRequests) { for (const auto& s : mNextRequest->mOutputStreams) { for (const auto& s : nextRequest->mOutputStreams) { if (stream == s) return true; if (stream == s) return true; } } if (stream == mNextRequest->mInputStream) return true; if (stream == nextRequest->mInputStream) return true; } } for (const auto& request : mRequestQueue) { for (const auto& request : mRequestQueue) { Loading @@ -3099,37 +3166,104 @@ bool Camera3Device::RequestThread::isStreamPending( return false; return false; } } void Camera3Device::RequestThread::cleanUpFailedRequest( void Camera3Device::RequestThread::cleanUpFailedRequests(Vector<NextRequest> *nextRequests, camera3_capture_request_t &request, bool sendRequestError) { sp<CaptureRequest> &nextRequest, if (nextRequests == nullptr) { Vector<camera3_stream_buffer_t> &outputBuffers) { 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) { if (halRequest->settings != NULL) { nextRequest->mSettings.unlock(request.settings); captureRequest->mSettings.unlock(halRequest->settings); } } if (nextRequest->mInputStream != NULL) { nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; if (captureRequest->mInputStream != NULL) { nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); 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; for (size_t i = 0; i < halRequest->num_output_buffers; i++) { nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; outputBuffers[i], 0); captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0); } } if (sendRequestError) { Mutex::Autolock l(mRequestLock); Mutex::Autolock l(mRequestLock); mNextRequest.clear(); if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, captureRequest->mResultExtras); } } } } sp<Camera3Device::CaptureRequest> Mutex::Autolock l(mRequestLock); Camera3Device::RequestThread::waitForNextRequest() { mNextRequests.clear(); status_t res; nextRequests->clear(); sp<CaptureRequest> nextRequest; } void Camera3Device::RequestThread::waitForNextRequestBatch(Vector<NextRequest> *nextRequests) { if (nextRequests == nullptr) { return; } // Optimized a bit for the simple steady-state case (single repeating // Optimized a bit for the simple steady-state case (single repeating // request), to avoid putting that request in the queue temporarily. // request), to avoid putting that request in the queue temporarily. Mutex::Autolock l(mRequestLock); 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()) { while (mRequestQueue.empty()) { if (!mRepeatingRequests.empty()) { if (!mRepeatingRequests.empty()) { // Always atomically enqueue all requests in a repeating request // Always atomically enqueue all requests in a repeating request Loading Loading @@ -3224,8 +3358,6 @@ sp<Camera3Device::CaptureRequest> handleAePrecaptureCancelRequest(nextRequest); handleAePrecaptureCancelRequest(nextRequest); mNextRequest = nextRequest; return nextRequest; return nextRequest; } } Loading services/camera/libcameraservice/device3/Camera3Device.h +36 −11 Original line number Original line Diff line number Diff line Loading @@ -264,6 +264,11 @@ class Camera3Device : // Used to cancel AE precapture trigger for devices doesn't support // Used to cancel AE precapture trigger for devices doesn't support // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL AeTriggerCancelOverride_t mAeTriggerCancelOverride; 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; typedef List<sp<CaptureRequest> > RequestList; Loading Loading @@ -440,6 +445,11 @@ class Camera3Device : /*out*/ /*out*/ int64_t *lastFrameNumber = NULL); int64_t *lastFrameNumber = NULL); /** * Flush all pending requests in HAL. */ status_t flush(); /** /** * Queue a trigger to be dispatched with the next outgoing * Queue a trigger to be dispatched with the next outgoing * process_capture_request. The settings for that request only * 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 static const nsecs_t kRequestTimeout = 50e6; // 50 ms // Waits for a request, or returns NULL if times out. // Used to prepare a batch of requests. sp<CaptureRequest> waitForNextRequest(); 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 // Prepare a HAL request and output buffers. Return TIMED_OUT if getting any output buffer // constructed. The buffers will be returned in the ERROR state // timed out. If an error is returned, the caller should clean up the pending request batch. // to mark them as not having valid data. status_t prepareHalRequests(Vector<NextRequest> *nextRequests); // All arguments will be modified. void cleanUpFailedRequest(camera3_capture_request_t &request, // Return buffers, etc, for a request that couldn't be fully constructed and send request sp<CaptureRequest> &nextRequest, // errors if sendRequestError is true. The buffers will be returned in the ERROR state Vector<camera3_stream_buffer_t> &outputBuffers); // to mark them as not having valid data. nextRequests will be modified. void cleanUpFailedRequests(Vector<NextRequest> *nextRequests, bool sendRequestError); // Pause handling // Pause handling bool waitIfPaused(); bool waitIfPaused(); Loading Loading @@ -539,10 +561,13 @@ class Camera3Device : Condition mRequestSignal; Condition mRequestSignal; RequestList mRequestQueue; RequestList mRequestQueue; RequestList mRepeatingRequests; 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 // on the request queue. Read-only even with mRequestLock held, outside // of threadLoop // of threadLoop sp<const CaptureRequest> mNextRequest; RequestList mNextRequests; // To protect flush() and sending a request batch to HAL. Mutex mFlushLock; bool mReconfigured; bool mReconfigured; Loading services/camera/libcameraservice/device3/Camera3DummyStream.cpp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const { return OK; return OK; } } bool Camera3DummyStream::isVideoStream() const { return false; } }; // namespace camera3 }; // namespace camera3 }; // namespace android }; // namespace android services/camera/libcameraservice/device3/Camera3DummyStream.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -54,6 +54,11 @@ class Camera3DummyStream : status_t setTransform(int transform); status_t setTransform(int transform); /** * Return if this output stream is for video encoding. */ bool isVideoStream() const; protected: 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 Original line Diff line number Diff line Loading @@ -565,6 +565,18 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); 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; return OK; } } Loading Loading @@ -1406,7 +1418,7 @@ status_t Camera3Device::flush(int64_t *frameNumber) { status_t res; status_t res; if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { res = mHal3Device->ops->flush(mHal3Device); res = mRequestThread->flush(); } else { } else { Mutex::Autolock l(mLock); Mutex::Autolock l(mLock); res = waitUntilDrainedLocked(); res = waitUntilDrainedLocked(); Loading Loading @@ -1595,6 +1607,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( newRequest->mOutputStreams.push(stream); newRequest->mOutputStreams.push(stream); } } newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); newRequest->mBatchSize = 1; return newRequest; return newRequest; } } Loading Loading @@ -2766,6 +2779,17 @@ status_t Camera3Device::RequestThread::clear( return OK; 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) { void Camera3Device::RequestThread::setPaused(bool paused) { Mutex::Autolock l(mPauseLock); Mutex::Autolock l(mPauseLock); mDoPause = paused; mDoPause = paused; Loading Loading @@ -2856,7 +2880,7 @@ void Camera3Device::overrideResultForPrecaptureCancel( } } bool Camera3Device::RequestThread::threadLoop() { bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; status_t res; // Handle paused state. // Handle paused state. Loading @@ -2864,79 +2888,184 @@ bool Camera3Device::RequestThread::threadLoop() { return true; return true; } } // Get work to do // Get next batch of requests. Vector<NextRequest> nextRequests; sp<CaptureRequest> nextRequest = waitForNextRequest(); waitForNextRequestBatch(&nextRequests); if (nextRequest == NULL) { const size_t numRequests = nextRequests.size(); if (numRequests == 0) { return true; return true; } } // Create request to HAL // Get the latest request ID, if any camera3_capture_request_t request = camera3_capture_request_t(); int latestRequestId; request.frame_number = nextRequest->mResultExtras.frameNumber; camera_metadata_entry_t requestIdEntry = nextRequests[nextRequests.size() - 1]. Vector<camera3_stream_buffer_t> outputBuffers; captureRequest->mSettings.find(ANDROID_REQUEST_ID); // Get the request ID, if any int requestId; camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { if (requestIdEntry.count > 0) { requestId = requestIdEntry.data.i32[0]; latestRequestId = requestIdEntry.data.i32[0]; } else { } else { ALOGW("%s: Did not have android.request.id set in the request", ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__); __FUNCTION__); latestRequestId = NAME_NOT_FOUND; requestId = 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) // Insert any queued triggers (before metadata is locked) int32_t triggerCount; status_t res = insertTriggers(captureRequest); res = insertTriggers(nextRequest); if (res < 0) { if (res < 0) { SET_ERR("RequestThread: Unable to insert triggers " SET_ERR("RequestThread: Unable to insert triggers " "(capture request %d, HAL device: %s (%d)", "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); halRequest->frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; return false; } } triggerCount = res; int triggerCount = res; bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); mPrevTriggers = triggerCount; // 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 last time if (mPrevRequest != nextRequest || triggersMixedIn) { if (mPrevRequest != captureRequest || triggersMixedIn) { /** /** * HAL workaround: * HAL workaround: * Insert a dummy trigger ID if a trigger is set but no trigger ID is * Insert a dummy trigger ID if a trigger is set but no trigger ID is */ */ res = addDummyTriggerIds(nextRequest); res = addDummyTriggerIds(captureRequest); if (res != OK) { if (res != OK) { SET_ERR("RequestThread: Unable to insert dummy trigger IDs " SET_ERR("RequestThread: Unable to insert dummy trigger IDs " "(capture request %d, HAL device: %s (%d)", "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); halRequest->frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; return false; } } /** /** * The request should be presorted so accesses in HAL * The request should be presorted so accesses in HAL * are O(logn). Sidenote, sorting a sorted metadata is nop. * are O(logn). Sidenote, sorting a sorted metadata is nop. */ */ nextRequest->mSettings.sort(); captureRequest->mSettings.sort(); request.settings = nextRequest->mSettings.getAndLock(); halRequest->settings = captureRequest->mSettings.getAndLock(); mPrevRequest = nextRequest; mPrevRequest = captureRequest; ALOGVV("%s: Request settings are NEW", __FUNCTION__); ALOGVV("%s: Request settings are NEW", __FUNCTION__); IF_ALOGV() { IF_ALOGV() { camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); find_camera_metadata_ro_entry( find_camera_metadata_ro_entry( request.settings, halRequest->settings, ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AF_TRIGGER, &e &e ); ); if (e.count > 0) { if (e.count > 0) { ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", __FUNCTION__, __FUNCTION__, request.frame_number, halRequest->frame_number, e.data.u8[0]); e.data.u8[0]); } } } } Loading @@ -2949,118 +3078,56 @@ bool Camera3Device::RequestThread::threadLoop() { uint32_t totalNumBuffers = 0; uint32_t totalNumBuffers = 0; // Fill in buffers // Fill in buffers if (nextRequest->mInputStream != NULL) { if (captureRequest->mInputStream != NULL) { request.input_buffer = &nextRequest->mInputBuffer; halRequest->input_buffer = &captureRequest->mInputBuffer; totalNumBuffers += 1; totalNumBuffers += 1; } else { } else { request.input_buffer = NULL; halRequest->input_buffer = NULL; } } outputBuffers.insertAt(camera3_stream_buffer_t(), 0, outputBuffers->insertAt(camera3_stream_buffer_t(), 0, nextRequest->mOutputStreams.size()); captureRequest->mOutputStreams.size()); request.output_buffers = outputBuffers.array(); halRequest->output_buffers = outputBuffers->array(); for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) { for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) { res = nextRequest->mOutputStreams.editItemAt(i)-> res = captureRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers.editItemAt(i)); getBuffer(&outputBuffers->editItemAt(i)); if (res != OK) { if (res != OK) { // Can't get output buffer from gralloc queue - this could be due to // Can't get output buffer from gralloc queue - this could be due to // abandoned queue or other consumer misbehavior, so not a fatal // abandoned queue or other consumer misbehavior, so not a fatal // error // error ALOGE("RequestThread: Can't get output buffer, skipping request:" ALOGE("RequestThread: Can't get output buffer, skipping request:" " %s (%d)", strerror(-res), res); " %s (%d)", strerror(-res), res); { Mutex::Autolock l(mRequestLock); return TIMED_OUT; if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, nextRequest->mResultExtras); } } cleanUpFailedRequest(request, nextRequest, outputBuffers); return true; } } 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 // Log request in the in-flight queue sp<Camera3Device> parent = mParent.promote(); sp<Camera3Device> parent = mParent.promote(); if (parent == NULL) { if (parent == NULL) { // Should not happen, and nowhere to send errors to, so just log it // Should not happen, and nowhere to send errors to, so just log it CLOGE("RequestThread: Parent is gone"); CLOGE("RequestThread: Parent is gone"); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; return false; } } res = parent->registerInFlight(halRequest->frame_number, res = parent->registerInFlight(request.frame_number, totalNumBuffers, captureRequest->mResultExtras, totalNumBuffers, nextRequest->mResultExtras, /*hasInput*/halRequest->input_buffer != NULL, /*hasInput*/request.input_buffer != NULL, captureRequest->mAeTriggerCancelOverride); nextRequest->mAeTriggerCancelOverride); ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 ", burstId = %" PRId32 ".", ", burstId = %" PRId32 ".", __FUNCTION__, __FUNCTION__, nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber, nextRequest->mResultExtras.burstId); captureRequest->mResultExtras.burstId); if (res != OK) { if (res != OK) { SET_ERR("RequestThread: Unable to register new in-flight request:" SET_ERR("RequestThread: Unable to register new in-flight request:" " %s (%d)", strerror(-res), res); " %s (%d)", strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return INVALID_OPERATION; 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(); } } // 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 { CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { Loading @@ -3075,11 +3142,11 @@ bool Camera3Device::RequestThread::isStreamPending( sp<Camera3StreamInterface>& stream) { sp<Camera3StreamInterface>& stream) { Mutex::Autolock l(mRequestLock); Mutex::Autolock l(mRequestLock); if (mNextRequest != nullptr) { for (const auto& nextRequest : mNextRequests) { for (const auto& s : mNextRequest->mOutputStreams) { for (const auto& s : nextRequest->mOutputStreams) { if (stream == s) return true; if (stream == s) return true; } } if (stream == mNextRequest->mInputStream) return true; if (stream == nextRequest->mInputStream) return true; } } for (const auto& request : mRequestQueue) { for (const auto& request : mRequestQueue) { Loading @@ -3099,37 +3166,104 @@ bool Camera3Device::RequestThread::isStreamPending( return false; return false; } } void Camera3Device::RequestThread::cleanUpFailedRequest( void Camera3Device::RequestThread::cleanUpFailedRequests(Vector<NextRequest> *nextRequests, camera3_capture_request_t &request, bool sendRequestError) { sp<CaptureRequest> &nextRequest, if (nextRequests == nullptr) { Vector<camera3_stream_buffer_t> &outputBuffers) { 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) { if (halRequest->settings != NULL) { nextRequest->mSettings.unlock(request.settings); captureRequest->mSettings.unlock(halRequest->settings); } } if (nextRequest->mInputStream != NULL) { nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; if (captureRequest->mInputStream != NULL) { nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); 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; for (size_t i = 0; i < halRequest->num_output_buffers; i++) { nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; outputBuffers[i], 0); captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0); } } if (sendRequestError) { Mutex::Autolock l(mRequestLock); Mutex::Autolock l(mRequestLock); mNextRequest.clear(); if (mListener != NULL) { mListener->notifyError( ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, captureRequest->mResultExtras); } } } } sp<Camera3Device::CaptureRequest> Mutex::Autolock l(mRequestLock); Camera3Device::RequestThread::waitForNextRequest() { mNextRequests.clear(); status_t res; nextRequests->clear(); sp<CaptureRequest> nextRequest; } void Camera3Device::RequestThread::waitForNextRequestBatch(Vector<NextRequest> *nextRequests) { if (nextRequests == nullptr) { return; } // Optimized a bit for the simple steady-state case (single repeating // Optimized a bit for the simple steady-state case (single repeating // request), to avoid putting that request in the queue temporarily. // request), to avoid putting that request in the queue temporarily. Mutex::Autolock l(mRequestLock); 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()) { while (mRequestQueue.empty()) { if (!mRepeatingRequests.empty()) { if (!mRepeatingRequests.empty()) { // Always atomically enqueue all requests in a repeating request // Always atomically enqueue all requests in a repeating request Loading Loading @@ -3224,8 +3358,6 @@ sp<Camera3Device::CaptureRequest> handleAePrecaptureCancelRequest(nextRequest); handleAePrecaptureCancelRequest(nextRequest); mNextRequest = nextRequest; return nextRequest; return nextRequest; } } Loading
services/camera/libcameraservice/device3/Camera3Device.h +36 −11 Original line number Original line Diff line number Diff line Loading @@ -264,6 +264,11 @@ class Camera3Device : // Used to cancel AE precapture trigger for devices doesn't support // Used to cancel AE precapture trigger for devices doesn't support // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL AeTriggerCancelOverride_t mAeTriggerCancelOverride; 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; typedef List<sp<CaptureRequest> > RequestList; Loading Loading @@ -440,6 +445,11 @@ class Camera3Device : /*out*/ /*out*/ int64_t *lastFrameNumber = NULL); int64_t *lastFrameNumber = NULL); /** * Flush all pending requests in HAL. */ status_t flush(); /** /** * Queue a trigger to be dispatched with the next outgoing * Queue a trigger to be dispatched with the next outgoing * process_capture_request. The settings for that request only * 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 static const nsecs_t kRequestTimeout = 50e6; // 50 ms // Waits for a request, or returns NULL if times out. // Used to prepare a batch of requests. sp<CaptureRequest> waitForNextRequest(); 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 // Prepare a HAL request and output buffers. Return TIMED_OUT if getting any output buffer // constructed. The buffers will be returned in the ERROR state // timed out. If an error is returned, the caller should clean up the pending request batch. // to mark them as not having valid data. status_t prepareHalRequests(Vector<NextRequest> *nextRequests); // All arguments will be modified. void cleanUpFailedRequest(camera3_capture_request_t &request, // Return buffers, etc, for a request that couldn't be fully constructed and send request sp<CaptureRequest> &nextRequest, // errors if sendRequestError is true. The buffers will be returned in the ERROR state Vector<camera3_stream_buffer_t> &outputBuffers); // to mark them as not having valid data. nextRequests will be modified. void cleanUpFailedRequests(Vector<NextRequest> *nextRequests, bool sendRequestError); // Pause handling // Pause handling bool waitIfPaused(); bool waitIfPaused(); Loading Loading @@ -539,10 +561,13 @@ class Camera3Device : Condition mRequestSignal; Condition mRequestSignal; RequestList mRequestQueue; RequestList mRequestQueue; RequestList mRepeatingRequests; 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 // on the request queue. Read-only even with mRequestLock held, outside // of threadLoop // of threadLoop sp<const CaptureRequest> mNextRequest; RequestList mNextRequests; // To protect flush() and sending a request batch to HAL. Mutex mFlushLock; bool mReconfigured; bool mReconfigured; Loading
services/camera/libcameraservice/device3/Camera3DummyStream.cpp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const { return OK; return OK; } } bool Camera3DummyStream::isVideoStream() const { return false; } }; // namespace camera3 }; // namespace camera3 }; // namespace android }; // namespace android
services/camera/libcameraservice/device3/Camera3DummyStream.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -54,6 +54,11 @@ class Camera3DummyStream : status_t setTransform(int transform); status_t setTransform(int transform); /** * Return if this output stream is for video encoding. */ bool isVideoStream() const; protected: protected: /** /** Loading
services/camera/libcameraservice/device3/Camera3OutputStream.cpp +11 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes