diff options
Diffstat (limited to 'services/camera/libcameraservice')
8 files changed, 387 insertions, 199 deletions
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index ec3591f..98d0a41 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -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; } @@ -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(); @@ -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; } @@ -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; @@ -2856,7 +2880,7 @@ void Camera3Device::overrideResultForPrecaptureCancel( } bool Camera3Device::RequestThread::threadLoop() { - + ATRACE_CALL(); status_t res; // Handle paused state. @@ -2864,203 +2888,246 @@ 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; } - // Insert any queued triggers (before metadata is locked) - int32_t triggerCount; - res = insertTriggers(nextRequest); - 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); + // 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; } - triggerCount = res; - bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); + // 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 the request is the same as last, or we had triggers last time - if (mPrevRequest != nextRequest || triggersMixedIn) { - /** - * HAL workaround: - * Insert a dummy trigger ID if a trigger is set but no trigger ID is - */ - res = addDummyTriggerIds(nextRequest); 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); + // 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; } - /** - * 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; - 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, - ANDROID_CONTROL_AF_TRIGGER, - &e - ); - if (e.count > 0) { - ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", - __FUNCTION__, - request.frame_number, - e.data.u8[0]); - } - } - } else { - // leave request.settings NULL to indicate 'reuse latest given' - ALOGVV("%s: Request settings are REUSED", - __FUNCTION__); - } + // Mark that the request has be submitted successfully. + nextRequest.submitted = true; - uint32_t totalNumBuffers = 0; + // Update the latest request sent to HAL + if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged + Mutex::Autolock al(mLatestRequestMutex); - // Fill in buffers - if (nextRequest->mInputStream != NULL) { - request.input_buffer = &nextRequest->mInputBuffer; - totalNumBuffers += 1; - } else { - request.input_buffer = NULL; - } + 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); + } - 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)); + // Remove any previously queued triggers (after unlock) + res = removeTriggers(mPrevRequest); 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); - } + 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(); } - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return true; + return false; } - request.num_output_buffers++; } - totalNumBuffers += request.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; + if (useFlushLock) { + mFlushLock.unlock(); } - res = parent->registerInFlight(request.frame_number, - totalNumBuffers, nextRequest->mResultExtras, - /*hasInput*/request.input_buffer != NULL, - nextRequest->mAeTriggerCancelOverride); - ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 - ", burstId = %" PRId32 ".", - __FUNCTION__, - nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, - nextRequest->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; + // Unset as current request + { + Mutex::Autolock l(mRequestLock); + mNextRequests.clear(); } - // Inform waitUntilRequestProcessed thread of a new request ID - { - Mutex::Autolock al(mLatestRequestMutex); + return true; +} - mLatestRequestId = requestId; - mLatestRequestSignal.signal(); +status_t Camera3Device::RequestThread::prepareHalRequests(Vector<NextRequest> *nextRequests) { + ATRACE_CALL(); + + if (nextRequests == nullptr) { + return BAD_VALUE; } - // 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(); + for (auto& nextRequest : *nextRequests) { + sp<CaptureRequest> captureRequest = nextRequest.captureRequest; + camera3_capture_request_t* halRequest = &nextRequest.halRequest; + Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers; - 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; - } + // Prepare a request to HAL + halRequest->frame_number = captureRequest->mResultExtras.frameNumber; - // Update the latest request sent to HAL - if (request.settings != NULL) { // Don't update them if they were unchanged - Mutex::Autolock al(mLatestRequestMutex); + // Insert any queued triggers (before metadata is locked) + status_t res = insertTriggers(captureRequest); - camera_metadata_t* cloned = clone_camera_metadata(request.settings); - mLatestRequest.acquire(cloned); - } + if (res < 0) { + SET_ERR("RequestThread: Unable to insert triggers " + "(capture request %d, HAL device: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } + int triggerCount = res; + bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); + mPrevTriggers = triggerCount; - if (request.settings != NULL) { - nextRequest->mSettings.unlock(request.settings); - } + // If the request is the same as last, or we had triggers last time + if (mPrevRequest != captureRequest || triggersMixedIn) { + /** + * HAL workaround: + * Insert a dummy trigger ID if a trigger is set but no trigger ID is + */ + res = addDummyTriggerIds(captureRequest); + if (res != OK) { + SET_ERR("RequestThread: Unable to insert dummy trigger IDs " + "(capture request %d, HAL device: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } - // Unset as current request - { - Mutex::Autolock l(mRequestLock); - mNextRequest.clear(); - } + /** + * The request should be presorted so accesses in HAL + * are O(logn). Sidenote, sorting a sorted metadata is nop. + */ + 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( + halRequest->settings, + ANDROID_CONTROL_AF_TRIGGER, + &e + ); + if (e.count > 0) { + ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", + __FUNCTION__, + halRequest->frame_number, + e.data.u8[0]); + } + } + } else { + // leave request.settings NULL to indicate 'reuse latest given' + ALOGVV("%s: Request settings are REUSED", + __FUNCTION__); + } - // 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; + uint32_t totalNumBuffers = 0; + + // Fill in buffers + if (captureRequest->mInputStream != NULL) { + halRequest->input_buffer = &captureRequest->mInputBuffer; + totalNumBuffers += 1; + } else { + halRequest->input_buffer = NULL; + } + + 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); + + return TIMED_OUT; + } + halRequest->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"); + return INVALID_OPERATION; + } + 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__, + 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); + return INVALID_OPERATION; + } } - mPrevTriggers = triggerCount; - return true; + return OK; } CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { @@ -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) { @@ -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) { - - if (request.settings != NULL) { - nextRequest->mSettings.unlock(request.settings); - } - if (nextRequest->mInputStream != NULL) { - nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; - nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); +void Camera3Device::RequestThread::cleanUpFailedRequests(Vector<NextRequest> *nextRequests, + bool sendRequestError) { + if (nextRequests == nullptr) { + return; } - 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 (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 (halRequest->settings != NULL) { + captureRequest->mSettings.unlock(halRequest->settings); + } + + if (captureRequest->mInputStream != NULL) { + captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; + captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer); + } + + 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); + if (mListener != NULL) { + mListener->notifyError( + ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, + captureRequest->mResultExtras); + } + } } Mutex::Autolock l(mRequestLock); - mNextRequest.clear(); + mNextRequests.clear(); + nextRequests->clear(); } -sp<Camera3Device::CaptureRequest> - Camera3Device::RequestThread::waitForNextRequest() { - status_t res; - 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 // 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 @@ -3224,8 +3358,6 @@ sp<Camera3Device::CaptureRequest> handleAePrecaptureCancelRequest(nextRequest); - mNextRequest = nextRequest; - return nextRequest; } diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 1f39940..a3abbaf 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -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; @@ -441,6 +446,11 @@ class Camera3Device : 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 * will be temporarily rewritten to add the trigger tag/value. @@ -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); - // 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); + // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold. + sp<CaptureRequest> waitForNextRequestLocked(); + + // 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(); @@ -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; diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp index ecb8ac8..1d9d04f 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp @@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const { return OK; } +bool Camera3DummyStream::isVideoStream() const { + return false; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h index 3a3dbf4..97c0c96 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.h +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h @@ -54,6 +54,11 @@ class Camera3DummyStream : status_t setTransform(int transform); + /** + * Return if this output stream is for video encoding. + */ + bool isVideoStream() const; + protected: /** diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 8c611d5..3f0a736 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -426,6 +426,17 @@ status_t Camera3OutputStream::getEndpointUsage(uint32_t *usage) const { return res; } +bool Camera3OutputStream::isVideoStream() const { + uint32_t usage = 0; + status_t res = getEndpointUsage(&usage); + if (res != OK) { + ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res); + return false; + } + + return (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h index 941d693..3c083ec 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h @@ -64,6 +64,11 @@ class Camera3OutputStream : */ status_t setTransform(int transform); + /** + * Return if this output stream is for video encoding. + */ + bool isVideoStream() const; + protected: Camera3OutputStream(int id, camera3_stream_type_t type, uint32_t width, uint32_t height, int format, diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h index aae72cf..df89b34 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h @@ -34,6 +34,11 @@ class Camera3OutputStreamInterface : public virtual Camera3StreamInterface { * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. */ virtual status_t setTransform(int transform) = 0; + + /** + * Return if this output stream is for video encoding. + */ + virtual bool isVideoStream() const = 0; }; } // namespace camera3 diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 7163d62..691764f 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -455,8 +455,9 @@ status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration); if (res != OK) { if (res == TIMED_OUT) { - ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__, - kWaitForBufferDuration / 1000000LL); + ALOGE("%s: wait for output buffer return timed out after %lldms (max_buffers %d)", + __FUNCTION__, kWaitForBufferDuration / 1000000LL, + camera3_stream::max_buffers); } return res; } |