diff options
Diffstat (limited to 'services/camera/libcameraservice/device3')
11 files changed, 619 insertions, 209 deletions
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 1d4768c..2f874f5 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -102,8 +102,10 @@ status_t Camera3Device::initialize(camera_module_t *module) camera3_device_t *device; + ATRACE_BEGIN("camera3->open"); res = module->common.methods->open(&module->common, deviceName.string(), reinterpret_cast<hw_device_t**>(&device)); + ATRACE_END(); if (res != OK) { SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res); @@ -112,9 +114,9 @@ status_t Camera3Device::initialize(camera_module_t *module) /** Cross-check device version */ - if (device->common.version != CAMERA_DEVICE_API_VERSION_3_0) { + if (device->common.version < CAMERA_DEVICE_API_VERSION_3_0) { SET_ERR_L("Could not open camera: " - "Camera device is not version %x, reports %x instead", + "Camera device should be at least %x, reports %x instead", CAMERA_DEVICE_API_VERSION_3_0, device->common.version); device->common.close(&device->common); @@ -128,7 +130,7 @@ status_t Camera3Device::initialize(camera_module_t *module) if (info.device_version != device->common.version) { SET_ERR_L("HAL reporting mismatched camera_info version (%x)" " and device version (%x).", - device->common.version, info.device_version); + info.device_version, device->common.version); device->common.close(&device->common); return BAD_VALUE; } @@ -146,24 +148,6 @@ status_t Camera3Device::initialize(camera_module_t *module) return BAD_VALUE; } - /** Get vendor metadata tags */ - - mVendorTagOps.get_camera_vendor_section_name = NULL; - - ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops"); - device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps); - ATRACE_END(); - - if (mVendorTagOps.get_camera_vendor_section_name != NULL) { - res = set_camera_metadata_vendor_tag_ops(&mVendorTagOps); - if (res != OK) { - SET_ERR_L("Unable to set tag ops: %s (%d)", - strerror(-res), res); - device->common.close(&device->common); - return res; - } - } - /** Start up status tracker thread */ mStatusTracker = new StatusTracker(this); res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string()); @@ -271,7 +255,9 @@ status_t Camera3Device::disconnect() { mStatusTracker.clear(); if (mHal3Device != NULL) { + ATRACE_BEGIN("camera3->close"); mHal3Device->common.close(&mHal3Device->common); + ATRACE_END(); mHal3Device = NULL; } @@ -298,6 +284,53 @@ bool Camera3Device::tryLockSpinRightRound(Mutex& lock) { return gotLock; } +ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const { + // TODO: replace below with availableStreamConfiguration for HAL3.2+. + camera_metadata_ro_entry availableJpegSizes = + mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_JPEG_SIZES); + if (availableJpegSizes.count == 0 || availableJpegSizes.count % 2 != 0) { + ALOGE("%s: Camera %d: Can't find find valid available jpeg sizes in static metadata!", + __FUNCTION__, mId); + return BAD_VALUE; + } + + // Get max jpeg size (area-wise). + int32_t maxJpegWidth = 0, maxJpegHeight = 0; + bool foundMax = false; + for (size_t i = 0; i < availableJpegSizes.count; i += 2) { + if ((availableJpegSizes.data.i32[i] * availableJpegSizes.data.i32[i + 1]) + > (maxJpegWidth * maxJpegHeight)) { + maxJpegWidth = availableJpegSizes.data.i32[i]; + maxJpegHeight = availableJpegSizes.data.i32[i + 1]; + foundMax = true; + } + } + if (!foundMax) { + return BAD_VALUE; + } + + // Get max jpeg buffer size + ssize_t maxJpegBufferSize = 0; + camera_metadata_ro_entry jpegMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE); + if (jpegMaxSize.count == 0) { + ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId); + return BAD_VALUE; + } + maxJpegBufferSize = jpegMaxSize.data.i32[0]; + + // Calculate final jpeg buffer size for the given resolution. + float scaleFactor = ((float) (width * height)) / (maxJpegWidth * maxJpegHeight); + ssize_t jpegBufferSize = scaleFactor * maxJpegBufferSize; + // Bound the buffer size to [MIN_JPEG_BUFFER_SIZE, maxJpegBufferSize]. + if (jpegBufferSize > maxJpegBufferSize) { + jpegBufferSize = maxJpegBufferSize; + } else if (jpegBufferSize < kMinJpegBufferSize) { + jpegBufferSize = kMinJpegBufferSize; + } + + return jpegBufferSize; +} + status_t Camera3Device::dump(int fd, const Vector<String16> &args) { ATRACE_CALL(); (void)args; @@ -386,14 +419,7 @@ const CameraMetadata& Camera3Device::info() const { return mDeviceInfo; } -status_t Camera3Device::capture(CameraMetadata &request) { - ATRACE_CALL(); - status_t res; - Mutex::Autolock il(mInterfaceLock); - Mutex::Autolock l(mLock); - - // TODO: take ownership of the request - +status_t Camera3Device::checkStatusOkToCaptureLocked() { switch (mStatus) { case STATUS_ERROR: CLOGE("Device has encountered a serious error"); @@ -402,7 +428,6 @@ status_t Camera3Device::capture(CameraMetadata &request) { CLOGE("Device not initialized"); return INVALID_OPERATION; case STATUS_UNCONFIGURED: - // May be lazily configuring streams, will check during setup case STATUS_CONFIGURED: case STATUS_ACTIVE: // OK @@ -411,71 +436,119 @@ status_t Camera3Device::capture(CameraMetadata &request) { SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } + return OK; +} - sp<CaptureRequest> newRequest = setUpRequestLocked(request); - if (newRequest == NULL) { - CLOGE("Can't create capture request"); +status_t Camera3Device::convertMetadataListToRequestListLocked( + const List<const CameraMetadata> &metadataList, RequestList *requestList) { + if (requestList == NULL) { + CLOGE("requestList cannot be NULL."); return BAD_VALUE; } - res = mRequestThread->queueRequest(newRequest); - if (res == OK) { - waitUntilStateThenRelock(/*active*/ true, kActiveTimeout); - if (res != OK) { - SET_ERR_L("Can't transition to active in %f seconds!", - kActiveTimeout/1e9); + int32_t burstId = 0; + for (List<const CameraMetadata>::const_iterator it = metadataList.begin(); + it != metadataList.end(); ++it) { + sp<CaptureRequest> newRequest = setUpRequestLocked(*it); + if (newRequest == 0) { + CLOGE("Can't create capture request"); + return BAD_VALUE; } - ALOGV("Camera %d: Capture request enqueued", mId); + + // Setup burst Id and request Id + newRequest->mResultExtras.burstId = burstId++; + if (it->exists(ANDROID_REQUEST_ID)) { + if (it->find(ANDROID_REQUEST_ID).count == 0) { + CLOGE("RequestID entry exists; but must not be empty in metadata"); + return BAD_VALUE; + } + newRequest->mResultExtras.requestId = it->find(ANDROID_REQUEST_ID).data.i32[0]; + } else { + CLOGE("RequestID does not exist in metadata"); + return BAD_VALUE; + } + + requestList->push_back(newRequest); + + ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); } - return res; + return OK; } +status_t Camera3Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) { + ATRACE_CALL(); + + List<const CameraMetadata> requests; + requests.push_back(request); + return captureList(requests, /*lastFrameNumber*/NULL); +} -status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) { +status_t Camera3Device::submitRequestsHelper( + const List<const CameraMetadata> &requests, bool repeating, + /*out*/ + int64_t *lastFrameNumber) { ATRACE_CALL(); - status_t res; Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - switch (mStatus) { - case STATUS_ERROR: - CLOGE("Device has encountered a serious error"); - return INVALID_OPERATION; - case STATUS_UNINITIALIZED: - CLOGE("Device not initialized"); - return INVALID_OPERATION; - case STATUS_UNCONFIGURED: - // May be lazily configuring streams, will check during setup - case STATUS_CONFIGURED: - case STATUS_ACTIVE: - // OK - break; - default: - SET_ERR_L("Unexpected status: %d", mStatus); - return INVALID_OPERATION; + status_t res = checkStatusOkToCaptureLocked(); + if (res != OK) { + // error logged by previous call + return res; } - sp<CaptureRequest> newRepeatingRequest = setUpRequestLocked(request); - if (newRepeatingRequest == NULL) { - CLOGE("Can't create repeating request"); - return BAD_VALUE; + RequestList requestList; + + res = convertMetadataListToRequestListLocked(requests, /*out*/&requestList); + if (res != OK) { + // error logged by previous call + return res; } - RequestList newRepeatingRequests; - newRepeatingRequests.push_back(newRepeatingRequest); + if (repeating) { + res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber); + } else { + res = mRequestThread->queueRequestList(requestList, lastFrameNumber); + } - res = mRequestThread->setRepeatingRequests(newRepeatingRequests); if (res == OK) { - waitUntilStateThenRelock(/*active*/ true, kActiveTimeout); + waitUntilStateThenRelock(/*active*/true, kActiveTimeout); if (res != OK) { SET_ERR_L("Can't transition to active in %f seconds!", kActiveTimeout/1e9); } - ALOGV("Camera %d: Repeating request set", mId); + ALOGV("Camera %d: Capture request %" PRId32 " enqueued", mId, + (*(requestList.begin()))->mResultExtras.requestId); + } else { + CLOGE("Cannot queue request. Impossible."); + return BAD_VALUE; } + return res; } +status_t Camera3Device::captureList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber) { + ATRACE_CALL(); + + return submitRequestsHelper(requests, /*repeating*/false, lastFrameNumber); +} + +status_t Camera3Device::setStreamingRequest(const CameraMetadata &request, + int64_t* /*lastFrameNumber*/) { + ATRACE_CALL(); + + List<const CameraMetadata> requests; + requests.push_back(request); + return setStreamingRequestList(requests, /*lastFrameNumber*/NULL); +} + +status_t Camera3Device::setStreamingRequestList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber) { + ATRACE_CALL(); + + return submitRequestsHelper(requests, /*repeating*/true, lastFrameNumber); +} sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked( const CameraMetadata &request) { @@ -497,7 +570,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked( return newRequest; } -status_t Camera3Device::clearStreamingRequest() { +status_t Camera3Device::clearStreamingRequest(int64_t *lastFrameNumber) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); @@ -519,7 +592,8 @@ status_t Camera3Device::clearStreamingRequest() { return INVALID_OPERATION; } ALOGV("Camera %d: Clearing repeating request", mId); - return mRequestThread->clearRepeatingRequests(); + + return mRequestThread->clearRepeatingRequests(lastFrameNumber); } status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) { @@ -714,8 +788,17 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, sp<Camera3OutputStream> newStream; if (format == HAL_PIXEL_FORMAT_BLOB) { + ssize_t jpegBufferSize = getJpegBufferSize(width, height); + if (jpegBufferSize > 0) { + ALOGV("%s: Overwrite Jpeg output buffer size from %zu to %zu", + __FUNCTION__, size, jpegBufferSize); + } else { + SET_ERR_L("Invalid jpeg buffer size %zd", jpegBufferSize); + return BAD_VALUE; + } + newStream = new Camera3OutputStream(mNextStreamId, consumer, - width, height, size, format); + width, height, jpegBufferSize, format); } else { newStream = new Camera3OutputStream(mNextStreamId, consumer, width, height, format); @@ -840,16 +923,20 @@ status_t Camera3Device::deleteStream(int id) { } sp<Camera3StreamInterface> deletedStream; + ssize_t outputStreamIdx = mOutputStreams.indexOfKey(id); if (mInputStream != NULL && id == mInputStream->getId()) { deletedStream = mInputStream; mInputStream.clear(); } else { - ssize_t idx = mOutputStreams.indexOfKey(id); - if (idx == NAME_NOT_FOUND) { + if (outputStreamIdx == NAME_NOT_FOUND) { CLOGE("Stream %d does not exist", id); return BAD_VALUE; } - deletedStream = mOutputStreams.editValueAt(idx); + } + + // Delete output stream or the output part of a bi-directional stream. + if (outputStreamIdx != NAME_NOT_FOUND) { + deletedStream = mOutputStreams.editValueAt(outputStreamIdx); mOutputStreams.removeItem(id); } @@ -918,6 +1005,10 @@ status_t Camera3Device::waitUntilDrained() { Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); + return waitUntilDrainedLocked(); +} + +status_t Camera3Device::waitUntilDrainedLocked() { switch (mStatus) { case STATUS_UNINITIALIZED: case STATUS_UNCONFIGURED: @@ -1030,7 +1121,7 @@ status_t Camera3Device::waitForNextFrame(nsecs_t timeout) { return OK; } -status_t Camera3Device::getNextFrame(CameraMetadata *frame) { +status_t Camera3Device::getNextResult(CaptureResult *frame) { ATRACE_CALL(); Mutex::Autolock l(mOutputLock); @@ -1038,8 +1129,14 @@ status_t Camera3Device::getNextFrame(CameraMetadata *frame) { return NOT_ENOUGH_DATA; } - CameraMetadata &result = *(mResultQueue.begin()); - frame->acquire(result); + if (frame == NULL) { + ALOGE("%s: argument cannot be NULL", __FUNCTION__); + return BAD_VALUE; + } + + CaptureResult &result = *(mResultQueue.begin()); + frame->mResultExtras = result.mResultExtras; + frame->mMetadata.acquire(result.mMetadata); mResultQueue.erase(mResultQueue.begin()); return OK; @@ -1117,14 +1214,25 @@ status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId, return INVALID_OPERATION; } -status_t Camera3Device::flush() { +status_t Camera3Device::flush(int64_t *frameNumber) { ATRACE_CALL(); ALOGV("%s: Camera %d: Flushing all requests", __FUNCTION__, mId); Mutex::Autolock il(mInterfaceLock); - Mutex::Autolock l(mLock); - mRequestThread->clear(); - return mHal3Device->ops->flush(mHal3Device); + { + Mutex::Autolock l(mLock); + mRequestThread->clear(/*out*/frameNumber); + } + + status_t res; + if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { + res = mHal3Device->ops->flush(mHal3Device); + } else { + Mutex::Autolock l(mLock); + res = waitUntilDrainedLocked(); + } + + return res; } /** @@ -1392,13 +1500,13 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) { * In-flight request management */ -status_t Camera3Device::registerInFlight(int32_t frameNumber, - int32_t requestId, int32_t numBuffers) { +status_t Camera3Device::registerInFlight(uint32_t frameNumber, + int32_t numBuffers, CaptureResultExtras resultExtras) { ATRACE_CALL(); Mutex::Autolock l(mInFlightLock); ssize_t res; - res = mInFlightMap.add(frameNumber, InFlightRequest(requestId, numBuffers)); + res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras)); if (res < 0) return res; return OK; @@ -1410,8 +1518,8 @@ status_t Camera3Device::registerInFlight(int32_t frameNumber, * to the output frame queue */ bool Camera3Device::processPartial3AQuirk( - int32_t frameNumber, int32_t requestId, - const CameraMetadata& partial) { + uint32_t frameNumber, + const CameraMetadata& partial, const CaptureResultExtras& resultExtras) { // Check if all 3A states are present // The full list of fields is @@ -1460,7 +1568,7 @@ bool Camera3Device::processPartial3AQuirk( ALOGVV("%s: Camera %d: Frame %d, Request ID %d: AF mode %d, AWB mode %d, " "AF state %d, AE state %d, AWB state %d, " "AF trigger %d, AE precapture trigger %d", - __FUNCTION__, mId, frameNumber, requestId, + __FUNCTION__, mId, frameNumber, resultExtras.requestId, afMode, awbMode, afState, aeState, awbState, afTriggerId, aeTriggerId); @@ -1475,58 +1583,63 @@ bool Camera3Device::processPartial3AQuirk( Mutex::Autolock l(mOutputLock); - CameraMetadata& min3AResult = - *mResultQueue.insert( - mResultQueue.end(), - CameraMetadata(kMinimal3AResultEntries, /*dataCapacity*/ 0)); - - if (!insert3AResult(min3AResult, ANDROID_REQUEST_FRAME_COUNT, - &frameNumber, frameNumber)) { + CaptureResult captureResult; + captureResult.mResultExtras = resultExtras; + captureResult.mMetadata = CameraMetadata(kMinimal3AResultEntries, /*dataCapacity*/ 0); + // TODO: change this to sp<CaptureResult>. This will need other changes, including, + // but not limited to CameraDeviceBase::getNextResult + CaptureResult& min3AResult = + *mResultQueue.insert(mResultQueue.end(), captureResult); + + if (!insert3AResult(min3AResult.mMetadata, ANDROID_REQUEST_FRAME_COUNT, + // TODO: This is problematic casting. Need to fix CameraMetadata. + reinterpret_cast<int32_t*>(&frameNumber), frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_REQUEST_ID, + int32_t requestId = resultExtras.requestId; + if (!insert3AResult(min3AResult.mMetadata, ANDROID_REQUEST_ID, &requestId, frameNumber)) { return false; } static const uint8_t partialResult = ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL; - if (!insert3AResult(min3AResult, ANDROID_QUIRKS_PARTIAL_RESULT, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_QUIRKS_PARTIAL_RESULT, &partialResult, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_MODE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_MODE, &afMode, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_MODE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AWB_MODE, &awbMode, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_STATE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AE_STATE, &aeState, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_STATE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_STATE, &afState, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_STATE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AWB_STATE, &awbState, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_TRIGGER_ID, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_TRIGGER_ID, &afTriggerId, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_PRECAPTURE_ID, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AE_PRECAPTURE_ID, &aeTriggerId, frameNumber)) { return false; } @@ -1538,7 +1651,7 @@ bool Camera3Device::processPartial3AQuirk( template<typename T> bool Camera3Device::get3AResult(const CameraMetadata& result, int32_t tag, - T* value, int32_t frameNumber) { + T* value, uint32_t frameNumber) { (void) frameNumber; camera_metadata_ro_entry_t entry; @@ -1563,7 +1676,7 @@ bool Camera3Device::get3AResult(const CameraMetadata& result, int32_t tag, template<typename T> bool Camera3Device::insert3AResult(CameraMetadata& result, int32_t tag, - const T* value, int32_t frameNumber) { + const T* value, uint32_t frameNumber) { if (result.update(tag, value, 1) != NO_ERROR) { mResultQueue.erase(--mResultQueue.end(), mResultQueue.end()); SET_ERR("Frame %d: Failed to set %s in partial metadata", @@ -1590,11 +1703,12 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { } bool partialResultQuirk = false; CameraMetadata collectedQuirkResult; + CaptureResultExtras resultExtras; - // Get capture timestamp from list of in-flight requests, where it was added - // by the shutter notification for this frame. Then update the in-flight - // status and remove the in-flight entry if all result data has been - // received. + // Get capture timestamp and resultExtras from list of in-flight requests, + // where it was added by the shutter notification for this frame. + // Then update the in-flight status and remove the in-flight entry if + // all result data has been received. nsecs_t timestamp = 0; { Mutex::Autolock l(mInFlightLock); @@ -1605,6 +1719,10 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { return; } InFlightRequest &request = mInFlightMap.editValueAt(idx); + ALOGVV("%s: got InFlightRequest requestId = %" PRId32 ", frameNumber = %" PRId64 + ", burstId = %" PRId32, + __FUNCTION__, request.resultExtras.requestId, request.resultExtras.frameNumber, + request.resultExtras.burstId); // Check if this result carries only partial metadata if (mUsePartialResultQuirk && result->result != NULL) { @@ -1626,13 +1744,15 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { if (!request.partialResultQuirk.haveSent3A) { request.partialResultQuirk.haveSent3A = processPartial3AQuirk(frameNumber, - request.requestId, - request.partialResultQuirk.collectedResult); + request.partialResultQuirk.collectedResult, + request.resultExtras); } } } timestamp = request.captureTimestamp; + resultExtras = request.resultExtras; + /** * One of the following must happen before it's legal to call process_capture_result, * unless partial metadata is being provided: @@ -1668,8 +1788,10 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { return; } - // Check if everything has arrived for this result (buffers and metadata) - if (request.haveResultMetadata && request.numBuffersLeft == 0) { + // Check if everything has arrived for this result (buffers and metadata), remove it from + // InFlightMap if both arrived or HAL reports error for this request (i.e. during flush). + if ((request.requestStatus != OK) || + (request.haveResultMetadata && request.numBuffersLeft == 0)) { ATRACE_ASYNC_END("frame capture", frameNumber); mInFlightMap.removeItemsAt(idx, 1); } @@ -1689,19 +1811,21 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { gotResult = true; - if (frameNumber != mNextResultFrameNumber) { + // TODO: need to track errors for tighter bounds on expected frame number + if (frameNumber < mNextResultFrameNumber) { SET_ERR("Out-of-order capture result metadata submitted! " "(got frame number %d, expecting %d)", frameNumber, mNextResultFrameNumber); return; } - mNextResultFrameNumber++; + mNextResultFrameNumber = frameNumber + 1; - CameraMetadata captureResult; - captureResult = result->result; + CaptureResult captureResult; + captureResult.mResultExtras = resultExtras; + captureResult.mMetadata = result->result; - if (captureResult.update(ANDROID_REQUEST_FRAME_COUNT, - (int32_t*)&frameNumber, 1) != OK) { + if (captureResult.mMetadata.update(ANDROID_REQUEST_FRAME_COUNT, + (int32_t*)&frameNumber, 1) != OK) { SET_ERR("Failed to set frame# in metadata (%d)", frameNumber); gotResult = false; @@ -1712,15 +1836,15 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { // Append any previous partials to form a complete result if (mUsePartialResultQuirk && !collectedQuirkResult.isEmpty()) { - captureResult.append(collectedQuirkResult); + captureResult.mMetadata.append(collectedQuirkResult); } - captureResult.sort(); + captureResult.mMetadata.sort(); // Check that there's a timestamp in the result metadata camera_metadata_entry entry = - captureResult.find(ANDROID_SENSOR_TIMESTAMP); + captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP); if (entry.count == 0) { SET_ERR("No timestamp provided by HAL for frame %d!", frameNumber); @@ -1734,9 +1858,13 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { if (gotResult) { // Valid result, insert into queue - CameraMetadata& queuedResult = - *mResultQueue.insert(mResultQueue.end(), CameraMetadata()); - queuedResult.swap(captureResult); + List<CaptureResult>::iterator queuedResult = + mResultQueue.insert(mResultQueue.end(), CaptureResult(captureResult)); + ALOGVV("%s: result requestId = %" PRId32 ", frameNumber = %" PRId64 + ", burstId = %" PRId32, __FUNCTION__, + queuedResult->mResultExtras.requestId, + queuedResult->mResultExtras.frameNumber, + queuedResult->mResultExtras.burstId); } } // scope for mOutputLock @@ -1762,8 +1890,6 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { } - - void Camera3Device::notify(const camera3_notify_msg *msg) { ATRACE_CALL(); NotificationListener *listener; @@ -1790,18 +1916,32 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { mId, __FUNCTION__, msg->message.error.frame_number, streamId, msg->message.error.error_code); + CaptureResultExtras resultExtras; // Set request error status for the request in the in-flight tracking { Mutex::Autolock l(mInFlightLock); ssize_t idx = mInFlightMap.indexOfKey(msg->message.error.frame_number); if (idx >= 0) { - mInFlightMap.editValueAt(idx).requestStatus = msg->message.error.error_code; + InFlightRequest &r = mInFlightMap.editValueAt(idx); + r.requestStatus = msg->message.error.error_code; + resultExtras = r.resultExtras; + } else { + resultExtras.frameNumber = msg->message.error.frame_number; + ALOGE("Camera %d: %s: cannot find in-flight request on frame %" PRId64 + " error", mId, __FUNCTION__, resultExtras.frameNumber); } } if (listener != NULL) { - listener->notifyError(msg->message.error.error_code, - msg->message.error.frame_number, streamId); + if (msg->message.error.error_code == CAMERA3_MSG_ERROR_DEVICE) { + listener->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE, + resultExtras); + } else { + listener->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE, + resultExtras); + } + } else { + ALOGE("Camera %d: %s: no listener available", mId, __FUNCTION__); } break; } @@ -1812,16 +1952,17 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { // Verify ordering of shutter notifications { Mutex::Autolock l(mOutputLock); - if (frameNumber != mNextShutterFrameNumber) { + // TODO: need to track errors for tighter bounds on expected frame number. + if (frameNumber < mNextShutterFrameNumber) { SET_ERR("Shutter notification out-of-order. Expected " "notification for frame %d, got frame %d", mNextShutterFrameNumber, frameNumber); break; } - mNextShutterFrameNumber++; + mNextShutterFrameNumber = frameNumber + 1; } - int32_t requestId = -1; + CaptureResultExtras resultExtras; // Set timestamp for the request in the in-flight tracking // and get the request ID to send upstream @@ -1831,7 +1972,7 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { if (idx >= 0) { InFlightRequest &r = mInFlightMap.editValueAt(idx); r.captureTimestamp = timestamp; - requestId = r.requestId; + resultExtras = r.resultExtras; } } if (idx < 0) { @@ -1840,10 +1981,10 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { break; } ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %" PRId64, - mId, __FUNCTION__, frameNumber, requestId, timestamp); + mId, __FUNCTION__, frameNumber, resultExtras.requestId, timestamp); // Call listener, if any if (listener != NULL) { - listener->notifyShutter(requestId, timestamp); + listener->notifyShutter(resultExtras, timestamp); } break; } @@ -1865,6 +2006,7 @@ CameraMetadata Camera3Device::getLatestRequestLocked() { return retVal; } + /** * RequestThread inner class methods */ @@ -1881,7 +2023,8 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, mDoPause(false), mPaused(true), mFrameNumber(0), - mLatestRequestId(NAME_NOT_FOUND) { + mLatestRequestId(NAME_NOT_FOUND), + mRepeatingLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES) { mStatusId = statusTracker->addComponent(); } @@ -1890,10 +2033,22 @@ void Camera3Device::RequestThread::configurationComplete() { mReconfigured = true; } -status_t Camera3Device::RequestThread::queueRequest( - sp<CaptureRequest> request) { +status_t Camera3Device::RequestThread::queueRequestList( + List<sp<CaptureRequest> > &requests, + /*out*/ + int64_t *lastFrameNumber) { Mutex::Autolock l(mRequestLock); - mRequestQueue.push_back(request); + for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end(); + ++it) { + mRequestQueue.push_back(*it); + } + + if (lastFrameNumber != NULL) { + *lastFrameNumber = mFrameNumber + mRequestQueue.size() - 1; + ALOGV("%s: requestId %d, mFrameNumber %" PRId32 ", lastFrameNumber %" PRId64 ".", + __FUNCTION__, (*(requests.begin()))->mResultExtras.requestId, mFrameNumber, + *lastFrameNumber); + } unpauseForNewRequests(); @@ -1957,28 +2112,43 @@ status_t Camera3Device::RequestThread::queueTriggerLocked( } status_t Camera3Device::RequestThread::setRepeatingRequests( - const RequestList &requests) { + const RequestList &requests, + /*out*/ + int64_t *lastFrameNumber) { Mutex::Autolock l(mRequestLock); + if (lastFrameNumber != NULL) { + *lastFrameNumber = mRepeatingLastFrameNumber; + } mRepeatingRequests.clear(); mRepeatingRequests.insert(mRepeatingRequests.begin(), requests.begin(), requests.end()); unpauseForNewRequests(); + mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES; return OK; } -status_t Camera3Device::RequestThread::clearRepeatingRequests() { +status_t Camera3Device::RequestThread::clearRepeatingRequests(/*out*/int64_t *lastFrameNumber) { Mutex::Autolock l(mRequestLock); mRepeatingRequests.clear(); + if (lastFrameNumber != NULL) { + *lastFrameNumber = mRepeatingLastFrameNumber; + } + mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES; return OK; } -status_t Camera3Device::RequestThread::clear() { +status_t Camera3Device::RequestThread::clear(/*out*/int64_t *lastFrameNumber) { Mutex::Autolock l(mRequestLock); + ALOGV("RequestThread::%s:", __FUNCTION__); mRepeatingRequests.clear(); mRequestQueue.clear(); mTriggerMap.clear(); + if (lastFrameNumber != NULL) { + *lastFrameNumber = mRepeatingLastFrameNumber; + } + mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES; return OK; } @@ -2030,6 +2200,7 @@ bool Camera3Device::RequestThread::threadLoop() { // 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 @@ -2050,7 +2221,7 @@ bool Camera3Device::RequestThread::threadLoop() { if (res < 0) { SET_ERR("RequestThread: Unable to insert triggers " "(capture request %d, HAL device: %s (%d)", - (mFrameNumber+1), strerror(-res), res); + request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } @@ -2068,7 +2239,7 @@ bool Camera3Device::RequestThread::threadLoop() { if (res != OK) { SET_ERR("RequestThread: Unable to insert dummy trigger IDs " "(capture request %d, HAL device: %s (%d)", - (mFrameNumber+1), strerror(-res), res); + request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } @@ -2092,7 +2263,7 @@ bool Camera3Device::RequestThread::threadLoop() { if (e.count > 0) { ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", __FUNCTION__, - mFrameNumber+1, + request.frame_number, e.data.u8[0]); } } @@ -2134,8 +2305,6 @@ bool Camera3Device::RequestThread::threadLoop() { request.num_output_buffers++; } - request.frame_number = mFrameNumber++; - // Log request in the in-flight queue sp<Camera3Device> parent = mParent.promote(); if (parent == NULL) { @@ -2144,8 +2313,13 @@ bool Camera3Device::RequestThread::threadLoop() { return false; } - res = parent->registerInFlight(request.frame_number, requestId, - request.num_output_buffers); + res = parent->registerInFlight(request.frame_number, + request.num_output_buffers, nextRequest->mResultExtras); + 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); @@ -2222,6 +2396,7 @@ CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { return mLatestRequest; } + void Camera3Device::RequestThread::cleanUpFailedRequest( camera3_capture_request_t &request, sp<CaptureRequest> &nextRequest, @@ -2263,6 +2438,9 @@ sp<Camera3Device::CaptureRequest> ++firstRequest, requests.end()); // No need to wait any longer + + mRepeatingLastFrameNumber = mFrameNumber + requests.size() - 1; + break; } @@ -2314,6 +2492,9 @@ sp<Camera3Device::CaptureRequest> mReconfigured = false; } + if (nextRequest != NULL) { + nextRequest->mResultExtras.frameNumber = mFrameNumber++; + } return nextRequest; } diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 468f641..00ae771 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -24,6 +24,8 @@ #include <utils/Thread.h> #include <utils/KeyedVector.h> #include <hardware/camera3.h> +#include <camera/CaptureResult.h> +#include <camera/camera2/ICameraDeviceUser.h> #include "common/CameraDeviceBase.h" #include "device3/StatusTracker.h" @@ -54,7 +56,7 @@ class Camera3StreamInterface; } /** - * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 + * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher. */ class Camera3Device : public CameraDeviceBase, @@ -78,15 +80,21 @@ class Camera3Device : // Capture and setStreamingRequest will configure streams if currently in // idle state - virtual status_t capture(CameraMetadata &request); - virtual status_t setStreamingRequest(const CameraMetadata &request); - virtual status_t clearStreamingRequest(); + virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL); + virtual status_t captureList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL); + virtual status_t setStreamingRequest(const CameraMetadata &request, + int64_t *lastFrameNumber = NULL); + virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL); + virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL); virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout); // Actual stream creation/deletion is delayed until first request is submitted // If adding streams while actively capturing, will pause device before adding - // stream, reconfiguring device, and unpausing. + // stream, reconfiguring device, and unpausing. Note that, for JPEG stream, the + // buffer size may be overwritten by an more accurate value calculated by Camera3Device. virtual status_t createStream(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, size_t size, int *id); @@ -116,7 +124,7 @@ class Camera3Device : virtual status_t setNotifyCallback(NotificationListener *listener); virtual bool willNotify3A(); virtual status_t waitForNextFrame(nsecs_t timeout); - virtual status_t getNextFrame(CameraMetadata *frame); + virtual status_t getNextResult(CaptureResult *frame); virtual status_t triggerAutofocus(uint32_t id); virtual status_t triggerCancelAutofocus(uint32_t id); @@ -125,7 +133,7 @@ class Camera3Device : virtual status_t pushReprocessBuffer(int reprocessStreamId, buffer_handle_t *buffer, wp<BufferReleasedListener> listener); - virtual status_t flush(); + virtual status_t flush(int64_t *lastFrameNumber = NULL); // Methods called by subclasses void notifyStatus(bool idle); // updates from StatusTracker @@ -137,6 +145,8 @@ class Camera3Device : static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec static const nsecs_t kActiveTimeout = 500000000; // 500 ms struct RequestTrigger; + // minimal jpeg buffer size: 256KB + blob header + static const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(camera3_jpeg_blob); // A lock to enforce serialization on the input/configure side // of the public interface. @@ -157,7 +167,6 @@ class Camera3Device : camera3_device_t *mHal3Device; CameraMetadata mDeviceInfo; - vendor_tag_query_ops_t mVendorTagOps; enum Status { STATUS_ERROR, @@ -199,9 +208,20 @@ class Camera3Device : sp<camera3::Camera3Stream> mInputStream; Vector<sp<camera3::Camera3OutputStreamInterface> > mOutputStreams; + CaptureResultExtras mResultExtras; }; typedef List<sp<CaptureRequest> > RequestList; + status_t checkStatusOkToCaptureLocked(); + + status_t convertMetadataListToRequestListLocked( + const List<const CameraMetadata> &metadataList, + /*out*/ + RequestList *requestList); + + status_t submitRequestsHelper(const List<const CameraMetadata> &requests, bool repeating, + int64_t *lastFrameNumber = NULL); + /** * Get the last request submitted to the hal by the request thread. * @@ -237,6 +257,13 @@ class Camera3Device : status_t waitUntilStateThenRelock(bool active, nsecs_t timeout); /** + * Implementation of waitUntilDrained. On success, will transition to IDLE state. + * + * Need to be called with mLock and mInterfaceLock held. + */ + status_t waitUntilDrainedLocked(); + + /** * Do common work for setting up a streaming or single capture request. * On success, will transition to ACTIVE if in IDLE. */ @@ -270,6 +297,12 @@ class Camera3Device : */ bool tryLockSpinRightRound(Mutex& lock); + /** + * Get Jpeg buffer size for a given jpeg resolution. + * Negative values are error codes. + */ + ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; + struct RequestTrigger { // Metadata tag number, e.g. android.control.aePrecaptureTrigger uint32_t metadataTag; @@ -308,15 +341,21 @@ class Camera3Device : * on either. Use waitUntilPaused to wait until request queue * has emptied out. */ - status_t setRepeatingRequests(const RequestList& requests); - status_t clearRepeatingRequests(); + status_t setRepeatingRequests(const RequestList& requests, + /*out*/ + int64_t *lastFrameNumber = NULL); + status_t clearRepeatingRequests(/*out*/ + int64_t *lastFrameNumber = NULL); - status_t queueRequest(sp<CaptureRequest> request); + status_t queueRequestList(List<sp<CaptureRequest> > &requests, + /*out*/ + int64_t *lastFrameNumber = NULL); /** * Remove all queued and repeating requests, and pending triggers */ - status_t clear(); + status_t clear(/*out*/ + int64_t *lastFrameNumber = NULL); /** * Queue a trigger to be dispatched with the next outgoing @@ -429,6 +468,8 @@ class Camera3Device : TriggerMap mTriggerMap; TriggerMap mTriggerRemovedMap; TriggerMap mTriggerReplacedMap; + + int64_t mRepeatingLastFrameNumber; }; sp<RequestThread> mRequestThread; @@ -437,8 +478,6 @@ class Camera3Device : */ struct InFlightRequest { - // android.request.id for the request - int requestId; // Set by notify() SHUTTER call. nsecs_t captureTimestamp; int requestStatus; @@ -447,6 +486,7 @@ class Camera3Device : // Decremented by calls to process_capture_result with valid output // buffers int numBuffersLeft; + CaptureResultExtras resultExtras; // Fields used by the partial result quirk only struct PartialResultQuirkInFlight { @@ -462,20 +502,26 @@ class Camera3Device : // Default constructor needed by KeyedVector InFlightRequest() : - requestId(0), captureTimestamp(0), requestStatus(OK), haveResultMetadata(false), numBuffersLeft(0) { } - InFlightRequest(int id, int numBuffers) : - requestId(id), + InFlightRequest(int numBuffers) : captureTimestamp(0), requestStatus(OK), haveResultMetadata(false), numBuffersLeft(numBuffers) { } + + InFlightRequest(int numBuffers, CaptureResultExtras extras) : + captureTimestamp(0), + requestStatus(OK), + haveResultMetadata(false), + numBuffersLeft(numBuffers), + resultExtras(extras) { + } }; // Map from frame number to the in-flight request state typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap; @@ -483,25 +529,25 @@ class Camera3Device : Mutex mInFlightLock; // Protects mInFlightMap InFlightMap mInFlightMap; - status_t registerInFlight(int32_t frameNumber, int32_t requestId, - int32_t numBuffers); + status_t registerInFlight(uint32_t frameNumber, + int32_t numBuffers, CaptureResultExtras resultExtras); /** * For the partial result quirk, check if all 3A state fields are available * and if so, queue up 3A-only result to the client. Returns true if 3A * is sent. */ - bool processPartial3AQuirk(int32_t frameNumber, int32_t requestId, - const CameraMetadata& partial); + bool processPartial3AQuirk(uint32_t frameNumber, + const CameraMetadata& partial, const CaptureResultExtras& resultExtras); // Helpers for reading and writing 3A metadata into to/from partial results template<typename T> bool get3AResult(const CameraMetadata& result, int32_t tag, - T* value, int32_t frameNumber); + T* value, uint32_t frameNumber); template<typename T> bool insert3AResult(CameraMetadata &result, int32_t tag, const T* value, - int32_t frameNumber); + uint32_t frameNumber); /** * Tracking for idle detection */ @@ -518,7 +564,7 @@ class Camera3Device : uint32_t mNextResultFrameNumber; uint32_t mNextShutterFrameNumber; - List<CameraMetadata> mResultQueue; + List<CaptureResult> mResultQueue; Condition mResultSignal; NotificationListener *mListener; diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp index d662cc2..50a2c10 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp @@ -34,7 +34,8 @@ Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type, Camera3Stream(id, type, width, height, maxSize, format), mTotalBufferCount(0), - mDequeuedBufferCount(0), + mHandoutTotalBufferCount(0), + mHandoutOutputBufferCount(0), mFrameCount(0), mLastTimestamp(0) { @@ -55,8 +56,8 @@ bool Camera3IOStreamBase::hasOutstandingBuffersLocked() const { nsecs_t signalTime = mCombinedFence->getSignalTime(); ALOGV("%s: Stream %d: Has %zu outstanding buffers," " buffer signal time is %" PRId64, - __FUNCTION__, mId, mDequeuedBufferCount, signalTime); - if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) { + __FUNCTION__, mId, mHandoutTotalBufferCount, signalTime); + if (mHandoutTotalBufferCount > 0 || signalTime == INT64_MAX) { return true; } return false; @@ -75,7 +76,7 @@ void Camera3IOStreamBase::dump(int fd, const Vector<String16> &args) const { lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n", mFrameCount, mLastTimestamp); lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n", - mTotalBufferCount, mDequeuedBufferCount); + mTotalBufferCount, mHandoutTotalBufferCount); write(fd, lines.string(), lines.size()); } @@ -104,6 +105,14 @@ size_t Camera3IOStreamBase::getBufferCountLocked() { return mTotalBufferCount; } +size_t Camera3IOStreamBase::getHandoutOutputBufferCountLocked() { + return mHandoutOutputBufferCount; +} + +size_t Camera3IOStreamBase::getHandoutInputBufferCountLocked() { + return (mHandoutTotalBufferCount - mHandoutOutputBufferCount); +} + status_t Camera3IOStreamBase::disconnectLocked() { switch (mState) { case STATE_IN_RECONFIG: @@ -117,9 +126,9 @@ status_t Camera3IOStreamBase::disconnectLocked() { return -ENOTCONN; } - if (mDequeuedBufferCount > 0) { + if (mHandoutTotalBufferCount > 0) { ALOGE("%s: Can't disconnect with %zu buffers still dequeued!", - __FUNCTION__, mDequeuedBufferCount); + __FUNCTION__, mHandoutTotalBufferCount); return INVALID_OPERATION; } @@ -130,7 +139,8 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, buffer_handle_t *handle, int acquireFence, int releaseFence, - camera3_buffer_status_t status) { + camera3_buffer_status_t status, + bool output) { /** * Note that all fences are now owned by HAL. */ @@ -144,14 +154,25 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, buffer.status = status; // Inform tracker about becoming busy - if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG && + if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { + /** + * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers + * before/after register_stream_buffers during initial configuration + * or re-configuration. + * + * TODO: IN_CONFIG and IN_RECONFIG checks only make sense for <HAL3.2 + */ sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentActive(mStatusId); } } - mDequeuedBufferCount++; + mHandoutTotalBufferCount++; + + if (output) { + mHandoutOutputBufferCount++; + } } status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const { @@ -165,7 +186,7 @@ status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const { // Only limit dequeue amount when fully configured if (mState == STATE_CONFIGURED && - mDequeuedBufferCount == camera3_stream::max_buffers) { + mHandoutTotalBufferCount == camera3_stream::max_buffers) { ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous" " buffers (%d)", __FUNCTION__, mId, camera3_stream::max_buffers); @@ -183,7 +204,7 @@ status_t Camera3IOStreamBase::returnBufferPreconditionCheckLocked() const { __FUNCTION__, mId, mState); return INVALID_OPERATION; } - if (mDequeuedBufferCount == 0) { + if (mHandoutTotalBufferCount == 0) { ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__, mId); return INVALID_OPERATION; @@ -221,9 +242,20 @@ status_t Camera3IOStreamBase::returnAnyBufferLocked( mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); } - mDequeuedBufferCount--; - if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG && + if (output) { + mHandoutOutputBufferCount--; + } + + mHandoutTotalBufferCount--; + if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { + /** + * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers + * before/after register_stream_buffers during initial configuration + * or re-configuration. + * + * TODO: IN_CONFIG and IN_RECONFIG checks only make sense for <HAL3.2 + */ ALOGV("%s: Stream %d: All buffers returned; now idle", __FUNCTION__, mId); sp<StatusTracker> statusTracker = mStatusTracker.promote(); diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h index fcb9d04..a35c290 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h @@ -48,7 +48,10 @@ class Camera3IOStreamBase : protected: size_t mTotalBufferCount; // sum of input and output buffers that are currently acquired by HAL - size_t mDequeuedBufferCount; + size_t mHandoutTotalBufferCount; + // number of output buffers that are currently acquired by HAL. This will be + // Redundant when camera3 streams are no longer bidirectional streams. + size_t mHandoutOutputBufferCount; Condition mBufferReturnedSignal; uint32_t mFrameCount; // Last received output buffer's timestamp @@ -76,6 +79,10 @@ class Camera3IOStreamBase : virtual size_t getBufferCountLocked(); + virtual size_t getHandoutOutputBufferCountLocked(); + + virtual size_t getHandoutInputBufferCountLocked(); + virtual status_t getEndpointUsage(uint32_t *usage) = 0; status_t getBufferPreconditionCheckLocked() const; @@ -92,7 +99,8 @@ class Camera3IOStreamBase : buffer_handle_t *handle, int acquire_fence, int release_fence, - camera3_buffer_status_t status); + camera3_buffer_status_t status, + bool output); }; // class Camera3IOStreamBase diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp index 5aa9a3e..319be1d 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp @@ -81,7 +81,7 @@ status_t Camera3InputStream::getInputBufferLocked( * in which case we reassign it to acquire_fence */ handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, - /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false); mBuffersInFlight.push_back(bufferItem); return OK; @@ -199,14 +199,36 @@ status_t Camera3InputStream::configureQueueLocked() { assert(mMaxSize == 0); assert(camera3_stream::format != HAL_PIXEL_FORMAT_BLOB); - mTotalBufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS + - camera3_stream::max_buffers; - mDequeuedBufferCount = 0; + mHandoutTotalBufferCount = 0; mFrameCount = 0; if (mConsumer.get() == 0) { - sp<BufferQueue> bq = new BufferQueue(); - mConsumer = new BufferItemConsumer(bq, camera3_stream::usage, + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + int minUndequeuedBuffers = 0; + res = producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers); + if (res != OK || minUndequeuedBuffers < 0) { + ALOGE("%s: Stream %d: Could not query min undequeued buffers (error %d, bufCount %d)", + __FUNCTION__, mId, res, minUndequeuedBuffers); + return res; + } + size_t minBufs = static_cast<size_t>(minUndequeuedBuffers); + /* + * We promise never to 'acquire' more than camera3_stream::max_buffers + * at any one time. + * + * Boost the number up to meet the minimum required buffer count. + * + * (Note that this sets consumer-side buffer count only, + * and not the sum of producer+consumer side as in other camera streams). + */ + mTotalBufferCount = camera3_stream::max_buffers > minBufs ? + camera3_stream::max_buffers : minBufs; + // TODO: somehow set the total buffer count when producer connects? + + mConsumer = new BufferItemConsumer(consumer, camera3_stream::usage, mTotalBufferCount); mConsumer->setName(String8::format("Camera3-InputStream-%d", mId)); } diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h index 681d684..ae49467 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.h +++ b/services/camera/libcameraservice/device3/Camera3InputStream.h @@ -44,6 +44,8 @@ class Camera3InputStream : public Camera3IOStreamBase { virtual void dump(int fd, const Vector<String16> &args) const; + // TODO: expose an interface to get the IGraphicBufferProducer + private: typedef BufferItemConsumer::BufferItem BufferItem; diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 682755d..7ec649b 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -119,7 +119,7 @@ status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) { * in which case we reassign it to acquire_fence */ handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, - /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true); return OK; } @@ -324,7 +324,7 @@ status_t Camera3OutputStream::configureQueueLocked() { } mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers; - mDequeuedBufferCount = 0; + mHandoutTotalBufferCount = 0; mFrameCount = 0; mLastTimestamp = 0; diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 70406f1..abfb602 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -23,6 +23,8 @@ #include "device3/Camera3Stream.h" #include "device3/StatusTracker.h" +#include <cutils/properties.h> + namespace android { namespace camera3 { @@ -137,6 +139,7 @@ camera3_stream* Camera3Stream::startConfiguration() { if (mState == STATE_CONSTRUCTED) { mState = STATE_IN_CONFIG; } else { // mState == STATE_CONFIGURED + LOG_ALWAYS_FATAL_IF(mState != STATE_CONFIGURED, "Invalid state: 0x%x", mState); mState = STATE_IN_RECONFIG; } @@ -209,8 +212,30 @@ status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) { status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); + status_t res = OK; + + // This function should be only called when the stream is configured already. + if (mState != STATE_CONFIGURED) { + ALOGE("%s: Stream %d: Can't get buffers if stream is not in CONFIGURED state %d", + __FUNCTION__, mId, mState); + return INVALID_OPERATION; + } + + // Wait for new buffer returned back if we are running into the limit. + if (getHandoutOutputBufferCountLocked() == camera3_stream::max_buffers) { + ALOGV("%s: Already dequeued max output buffers (%d), wait for next returned one.", + __FUNCTION__, camera3_stream::max_buffers); + 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); + } + return res; + } + } - status_t res = getBufferLocked(buffer); + res = getBufferLocked(buffer); if (res == OK) { fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true); } @@ -223,9 +248,18 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, ATRACE_CALL(); Mutex::Autolock l(mLock); + /** + * TODO: Check that the state is valid first. + * + * <HAL3.2 IN_CONFIG and IN_RECONFIG in addition to CONFIGURED. + * >= HAL3.2 CONFIGURED only + * + * Do this for getBuffer as well. + */ status_t res = returnBufferLocked(buffer, timestamp); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true); + mOutputBufferReturnedSignal.signal(); } return res; @@ -234,8 +268,30 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); + status_t res = OK; + + // This function should be only called when the stream is configured already. + if (mState != STATE_CONFIGURED) { + ALOGE("%s: Stream %d: Can't get input buffers if stream is not in CONFIGURED state %d", + __FUNCTION__, mId, mState); + return INVALID_OPERATION; + } + + // Wait for new buffer returned back if we are running into the limit. + if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers) { + ALOGV("%s: Already dequeued max input buffers (%d), wait for next returned one.", + __FUNCTION__, camera3_stream::max_buffers); + res = mInputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration); + if (res != OK) { + if (res == TIMED_OUT) { + ALOGE("%s: wait for input buffer return timed out after %lldms", __FUNCTION__, + kWaitForBufferDuration / 1000000LL); + } + return res; + } + } - status_t res = getInputBufferLocked(buffer); + res = getInputBufferLocked(buffer); if (res == OK) { fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false); } @@ -250,6 +306,7 @@ status_t Camera3Stream::returnInputBuffer(const camera3_stream_buffer &buffer) { status_t res = returnInputBufferLocked(buffer); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false); + mInputBufferReturnedSignal.signal(); } return res; } @@ -314,12 +371,46 @@ status_t Camera3Stream::disconnect() { status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) { ATRACE_CALL(); + + /** + * >= CAMERA_DEVICE_API_VERSION_3_2: + * + * camera3_device_t->ops->register_stream_buffers() is not called and must + * be NULL. + */ + if (hal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_2) { + ALOGV("%s: register_stream_buffers unused as of HAL3.2", __FUNCTION__); + + /** + * Skip the NULL check if camera.dev.register_stream is 1. + * + * For development-validation purposes only. + * + * TODO: Remove the property check before shipping L (b/13914251). + */ + char value[PROPERTY_VALUE_MAX] = { '\0', }; + property_get("camera.dev.register_stream", value, "0"); + int propInt = atoi(value); + + if (propInt == 0 && hal3Device->ops->register_stream_buffers != NULL) { + ALOGE("%s: register_stream_buffers is deprecated in HAL3.2; " + "must be set to NULL in camera3_device::ops", __FUNCTION__); + return INVALID_OPERATION; + } else { + ALOGD("%s: Skipping NULL check for deprecated register_stream_buffers"); + } + + return OK; + } else { + ALOGV("%s: register_stream_buffers using deprecated code path", __FUNCTION__); + } + status_t res; size_t bufferCount = getBufferCountLocked(); Vector<buffer_handle_t*> buffers; - buffers.insertAt(NULL, 0, bufferCount); + buffers.insertAt(/*prototype_item*/NULL, /*index*/0, bufferCount); camera3_stream_buffer_set bufferSet = camera3_stream_buffer_set(); bufferSet.stream = this; @@ -327,7 +418,7 @@ status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) { bufferSet.buffers = buffers.editArray(); Vector<camera3_stream_buffer_t> streamBuffers; - streamBuffers.insertAt(camera3_stream_buffer_t(), 0, bufferCount); + streamBuffers.insertAt(camera3_stream_buffer_t(), /*index*/0, bufferCount); // Register all buffers with the HAL. This means getting all the buffers // from the stream, providing them to the HAL with the diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index 6eeb721..14f5387 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -82,6 +82,23 @@ namespace camera3 { * STATE_CONFIGURED => STATE_CONSTRUCTED: * When disconnect() is called after making sure stream is idle with * waitUntilIdle(). + * + * Status Tracking: + * Each stream is tracked by StatusTracker as a separate component, + * depending on the handed out buffer count. The state must be STATE_CONFIGURED + * in order for the component to be marked. + * + * It's marked in one of two ways: + * + * - ACTIVE: One or more buffers have been handed out (with #getBuffer). + * - IDLE: All buffers have been returned (with #returnBuffer), and their + * respective release_fence(s) have been signaled. + * + * A typical use case is output streams. When the HAL has any buffers + * dequeued, the stream is marked ACTIVE. When the HAL returns all buffers + * (e.g. if no capture requests are active), the stream is marked IDLE. + * In this use case, the app consumer does not affect the component status. + * */ class Camera3Stream : protected camera3_stream, @@ -262,6 +279,12 @@ class Camera3Stream : // Get the total number of buffers in the queue virtual size_t getBufferCountLocked() = 0; + // Get handout output buffer count. + virtual size_t getHandoutOutputBufferCountLocked() = 0; + + // Get handout input buffer count. + virtual size_t getHandoutInputBufferCountLocked() = 0; + // Get the usage flags for the other endpoint, or return // INVALID_OPERATION if they cannot be obtained. virtual status_t getEndpointUsage(uint32_t *usage) = 0; @@ -274,6 +297,9 @@ class Camera3Stream : private: uint32_t oldUsage; uint32_t oldMaxBuffers; + Condition mOutputBufferReturnedSignal; + Condition mInputBufferReturnedSignal; + static const nsecs_t kWaitForBufferDuration = 3000000000LL; // 3000 ms // Gets all buffers from endpoint and registers them with the HAL. status_t registerBuffersLocked(camera3_device *hal3Device); diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp index 44d8188..05b3d1f 100644 --- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp @@ -111,15 +111,17 @@ struct TimestampFinder : public RingBufferConsumer::RingBufferComparator { } // namespace anonymous Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height, - int depth) : + int bufferCount) : Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL, width, height, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), - mDepth(depth) { + mDepth(bufferCount) { - sp<BufferQueue> bq = new BufferQueue(); - mProducer = new RingBufferConsumer(bq, GRALLOC_USAGE_HW_CAMERA_ZSL, depth); - mConsumer = new Surface(bq); + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount); + mConsumer = new Surface(producer); } Camera3ZslStream::~Camera3ZslStream() { @@ -174,7 +176,7 @@ status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) { * in which case we reassign it to acquire_fence */ handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, - /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false); mBuffersInFlight.push_back(bufferItem); diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.h b/services/camera/libcameraservice/device3/Camera3ZslStream.h index c7f4490..6721832 100644 --- a/services/camera/libcameraservice/device3/Camera3ZslStream.h +++ b/services/camera/libcameraservice/device3/Camera3ZslStream.h @@ -37,10 +37,10 @@ class Camera3ZslStream : public Camera3OutputStream { public: /** - * Set up a ZSL stream of a given resolution. Depth is the number of buffers + * Set up a ZSL stream of a given resolution. bufferCount is the number of buffers * cached within the stream that can be retrieved for input. */ - Camera3ZslStream(int id, uint32_t width, uint32_t height, int depth); + Camera3ZslStream(int id, uint32_t width, uint32_t height, int bufferCount); ~Camera3ZslStream(); virtual void dump(int fd, const Vector<String16> &args) const; |