Loading services/camera/libcameraservice/Camera3Device.cpp +331 −19 Original line number Diff line number Diff line Loading @@ -262,6 +262,8 @@ status_t Camera3Device::capture(CameraMetadata &request) { ATRACE_CALL(); Mutex::Autolock l(mLock); // TODO: take ownership of the request switch (mStatus) { case STATUS_ERROR: ALOGE("%s: Device has encountered a serious error", __FUNCTION__); Loading Loading @@ -363,10 +365,8 @@ status_t Camera3Device::clearStreamingRequest() { status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) { ATRACE_CALL(); (void)requestId; (void)timeout; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; return mRequestThread->waitUntilRequestProcessed(requestId, timeout); } status_t Camera3Device::createStream(sp<ANativeWindow> consumer, Loading Loading @@ -698,28 +698,62 @@ status_t Camera3Device::getNextFrame(CameraMetadata *frame) { status_t Camera3Device::triggerAutofocus(uint32_t id) { ATRACE_CALL(); (void)id; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id); // Mix-in this trigger into the next request and only the next request. RequestTrigger trigger[] = { { ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AF_TRIGGER_START }, { ANDROID_CONTROL_AF_TRIGGER_ID, static_cast<int32_t>(id) }, }; return mRequestThread->queueTrigger(trigger, sizeof(trigger)/sizeof(trigger[0])); } status_t Camera3Device::triggerCancelAutofocus(uint32_t id) { ATRACE_CALL(); (void)id; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; ALOGV("%s: Triggering cancel autofocus, id %d", __FUNCTION__, id); // Mix-in this trigger into the next request and only the next request. RequestTrigger trigger[] = { { ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AF_TRIGGER_CANCEL }, { ANDROID_CONTROL_AF_TRIGGER_ID, static_cast<int32_t>(id) }, }; return mRequestThread->queueTrigger(trigger, sizeof(trigger)/sizeof(trigger[0])); } status_t Camera3Device::triggerPrecaptureMetering(uint32_t id) { ATRACE_CALL(); (void)id; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id); // Mix-in this trigger into the next request and only the next request. RequestTrigger trigger[] = { { ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START }, { ANDROID_CONTROL_AE_PRECAPTURE_ID, static_cast<int32_t>(id) }, }; return mRequestThread->queueTrigger(trigger, sizeof(trigger)/sizeof(trigger[0])); } status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId, Loading Loading @@ -997,9 +1031,13 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { // Dispatch any 3A change events to listeners if (listener != NULL) { if (new3aState.aeState != cur3aState.aeState) { ALOGVV("%s: AE state changed from 0x%x to 0x%x", __FUNCTION__, cur3aState.aeState, new3aState.aeState); listener->notifyAutoExposure(new3aState.aeState, aeTriggerId); } if (new3aState.afState != cur3aState.afState) { ALOGVV("%s: AF state changed from 0x%x to 0x%x", __FUNCTION__, cur3aState.afState, new3aState.afState); listener->notifyAutoFocus(new3aState.afState, afTriggerId); } if (new3aState.awbState != cur3aState.awbState) { Loading Loading @@ -1059,7 +1097,8 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, mReconfigured(false), mDoPause(false), mPaused(true), mFrameNumber(0) { mFrameNumber(0), mLatestRequestId(NAME_NOT_FOUND) { } void Camera3Device::RequestThread::configurationComplete() { Loading @@ -1075,6 +1114,57 @@ status_t Camera3Device::RequestThread::queueRequest( return OK; } status_t Camera3Device::RequestThread::queueTrigger( RequestTrigger trigger[], size_t count) { Mutex::Autolock l(mTriggerMutex); status_t ret; for (size_t i = 0; i < count; ++i) { ret = queueTriggerLocked(trigger[i]); if (ret != OK) { return ret; } } return OK; } status_t Camera3Device::RequestThread::queueTriggerLocked( RequestTrigger trigger) { uint32_t tag = trigger.metadataTag; ssize_t index = mTriggerMap.indexOfKey(tag); switch (trigger.getTagType()) { case TYPE_BYTE: // fall-through case TYPE_INT32: break; default: ALOGE("%s: Type not supported: 0x%x", __FUNCTION__, trigger.getTagType()); return INVALID_OPERATION; } /** * Collect only the latest trigger, since we only have 1 field * in the request settings per trigger tag, and can't send more than 1 * trigger per request. */ if (index != NAME_NOT_FOUND) { mTriggerMap.editValueAt(index) = trigger; } else { mTriggerMap.add(tag, trigger); } return OK; } status_t Camera3Device::RequestThread::setRepeatingRequests( const RequestList &requests) { Mutex::Autolock l(mRequestLock); Loading Loading @@ -1108,6 +1198,24 @@ status_t Camera3Device::RequestThread::waitUntilPaused(nsecs_t timeout) { return OK; } status_t Camera3Device::RequestThread::waitUntilRequestProcessed( int32_t requestId, nsecs_t timeout) { Mutex::Autolock l(mLatestRequestMutex); status_t res; while (mLatestRequestId != requestId) { nsecs_t startTime = systemTime(); res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout); if (res != OK) return res; timeout -= (systemTime() - startTime); } return OK; } bool Camera3Device::RequestThread::threadLoop() { status_t res; Loading @@ -1125,16 +1233,55 @@ bool Camera3Device::RequestThread::threadLoop() { } // Create request to HAL camera3_capture_request_t request = camera3_capture_request_t(); Vector<camera3_stream_buffer_t> outputBuffers; if (mPrevRequest != nextRequest) { // Insert any queued triggers (before metadata is locked) int32_t triggerCount; res = insertTriggers(nextRequest); if (res < 0) { ALOGE("RequestThread: Unable to insert triggers " "(capture request %d, HAL device: %s (%d)", (mFrameNumber+1), strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } triggerCount = res; bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); // If the request is the same as last, or we had triggers last time if (mPrevRequest != nextRequest || triggersMixedIn) { /** * 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; } // else leave request.settings NULL to indicate 'reuse latest given' 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__, mFrameNumber+1, e.data.u8[0]); } } } else { // leave request.settings NULL to indicate 'reuse latest given' ALOGVV("%s: Request settings are REUSED", __FUNCTION__); } camera3_stream_buffer_t inputBuffer; Vector<camera3_stream_buffer_t> outputBuffers; // Fill in buffers Loading Loading @@ -1168,6 +1315,7 @@ bool Camera3Device::RequestThread::threadLoop() { request.frame_number = mFrameNumber++; // Submit request and block until ready for next one res = mHal3Device->ops->process_capture_request(mHal3Device, &request); Loading @@ -1181,6 +1329,35 @@ bool Camera3Device::RequestThread::threadLoop() { if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); } // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { ALOGE("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); return false; } mPrevTriggers = triggerCount; // Read android.request.id from the request settings metadata // - inform waitUntilRequestProcessed thread of a new request ID { Mutex::Autolock al(mLatestRequestMutex); camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { mLatestRequestId = requestIdEntry.data.i32[0]; } else { ALOGW("%s: Did not have android.request.id set in the request", __FUNCTION__); mLatestRequestId = NAME_NOT_FOUND; } mLatestRequestSignal.signal(); } return true; } Loading Loading @@ -1285,6 +1462,141 @@ bool Camera3Device::RequestThread::waitIfPaused() { return false; } status_t Camera3Device::RequestThread::insertTriggers( const sp<CaptureRequest> &request) { Mutex::Autolock al(mTriggerMutex); CameraMetadata &metadata = request->mSettings; size_t count = mTriggerMap.size(); for (size_t i = 0; i < count; ++i) { RequestTrigger trigger = mTriggerMap.valueAt(i); uint32_t tag = trigger.metadataTag; camera_metadata_entry entry = metadata.find(tag); if (entry.count > 0) { /** * Already has an entry for this trigger in the request. * Rewrite it with our requested trigger value. */ RequestTrigger oldTrigger = trigger; oldTrigger.entryValue = entry.data.u8[0]; mTriggerReplacedMap.add(tag, oldTrigger); } else { /** * More typical, no trigger entry, so we just add it */ mTriggerRemovedMap.add(tag, trigger); } status_t res; switch (trigger.getTagType()) { case TYPE_BYTE: { uint8_t entryValue = static_cast<uint8_t>(trigger.entryValue); res = metadata.update(tag, &entryValue, /*count*/1); break; } case TYPE_INT32: res = metadata.update(tag, &trigger.entryValue, /*count*/1); break; default: ALOGE("%s: Type not supported: 0x%x", __FUNCTION__, trigger.getTagType()); return INVALID_OPERATION; } if (res != OK) { ALOGE("%s: Failed to update request metadata with trigger tag %s" ", value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); return res; } ALOGV("%s: Mixed in trigger %s, value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); } mTriggerMap.clear(); return count; } status_t Camera3Device::RequestThread::removeTriggers( const sp<CaptureRequest> &request) { Mutex::Autolock al(mTriggerMutex); CameraMetadata &metadata = request->mSettings; /** * Replace all old entries with their old values. */ for (size_t i = 0; i < mTriggerReplacedMap.size(); ++i) { RequestTrigger trigger = mTriggerReplacedMap.valueAt(i); status_t res; uint32_t tag = trigger.metadataTag; switch (trigger.getTagType()) { case TYPE_BYTE: { uint8_t entryValue = static_cast<uint8_t>(trigger.entryValue); res = metadata.update(tag, &entryValue, /*count*/1); break; } case TYPE_INT32: res = metadata.update(tag, &trigger.entryValue, /*count*/1); break; default: ALOGE("%s: Type not supported: 0x%x", __FUNCTION__, trigger.getTagType()); return INVALID_OPERATION; } if (res != OK) { ALOGE("%s: Failed to restore request metadata with trigger tag %s" ", trigger value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); return res; } } mTriggerReplacedMap.clear(); /** * Remove all new entries. */ for (size_t i = 0; i < mTriggerRemovedMap.size(); ++i) { RequestTrigger trigger = mTriggerRemovedMap.valueAt(i); status_t res = metadata.erase(trigger.metadataTag); if (res != OK) { ALOGE("%s: Failed to erase metadata with trigger tag %s" ", trigger value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); return res; } } mTriggerRemovedMap.clear(); return OK; } /** * Static callback forwarding methods from HAL to instance */ Loading services/camera/libcameraservice/Camera3Device.h +54 −1 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ class Camera3Device : private: static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec struct RequestTrigger; Mutex mLock; Loading Loading @@ -172,6 +172,23 @@ class Camera3Device : */ status_t configureStreamsLocked(); struct RequestTrigger { // Metadata tag number, e.g. android.control.aePrecaptureTrigger uint32_t metadataTag; // Metadata value, e.g. 'START' or the trigger ID int32_t entryValue; // The last part of the fully qualified path, e.g. afTrigger const char *getTagName() const { return get_camera_metadata_tag_name(metadataTag) ?: "NULL"; } // e.g. TYPE_BYTE, TYPE_INT32, etc. int getTagType() const { return get_camera_metadata_tag_type(metadataTag); } }; /** * Thread for managing capture request submission to HAL device. */ Loading @@ -197,6 +214,14 @@ class Camera3Device : status_t queueRequest(sp<CaptureRequest> request); /** * 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. * Subsequent requests will not be rewritten (for this tag). */ status_t queueTrigger(RequestTrigger trigger[], size_t count); /** * Pause/unpause the capture thread. Doesn't block, so use * waitUntilPaused to wait until the thread is paused. Loading @@ -210,11 +235,27 @@ class Camera3Device : */ status_t waitUntilPaused(nsecs_t timeout); /** * Wait until thread processes the capture request with settings' * android.request.id == requestId. * * Returns TIMED_OUT in case the thread does not process the request * within the timeout. */ status_t waitUntilRequestProcessed(int32_t requestId, nsecs_t timeout); protected: virtual bool threadLoop(); private: status_t queueTriggerLocked(RequestTrigger trigger); // Mix-in queued triggers into this request int32_t insertTriggers(const sp<CaptureRequest> &request); // Purge the queued triggers from this request, // restoring the old field values for those tags. status_t removeTriggers(const sp<CaptureRequest> &request); static const nsecs_t kRequestTimeout = 50e6; // 50 ms // Waits for a request, or returns NULL if times out. Loading Loading @@ -249,8 +290,20 @@ class Camera3Device : Condition mPausedSignal; sp<CaptureRequest> mPrevRequest; int32_t mPrevTriggers; int32_t mFrameNumber; Mutex mLatestRequestMutex; Condition mLatestRequestSignal; // android.request.id for latest process_capture_request int32_t mLatestRequestId; typedef KeyedVector<uint32_t/*tag*/, RequestTrigger> TriggerMap; Mutex mTriggerMutex; TriggerMap mTriggerMap; TriggerMap mTriggerRemovedMap; TriggerMap mTriggerReplacedMap; }; sp<RequestThread> mRequestThread; Loading services/camera/libcameraservice/camera2/CaptureSequencer.cpp +28 −1 Original line number Diff line number Diff line Loading @@ -270,6 +270,9 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c processor->clearZslQueue(); } /** * Fire the jpegCallback in Camera#takePicture(..., jpegCallback) */ if (mCaptureBuffer != 0 && res == OK) { Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks); Loading Loading @@ -367,6 +370,8 @@ CaptureSequencer::CaptureState CaptureSequencer::manageZslReprocessing( CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart( sp<Camera2Client> &client) { ATRACE_CALL(); // Get the onFrameAvailable callback when the requestID == mCaptureId client->registerFrameListener(mCaptureId, mCaptureId + 1, this); { Loading Loading @@ -426,6 +431,13 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( SharedParameters::Lock l(client->getParameters()); Vector<uint8_t> outputStreams; /** * Set up output streams in the request * - preview * - capture/jpeg * - callback (if preview callbacks enabled) * - recording (if recording enabled) */ outputStreams.push(client->getPreviewStreamId()); outputStreams.push(client->getCaptureStreamId()); Loading Loading @@ -454,6 +466,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( return DONE; } // Create a capture copy since CameraDeviceBase#capture takes ownership CameraMetadata captureCopy = mCaptureRequest; if (captureCopy.entryCount() == 0) { ALOGE("%s: Camera %d: Unable to copy capture request for HAL device", Loading @@ -461,7 +474,12 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( return DONE; } /** * Clear the streaming request for still-capture pictures * (as opposed to i.e. video snapshots) */ if (l.mParameters.state == Parameters::STILL_CAPTURE) { // API definition of takePicture() - stop preview before taking pic res = client->stopStream(); if (res != OK) { ALOGE("%s: Camera %d: Unable to stop preview for still capture: " Loading @@ -488,6 +506,8 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( status_t res; ATRACE_CALL(); Mutex::Autolock l(mInputMutex); // Wait for new metadata result (mNewFrame) while (!mNewFrameReceived) { res = mNewFrameSignal.waitRelative(mInputMutex, kWaitDuration); if (res == TIMED_OUT) { Loading @@ -495,12 +515,17 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( break; } } // Approximation of the shutter being closed // - TODO: use the hal3 exposure callback in Camera3Device instead if (mNewFrameReceived && !mShutterNotified) { SharedParameters::Lock l(client->getParameters()); /* warning: this also locks a SharedCameraCallbacks */ shutterNotifyLocked(l.mParameters, client, mMsgType); mShutterNotified = true; } // Wait until jpeg was captured by JpegProcessor while (mNewFrameReceived && !mNewCaptureReceived) { res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration); if (res == TIMED_OUT) { Loading @@ -524,7 +549,9 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( } if (entry.data.i64[0] != mCaptureTimestamp) { ALOGW("Mismatched capture timestamps: Metadata frame %lld," " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp); " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp); } client->removeFrameListener(mCaptureId, mCaptureId + 1, this); Loading services/camera/libcameraservice/camera2/JpegProcessor.h +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ class JpegProcessor: JpegProcessor(wp<Camera2Client> client, wp<CaptureSequencer> sequencer); ~JpegProcessor(); // CpuConsumer listener implementation void onFrameAvailable(); status_t updateStream(const Parameters ¶ms); Loading Loading
services/camera/libcameraservice/Camera3Device.cpp +331 −19 Original line number Diff line number Diff line Loading @@ -262,6 +262,8 @@ status_t Camera3Device::capture(CameraMetadata &request) { ATRACE_CALL(); Mutex::Autolock l(mLock); // TODO: take ownership of the request switch (mStatus) { case STATUS_ERROR: ALOGE("%s: Device has encountered a serious error", __FUNCTION__); Loading Loading @@ -363,10 +365,8 @@ status_t Camera3Device::clearStreamingRequest() { status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) { ATRACE_CALL(); (void)requestId; (void)timeout; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; return mRequestThread->waitUntilRequestProcessed(requestId, timeout); } status_t Camera3Device::createStream(sp<ANativeWindow> consumer, Loading Loading @@ -698,28 +698,62 @@ status_t Camera3Device::getNextFrame(CameraMetadata *frame) { status_t Camera3Device::triggerAutofocus(uint32_t id) { ATRACE_CALL(); (void)id; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id); // Mix-in this trigger into the next request and only the next request. RequestTrigger trigger[] = { { ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AF_TRIGGER_START }, { ANDROID_CONTROL_AF_TRIGGER_ID, static_cast<int32_t>(id) }, }; return mRequestThread->queueTrigger(trigger, sizeof(trigger)/sizeof(trigger[0])); } status_t Camera3Device::triggerCancelAutofocus(uint32_t id) { ATRACE_CALL(); (void)id; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; ALOGV("%s: Triggering cancel autofocus, id %d", __FUNCTION__, id); // Mix-in this trigger into the next request and only the next request. RequestTrigger trigger[] = { { ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AF_TRIGGER_CANCEL }, { ANDROID_CONTROL_AF_TRIGGER_ID, static_cast<int32_t>(id) }, }; return mRequestThread->queueTrigger(trigger, sizeof(trigger)/sizeof(trigger[0])); } status_t Camera3Device::triggerPrecaptureMetering(uint32_t id) { ATRACE_CALL(); (void)id; ALOGE("%s: Unimplemented", __FUNCTION__); return INVALID_OPERATION; ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id); // Mix-in this trigger into the next request and only the next request. RequestTrigger trigger[] = { { ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START }, { ANDROID_CONTROL_AE_PRECAPTURE_ID, static_cast<int32_t>(id) }, }; return mRequestThread->queueTrigger(trigger, sizeof(trigger)/sizeof(trigger[0])); } status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId, Loading Loading @@ -997,9 +1031,13 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { // Dispatch any 3A change events to listeners if (listener != NULL) { if (new3aState.aeState != cur3aState.aeState) { ALOGVV("%s: AE state changed from 0x%x to 0x%x", __FUNCTION__, cur3aState.aeState, new3aState.aeState); listener->notifyAutoExposure(new3aState.aeState, aeTriggerId); } if (new3aState.afState != cur3aState.afState) { ALOGVV("%s: AF state changed from 0x%x to 0x%x", __FUNCTION__, cur3aState.afState, new3aState.afState); listener->notifyAutoFocus(new3aState.afState, afTriggerId); } if (new3aState.awbState != cur3aState.awbState) { Loading Loading @@ -1059,7 +1097,8 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, mReconfigured(false), mDoPause(false), mPaused(true), mFrameNumber(0) { mFrameNumber(0), mLatestRequestId(NAME_NOT_FOUND) { } void Camera3Device::RequestThread::configurationComplete() { Loading @@ -1075,6 +1114,57 @@ status_t Camera3Device::RequestThread::queueRequest( return OK; } status_t Camera3Device::RequestThread::queueTrigger( RequestTrigger trigger[], size_t count) { Mutex::Autolock l(mTriggerMutex); status_t ret; for (size_t i = 0; i < count; ++i) { ret = queueTriggerLocked(trigger[i]); if (ret != OK) { return ret; } } return OK; } status_t Camera3Device::RequestThread::queueTriggerLocked( RequestTrigger trigger) { uint32_t tag = trigger.metadataTag; ssize_t index = mTriggerMap.indexOfKey(tag); switch (trigger.getTagType()) { case TYPE_BYTE: // fall-through case TYPE_INT32: break; default: ALOGE("%s: Type not supported: 0x%x", __FUNCTION__, trigger.getTagType()); return INVALID_OPERATION; } /** * Collect only the latest trigger, since we only have 1 field * in the request settings per trigger tag, and can't send more than 1 * trigger per request. */ if (index != NAME_NOT_FOUND) { mTriggerMap.editValueAt(index) = trigger; } else { mTriggerMap.add(tag, trigger); } return OK; } status_t Camera3Device::RequestThread::setRepeatingRequests( const RequestList &requests) { Mutex::Autolock l(mRequestLock); Loading Loading @@ -1108,6 +1198,24 @@ status_t Camera3Device::RequestThread::waitUntilPaused(nsecs_t timeout) { return OK; } status_t Camera3Device::RequestThread::waitUntilRequestProcessed( int32_t requestId, nsecs_t timeout) { Mutex::Autolock l(mLatestRequestMutex); status_t res; while (mLatestRequestId != requestId) { nsecs_t startTime = systemTime(); res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout); if (res != OK) return res; timeout -= (systemTime() - startTime); } return OK; } bool Camera3Device::RequestThread::threadLoop() { status_t res; Loading @@ -1125,16 +1233,55 @@ bool Camera3Device::RequestThread::threadLoop() { } // Create request to HAL camera3_capture_request_t request = camera3_capture_request_t(); Vector<camera3_stream_buffer_t> outputBuffers; if (mPrevRequest != nextRequest) { // Insert any queued triggers (before metadata is locked) int32_t triggerCount; res = insertTriggers(nextRequest); if (res < 0) { ALOGE("RequestThread: Unable to insert triggers " "(capture request %d, HAL device: %s (%d)", (mFrameNumber+1), strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } triggerCount = res; bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); // If the request is the same as last, or we had triggers last time if (mPrevRequest != nextRequest || triggersMixedIn) { /** * 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; } // else leave request.settings NULL to indicate 'reuse latest given' 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__, mFrameNumber+1, e.data.u8[0]); } } } else { // leave request.settings NULL to indicate 'reuse latest given' ALOGVV("%s: Request settings are REUSED", __FUNCTION__); } camera3_stream_buffer_t inputBuffer; Vector<camera3_stream_buffer_t> outputBuffers; // Fill in buffers Loading Loading @@ -1168,6 +1315,7 @@ bool Camera3Device::RequestThread::threadLoop() { request.frame_number = mFrameNumber++; // Submit request and block until ready for next one res = mHal3Device->ops->process_capture_request(mHal3Device, &request); Loading @@ -1181,6 +1329,35 @@ bool Camera3Device::RequestThread::threadLoop() { if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); } // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { ALOGE("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); return false; } mPrevTriggers = triggerCount; // Read android.request.id from the request settings metadata // - inform waitUntilRequestProcessed thread of a new request ID { Mutex::Autolock al(mLatestRequestMutex); camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { mLatestRequestId = requestIdEntry.data.i32[0]; } else { ALOGW("%s: Did not have android.request.id set in the request", __FUNCTION__); mLatestRequestId = NAME_NOT_FOUND; } mLatestRequestSignal.signal(); } return true; } Loading Loading @@ -1285,6 +1462,141 @@ bool Camera3Device::RequestThread::waitIfPaused() { return false; } status_t Camera3Device::RequestThread::insertTriggers( const sp<CaptureRequest> &request) { Mutex::Autolock al(mTriggerMutex); CameraMetadata &metadata = request->mSettings; size_t count = mTriggerMap.size(); for (size_t i = 0; i < count; ++i) { RequestTrigger trigger = mTriggerMap.valueAt(i); uint32_t tag = trigger.metadataTag; camera_metadata_entry entry = metadata.find(tag); if (entry.count > 0) { /** * Already has an entry for this trigger in the request. * Rewrite it with our requested trigger value. */ RequestTrigger oldTrigger = trigger; oldTrigger.entryValue = entry.data.u8[0]; mTriggerReplacedMap.add(tag, oldTrigger); } else { /** * More typical, no trigger entry, so we just add it */ mTriggerRemovedMap.add(tag, trigger); } status_t res; switch (trigger.getTagType()) { case TYPE_BYTE: { uint8_t entryValue = static_cast<uint8_t>(trigger.entryValue); res = metadata.update(tag, &entryValue, /*count*/1); break; } case TYPE_INT32: res = metadata.update(tag, &trigger.entryValue, /*count*/1); break; default: ALOGE("%s: Type not supported: 0x%x", __FUNCTION__, trigger.getTagType()); return INVALID_OPERATION; } if (res != OK) { ALOGE("%s: Failed to update request metadata with trigger tag %s" ", value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); return res; } ALOGV("%s: Mixed in trigger %s, value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); } mTriggerMap.clear(); return count; } status_t Camera3Device::RequestThread::removeTriggers( const sp<CaptureRequest> &request) { Mutex::Autolock al(mTriggerMutex); CameraMetadata &metadata = request->mSettings; /** * Replace all old entries with their old values. */ for (size_t i = 0; i < mTriggerReplacedMap.size(); ++i) { RequestTrigger trigger = mTriggerReplacedMap.valueAt(i); status_t res; uint32_t tag = trigger.metadataTag; switch (trigger.getTagType()) { case TYPE_BYTE: { uint8_t entryValue = static_cast<uint8_t>(trigger.entryValue); res = metadata.update(tag, &entryValue, /*count*/1); break; } case TYPE_INT32: res = metadata.update(tag, &trigger.entryValue, /*count*/1); break; default: ALOGE("%s: Type not supported: 0x%x", __FUNCTION__, trigger.getTagType()); return INVALID_OPERATION; } if (res != OK) { ALOGE("%s: Failed to restore request metadata with trigger tag %s" ", trigger value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); return res; } } mTriggerReplacedMap.clear(); /** * Remove all new entries. */ for (size_t i = 0; i < mTriggerRemovedMap.size(); ++i) { RequestTrigger trigger = mTriggerRemovedMap.valueAt(i); status_t res = metadata.erase(trigger.metadataTag); if (res != OK) { ALOGE("%s: Failed to erase metadata with trigger tag %s" ", trigger value %d", __FUNCTION__, trigger.getTagName(), trigger.entryValue); return res; } } mTriggerRemovedMap.clear(); return OK; } /** * Static callback forwarding methods from HAL to instance */ Loading
services/camera/libcameraservice/Camera3Device.h +54 −1 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ class Camera3Device : private: static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec struct RequestTrigger; Mutex mLock; Loading Loading @@ -172,6 +172,23 @@ class Camera3Device : */ status_t configureStreamsLocked(); struct RequestTrigger { // Metadata tag number, e.g. android.control.aePrecaptureTrigger uint32_t metadataTag; // Metadata value, e.g. 'START' or the trigger ID int32_t entryValue; // The last part of the fully qualified path, e.g. afTrigger const char *getTagName() const { return get_camera_metadata_tag_name(metadataTag) ?: "NULL"; } // e.g. TYPE_BYTE, TYPE_INT32, etc. int getTagType() const { return get_camera_metadata_tag_type(metadataTag); } }; /** * Thread for managing capture request submission to HAL device. */ Loading @@ -197,6 +214,14 @@ class Camera3Device : status_t queueRequest(sp<CaptureRequest> request); /** * 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. * Subsequent requests will not be rewritten (for this tag). */ status_t queueTrigger(RequestTrigger trigger[], size_t count); /** * Pause/unpause the capture thread. Doesn't block, so use * waitUntilPaused to wait until the thread is paused. Loading @@ -210,11 +235,27 @@ class Camera3Device : */ status_t waitUntilPaused(nsecs_t timeout); /** * Wait until thread processes the capture request with settings' * android.request.id == requestId. * * Returns TIMED_OUT in case the thread does not process the request * within the timeout. */ status_t waitUntilRequestProcessed(int32_t requestId, nsecs_t timeout); protected: virtual bool threadLoop(); private: status_t queueTriggerLocked(RequestTrigger trigger); // Mix-in queued triggers into this request int32_t insertTriggers(const sp<CaptureRequest> &request); // Purge the queued triggers from this request, // restoring the old field values for those tags. status_t removeTriggers(const sp<CaptureRequest> &request); static const nsecs_t kRequestTimeout = 50e6; // 50 ms // Waits for a request, or returns NULL if times out. Loading Loading @@ -249,8 +290,20 @@ class Camera3Device : Condition mPausedSignal; sp<CaptureRequest> mPrevRequest; int32_t mPrevTriggers; int32_t mFrameNumber; Mutex mLatestRequestMutex; Condition mLatestRequestSignal; // android.request.id for latest process_capture_request int32_t mLatestRequestId; typedef KeyedVector<uint32_t/*tag*/, RequestTrigger> TriggerMap; Mutex mTriggerMutex; TriggerMap mTriggerMap; TriggerMap mTriggerRemovedMap; TriggerMap mTriggerReplacedMap; }; sp<RequestThread> mRequestThread; Loading
services/camera/libcameraservice/camera2/CaptureSequencer.cpp +28 −1 Original line number Diff line number Diff line Loading @@ -270,6 +270,9 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c processor->clearZslQueue(); } /** * Fire the jpegCallback in Camera#takePicture(..., jpegCallback) */ if (mCaptureBuffer != 0 && res == OK) { Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks); Loading Loading @@ -367,6 +370,8 @@ CaptureSequencer::CaptureState CaptureSequencer::manageZslReprocessing( CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart( sp<Camera2Client> &client) { ATRACE_CALL(); // Get the onFrameAvailable callback when the requestID == mCaptureId client->registerFrameListener(mCaptureId, mCaptureId + 1, this); { Loading Loading @@ -426,6 +431,13 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( SharedParameters::Lock l(client->getParameters()); Vector<uint8_t> outputStreams; /** * Set up output streams in the request * - preview * - capture/jpeg * - callback (if preview callbacks enabled) * - recording (if recording enabled) */ outputStreams.push(client->getPreviewStreamId()); outputStreams.push(client->getCaptureStreamId()); Loading Loading @@ -454,6 +466,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( return DONE; } // Create a capture copy since CameraDeviceBase#capture takes ownership CameraMetadata captureCopy = mCaptureRequest; if (captureCopy.entryCount() == 0) { ALOGE("%s: Camera %d: Unable to copy capture request for HAL device", Loading @@ -461,7 +474,12 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( return DONE; } /** * Clear the streaming request for still-capture pictures * (as opposed to i.e. video snapshots) */ if (l.mParameters.state == Parameters::STILL_CAPTURE) { // API definition of takePicture() - stop preview before taking pic res = client->stopStream(); if (res != OK) { ALOGE("%s: Camera %d: Unable to stop preview for still capture: " Loading @@ -488,6 +506,8 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( status_t res; ATRACE_CALL(); Mutex::Autolock l(mInputMutex); // Wait for new metadata result (mNewFrame) while (!mNewFrameReceived) { res = mNewFrameSignal.waitRelative(mInputMutex, kWaitDuration); if (res == TIMED_OUT) { Loading @@ -495,12 +515,17 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( break; } } // Approximation of the shutter being closed // - TODO: use the hal3 exposure callback in Camera3Device instead if (mNewFrameReceived && !mShutterNotified) { SharedParameters::Lock l(client->getParameters()); /* warning: this also locks a SharedCameraCallbacks */ shutterNotifyLocked(l.mParameters, client, mMsgType); mShutterNotified = true; } // Wait until jpeg was captured by JpegProcessor while (mNewFrameReceived && !mNewCaptureReceived) { res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration); if (res == TIMED_OUT) { Loading @@ -524,7 +549,9 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( } if (entry.data.i64[0] != mCaptureTimestamp) { ALOGW("Mismatched capture timestamps: Metadata frame %lld," " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp); " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp); } client->removeFrameListener(mCaptureId, mCaptureId + 1, this); Loading
services/camera/libcameraservice/camera2/JpegProcessor.h +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ class JpegProcessor: JpegProcessor(wp<Camera2Client> client, wp<CaptureSequencer> sequencer); ~JpegProcessor(); // CpuConsumer listener implementation void onFrameAvailable(); status_t updateStream(const Parameters ¶ms); Loading