Merge cherrypicks of [3365569, 3365570, 3366860, 3366878, 3365571, 3365572, 3366918, 3365573, 3365589, 3365590, 3366938, 3366902, 3365574, 3365575, 3365576, 3365577, 3366958, 3365824, 3365591, 3366959, 3366960, 3366961, 3366962, 3366963, 3366964, 3366965, 3366919, 3366966, 3366967, 3366968, 3366969, 3366970, 3367018, 3367019, 3365592, 3365593, 3366985, 3365825, 3366988, 3366989, 3366990, 3366991, 3366992, 3366993, 3366994, 3367004, 3367005, 3367006, 3367007, 3367008, 3367009, 3367010, 3367011, 3367012, 3367013, 3367014, 3367015, 3367016, 3367017, 3367038, 3367039, 3367040, 3367041, 3367042, 3367044, 3367045, 3367046, 3367049, 3367050, 3367052, 3367053, 3367054, 3367055, 3367056, 3366920, 3366921, 3366922, 3367079] into oc-mr1-release
Change-Id: I10e3e1c9ba6057523c71ad89f8fdc9810de38571
diff --git a/msm8998/QCamera2/Android.mk b/msm8998/QCamera2/Android.mk
index e8a6811..184d9bc 100755
--- a/msm8998/QCamera2/Android.mk
+++ b/msm8998/QCamera2/Android.mk
@@ -30,6 +30,7 @@
#HAL 3.0 source
LOCAL_SRC_FILES += \
+ HAL3/QCamera3HdrPlusListenerThread.cpp \
HAL3/QCamera3HWI.cpp \
HAL3/QCamera3Mem.cpp \
HAL3/QCamera3Stream.cpp \
diff --git a/msm8998/QCamera2/HAL3/QCamera3Channel.cpp b/msm8998/QCamera2/HAL3/QCamera3Channel.cpp
index bb12822..cf9fe4a 100644
--- a/msm8998/QCamera2/HAL3/QCamera3Channel.cpp
+++ b/msm8998/QCamera2/HAL3/QCamera3Channel.cpp
@@ -4034,8 +4034,8 @@
const uint32_t *ldafCalib = hal_obj->getLdafCalib();
const char *easelFwVersion = hal_obj->getEaselFwVersion();
if ((eepromVersion && strlen(eepromVersion)) ||
- ldafCalib) {
- int len = 0;
+ ldafCalib || easelFwVersion) {
+ uint32_t len = 0;
settings->image_desc_valid = true;
if (eepromVersion && strlen(eepromVersion)) {
len = snprintf(settings->image_desc, sizeof(settings->image_desc),
@@ -4048,8 +4048,12 @@
}
if (easelFwVersion) {
ALOGD("%s: Easel FW version %s", __FUNCTION__, easelFwVersion);
+ if (len > 0 && len < sizeof(settings->image_desc)) {
+ settings->image_desc[len] = ',';
+ len++;
+ }
len += snprintf(settings->image_desc + len,
- sizeof(settings->image_desc) - len, ":%s", easelFwVersion);
+ sizeof(settings->image_desc) - len, "E-ver:%s", easelFwVersion);
}
}
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
index fe1fe8d..771d35b 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
@@ -147,6 +147,7 @@
// The following Easel related variables must be protected by gHdrPlusClientLock.
std::unique_ptr<EaselManagerClient> gEaselManagerClient;
bool EaselManagerClientOpened = false; // If gEaselManagerClient is opened.
+int32_t gActiveEaselClient = 0; // The number of active cameras on Easel.
std::unique_ptr<HdrPlusClient> gHdrPlusClient = nullptr;
bool gHdrPlusClientOpening = false; // If HDR+ client is being opened.
std::condition_variable gHdrPlusClientOpenCond; // Used to synchronize HDR+ client opening.
@@ -909,12 +910,24 @@
std::unique_lock<std::mutex> l(gHdrPlusClientLock);
if (gEaselManagerClient != nullptr && gEaselManagerClient->isEaselPresentOnDevice()) {
logEaselEvent("EASEL_STARTUP_LATENCY", "Resume");
- rc = gEaselManagerClient->resume(this);
- if (rc != 0) {
- ALOGE("%s: Resuming Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+ if (gActiveEaselClient == 0) {
+ rc = gEaselManagerClient->resume(this);
+ if (rc != 0) {
+ ALOGE("%s: Resuming Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+ return rc;
+ }
+ mEaselFwUpdated = false;
+ }
+
+ gActiveEaselClient++;
+
+ mQCamera3HdrPlusListenerThread = new QCamera3HdrPlusListenerThread(this);
+ rc = mQCamera3HdrPlusListenerThread->run("QCamera3HdrPlusListenerThread");
+ if (rc != OK) {
+ ALOGE("%s: Starting HDR+ client listener thread failed: %s (%d)", __FUNCTION__,
+ strerror(-rc), rc);
return rc;
}
- mEaselFwUpdated = false;
}
}
@@ -928,12 +941,19 @@
{
std::unique_lock<std::mutex> l(gHdrPlusClientLock);
if (gEaselManagerClient != nullptr && gEaselManagerClient->isEaselPresentOnDevice()) {
- status_t suspendErr = gEaselManagerClient->suspend();
- if (suspendErr != 0) {
- ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__,
- strerror(-suspendErr), suspendErr);
+ if (gActiveEaselClient == 1) {
+ status_t suspendErr = gEaselManagerClient->suspend();
+ if (suspendErr != 0) {
+ ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__,
+ strerror(-suspendErr), suspendErr);
+ }
}
+ gActiveEaselClient--;
}
+
+ mQCamera3HdrPlusListenerThread->requestExit();
+ mQCamera3HdrPlusListenerThread->join();
+ mQCamera3HdrPlusListenerThread = nullptr;
}
}
@@ -1124,11 +1144,18 @@
{
std::unique_lock<std::mutex> l(gHdrPlusClientLock);
if (EaselManagerClientOpened) {
- rc = gEaselManagerClient->suspend();
- if (rc != 0) {
- ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+ if (gActiveEaselClient == 1) {
+ rc = gEaselManagerClient->suspend();
+ if (rc != 0) {
+ ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
+ }
}
+ gActiveEaselClient--;
}
+
+ mQCamera3HdrPlusListenerThread->requestExit();
+ mQCamera3HdrPlusListenerThread->join();
+ mQCamera3HdrPlusListenerThread = nullptr;
}
return rc;
@@ -6430,6 +6457,7 @@
return rc;
}
}
+ mFirstPreviewIntentSeen = false;
}
pthread_mutex_unlock(&mMutex);
@@ -10918,7 +10946,7 @@
if (eepromLength + sizeof(easelInfo) < MAX_EEPROM_VERSION_INFO_LEN) {
eepromLength += sizeof(easelInfo);
strlcat(eepromInfo, ((gEaselManagerClient != nullptr &&
- gEaselManagerClient->isEaselPresentOnDevice()) ? ",E-ver" : ",E:N"),
+ gEaselManagerClient->isEaselPresentOnDevice()) ? ",E-Y" : ",E:N"),
MAX_EEPROM_VERSION_INFO_LEN);
}
staticInfo.update(NEXUS_EXPERIMENTAL_2017_EEPROM_VERSION_INFO,
@@ -11177,7 +11205,7 @@
ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__, strerror(-res), res);
}
- gEaselBypassOnly = !property_get_bool("persist.camera.hdrplus.enable", false);
+ gEaselBypassOnly = property_get_bool("persist.camera.hdrplus.disable", false);
gEaselProfilingEnabled = property_get_bool("persist.camera.hdrplus.profiling", false);
// Expose enableZsl key only when HDR+ mode is enabled.
@@ -15189,7 +15217,7 @@
return OK;
}
- status_t res = gEaselManagerClient->openHdrPlusClientAsync(this);
+ status_t res = gEaselManagerClient->openHdrPlusClientAsync(mQCamera3HdrPlusListenerThread.get());
if (res != OK) {
ALOGE("%s: Opening HDR+ client asynchronously failed: %s (%d)", __FUNCTION__,
strerror(-res), res);
@@ -15354,6 +15382,13 @@
void QCamera3HardwareInterface::handleEaselFatalError()
{
+ {
+ std::unique_lock<std::mutex> l(gHdrPlusClientLock);
+ if (gHdrPlusClient != nullptr) {
+ gHdrPlusClient->nofityEaselFatalError();
+ }
+ }
+
pthread_mutex_lock(&mMutex);
mState = ERROR;
pthread_mutex_unlock(&mMutex);
@@ -15765,25 +15800,20 @@
streamBuffer.acquire_fence = -1;
streamBuffer.release_fence = -1;
- streamBuffers.push_back(streamBuffer);
-
// Send out error buffer event.
camera3_notify_msg_t notify_msg = {};
notify_msg.type = CAMERA3_MSG_ERROR;
notify_msg.message.error.frame_number = pendingBuffers->frame_number;
- notify_msg.message.error.error_code = CAMERA3_MSG_ERROR_BUFFER;
+ notify_msg.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
notify_msg.message.error.error_stream = buffer.stream;
orchestrateNotify(¬ify_msg);
+ mOutputBufferDispatcher.markBufferReady(pendingBuffers->frame_number, streamBuffer);
}
- camera3_capture_result_t result = {};
- result.frame_number = pendingBuffers->frame_number;
- result.num_output_buffers = streamBuffers.size();
- result.output_buffers = &streamBuffers[0];
+ mShutterDispatcher.clear(pendingBuffers->frame_number);
- // Send out result with buffer errors.
- orchestrateResult(&result);
+
// Remove pending buffers.
mPendingBuffersMap.mPendingBuffersInRequest.erase(pendingBuffers);
@@ -15802,7 +15832,6 @@
pthread_mutex_unlock(&mMutex);
}
-
ShutterDispatcher::ShutterDispatcher(QCamera3HardwareInterface *parent) :
mParent(parent) {}
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.h b/msm8998/QCamera2/HAL3/QCamera3HWI.h
index 4eaf8a8..c10c724 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.h
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.h
@@ -47,6 +47,7 @@
#include "QCameraCommon.h"
#include "QCamera3VendorTags.h"
#include "QCameraDualCamSettings.h"
+#include "QCamera3HdrPlusListenerThread.h"
#include "EaselManagerClient.h"
#include "HdrPlusClient.h"
@@ -894,6 +895,9 @@
int32_t mSceneDistance;
std::future<void> mEaselErrorFuture;
+
+ // Thread to handle callbacks from HDR+ client. Protected by gHdrPlusClientLock.
+ sp<QCamera3HdrPlusListenerThread> mQCamera3HdrPlusListenerThread;
};
}; // namespace qcamera
diff --git a/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp
new file mode 100644
index 0000000..355d970
--- /dev/null
+++ b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QCamera3HdrPlusListenerThread.h"
+
+
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using namespace android;
+
+namespace qcamera {
+
+QCamera3HdrPlusListenerThread::QCamera3HdrPlusListenerThread(
+ HdrPlusClientListener *listener) : mListener(listener), mExitRequested(false),
+ mFatalError(false)
+{
+}
+
+QCamera3HdrPlusListenerThread::~QCamera3HdrPlusListenerThread()
+{
+ requestExit();
+}
+
+void QCamera3HdrPlusListenerThread::onOpened(std::unique_ptr<HdrPlusClient> client)
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ if (mClient != nullptr) {
+ ALOGW("%s: An old client exists and will be destroyed.", __FUNCTION__);
+ }
+ mClient = std::move(client);
+ mPendingCallbacks.push(CALLBACK_TYPE_OPENED);
+ mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onOpenFailed(status_t err)
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ if (mOpenError != OK) {
+ ALOGW("%s: An old open failure exists and will be ignored: %s (%d)", __FUNCTION__,
+ strerror(-mOpenError), mOpenError);
+ }
+ mOpenError = err;
+ mPendingCallbacks.push(CALLBACK_TYPE_OPENFAILED);
+ mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onFatalError()
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ if (mFatalError) {
+ ALOGW("%s: An old fatal failure exists.", __FUNCTION__);
+ }
+ mFatalError = true;
+ mPendingCallbacks.push(CALLBACK_TYPE_FATAL_ERROR);
+ mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onCaptureResult(pbcamera::CaptureResult *result,
+ const camera_metadata_t &resultMetadata)
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+
+ PendingResult pendingResult = {};
+ pendingResult.result = *result;
+ pendingResult.metadata = clone_camera_metadata(&resultMetadata);
+ pendingResult.isFailed = false;
+ mResults.push(pendingResult);
+
+ mPendingCallbacks.push(CALLBACK_TYPE_CAPTURE_RESULT);
+ mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onFailedCaptureResult(pbcamera::CaptureResult *failedResult)
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+
+ PendingResult result = {};
+ result.result = *failedResult;
+ result.metadata = nullptr;
+ result.isFailed = true;
+ mResults.push(result);
+
+ mPendingCallbacks.push(CALLBACK_TYPE_CAPTURE_RESULT);
+ mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onShutter(uint32_t requestId, int64_t apSensorTimestampNs)
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+
+ std::pair<uint32_t, int64_t> shutter(requestId, apSensorTimestampNs);
+ mShutters.push(shutter);
+
+ mPendingCallbacks.push(CALLBACK_TYPE_SHUTTER);
+ mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onNextCaptureReady(uint32_t requestId)
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ mNextCaptureReadyIds.push(requestId);
+
+ mPendingCallbacks.push(CALLBACK_TYPE_NEXT_CAPTURE_READY);
+ mCallbackCond.notify_one();
+
+}
+
+void QCamera3HdrPlusListenerThread::onPostview(uint32_t requestId,
+ std::unique_ptr<std::vector<uint8_t>> postview, uint32_t width, uint32_t height,
+ uint32_t stride, int32_t format)
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+
+ PendingPostview pendingPostview = {};
+ pendingPostview.requestId = requestId;
+ pendingPostview.postview = std::move(postview);
+ pendingPostview.width = width;
+ pendingPostview.height = height;
+ pendingPostview.stride = stride;
+ pendingPostview.format = format;
+ mPostviews.push(std::move(pendingPostview));
+
+ mPendingCallbacks.push(CALLBACK_TYPE_POSTVIEW);
+ mCallbackCond.notify_one();
+
+}
+
+void QCamera3HdrPlusListenerThread::requestExit()
+{
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ mExitRequested = true;
+ mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::handleFatalError()
+{
+ bool fatalError;
+ {
+ std::unique_lock<std::mutex> lock(mCallbackLock);
+ if (!mFatalError) {
+ ALOGW("%s: There is no fatal error.", __FUNCTION__);
+ return;
+ }
+
+ fatalError = mFatalError;
+ }
+
+ mListener->onFatalError();
+}
+
+void QCamera3HdrPlusListenerThread::handlePendingClient()
+{
+ std::unique_ptr<HdrPlusClient> client;
+ {
+ std::unique_lock<std::mutex> lock(mCallbackLock);
+ if (mClient == nullptr) {
+ ALOGW("%s: There is no pending client.", __FUNCTION__);
+ return;
+ }
+
+ client = std::move(mClient);
+ }
+
+ mListener->onOpened(std::move(client));
+}
+
+void QCamera3HdrPlusListenerThread::handleOpenError()
+{
+ status_t err = OK;
+ {
+ std::unique_lock<std::mutex> lock(mCallbackLock);
+ if (mOpenError == OK) {
+ ALOGW("%s: There is no pending open failure.", __FUNCTION__);
+ return;
+ }
+
+ err = mOpenError;
+ mOpenError = OK;
+ }
+
+ mListener->onOpenFailed(err);
+}
+
+void QCamera3HdrPlusListenerThread::handleNextCaptureReady()
+{
+ uint32_t requestId = 0;
+ {
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ if (mNextCaptureReadyIds.size() == 0) {
+ ALOGW("%s: There is no NextCaptureReady.", __FUNCTION__);
+ return;
+ }
+ requestId = mNextCaptureReadyIds.front();
+ mNextCaptureReadyIds.pop();
+ }
+ mListener->onNextCaptureReady(requestId);
+}
+
+void QCamera3HdrPlusListenerThread::handleCaptureResult()
+{
+ PendingResult result = {};
+ {
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ if (mResults.size() == 0) {
+ ALOGW("%s: There is no capture result.", __FUNCTION__);
+ return;
+ }
+ result = mResults.front();
+ mResults.pop();
+ }
+
+ if (result.isFailed) {
+ mListener->onFailedCaptureResult(&result.result);
+ } else {
+ mListener->onCaptureResult(&result.result, *result.metadata);
+ }
+}
+
+void QCamera3HdrPlusListenerThread::handleShutter()
+{
+ uint32_t requestId;
+ int64_t apSensorTimestampNs;
+
+ {
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ if (mShutters.size() == 0) {
+ ALOGW("%s: There is no shutter.", __FUNCTION__);
+ return;;
+ }
+
+ auto shutter = mShutters.front();
+ requestId = shutter.first;
+ apSensorTimestampNs = shutter.second;
+ mShutters.pop();
+ }
+
+ mListener->onShutter(requestId, apSensorTimestampNs);
+}
+
+void QCamera3HdrPlusListenerThread::handlePostview()
+{
+ PendingPostview postview = {};
+
+ {
+ std::unique_lock<std::mutex> l(mCallbackLock);
+ if (mPostviews.size() == 0) {
+ ALOGW("%s: There is no postview.", __FUNCTION__);
+ return;;
+ }
+
+ postview = std::move(mPostviews.front());
+ mPostviews.pop();
+ }
+
+ mListener->onPostview(postview.requestId, std::move(postview.postview), postview.width,
+ postview.height, postview.stride, postview.format);
+}
+
+bool QCamera3HdrPlusListenerThread::threadLoop()
+{
+ if (mListener == nullptr) {
+ ALOGE("%s: mListener is nullptr.", __FUNCTION__);
+ return false;
+ }
+
+ while (1) {
+ CallbackType nextCallback;
+
+ {
+ std::unique_lock<std::mutex> lock(mCallbackLock);
+ if (!mExitRequested && mPendingCallbacks.size() == 0) {
+ mCallbackCond.wait(lock,
+ [&] { return mExitRequested || mPendingCallbacks.size() > 0; });
+ }
+
+ if (mExitRequested) {
+ return false;
+ } else {
+ nextCallback = mPendingCallbacks.front();
+ mPendingCallbacks.pop();
+ }
+ }
+
+ switch (nextCallback) {
+ case CALLBACK_TYPE_OPENED:
+ handlePendingClient();
+ break;
+ case CALLBACK_TYPE_OPENFAILED:
+ handleOpenError();
+ break;
+ case CALLBACK_TYPE_FATAL_ERROR:
+ handleFatalError();
+ break;
+ case CALLBACK_TYPE_CAPTURE_RESULT:
+ handleCaptureResult();
+ break;
+ case CALLBACK_TYPE_SHUTTER:
+ handleShutter();
+ break;
+ case CALLBACK_TYPE_NEXT_CAPTURE_READY:
+ handleNextCaptureReady();
+ break;
+ case CALLBACK_TYPE_POSTVIEW:
+ handlePostview();
+ break;
+ default:
+ ALOGE("%s: Unknown callback type %d", __FUNCTION__, nextCallback);
+ break;
+ }
+ }
+
+ return false;
+}
+
+}; // namespace qcamera
diff --git a/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h
new file mode 100644
index 0000000..e64de36
--- /dev/null
+++ b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __HDRPLUSCLIENTLISTENERHANDLERTHREAD__
+#define __HDRPLUSCLIENTLISTENERHANDLERTHREAD__
+
+// System dependencies
+#include <utils/Thread.h>
+#include <queue>
+
+#include "EaselManagerClient.h"
+#include "HdrPlusClient.h"
+
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using namespace android;
+
+namespace qcamera {
+
+/*
+ * A thread to handle callbacks from HDR+ client. When a callback from HDR+ client is invoked,
+ * HDR+ client callback thread will return and the threadloop of QCamera3HdrPlusListenerThread
+ * will call the callback handlers in QCamera3HWI, to avoid deadlock in HDR+ client callback thread.
+ */
+class QCamera3HdrPlusListenerThread : public HdrPlusClientListener, public Thread
+{
+public:
+ // listener is an HdrPlusClientListener to forward the callbacks in the thread loop.
+ QCamera3HdrPlusListenerThread(HdrPlusClientListener *listener);
+ virtual ~QCamera3HdrPlusListenerThread();
+
+ // Request the thread to exit.
+ void requestExit() override;
+
+private:
+ // HDR+ client callbacks.
+ void onOpened(std::unique_ptr<HdrPlusClient> client) override;
+ void onOpenFailed(status_t err) override;
+ void onFatalError() override;
+ void onCaptureResult(pbcamera::CaptureResult *result,
+ const camera_metadata_t &resultMetadata) override;
+ void onFailedCaptureResult(pbcamera::CaptureResult *failedResult) override;
+ void onShutter(uint32_t requestId, int64_t apSensorTimestampNs) override;
+ void onNextCaptureReady(uint32_t requestId) override;
+ void onPostview(uint32_t requestId, std::unique_ptr<std::vector<uint8_t>> postview,
+ uint32_t width, uint32_t height, uint32_t stride, int32_t format) override;
+
+ bool threadLoop() override;
+
+ // The following functions handle the pending callbacks by calling the callback handlers
+ // in QCamera3HWI.
+ bool hasPendingEventsLocked();
+ void handlePendingClient();
+ void handleNextCaptureReady();
+ void handleCaptureResult();
+ void handleFatalError();
+ void handleOpenError();
+ void handleShutter();
+ void handlePostview();
+
+ struct PendingResult {
+ pbcamera::CaptureResult result;
+ camera_metadata_t *metadata;
+ bool isFailed;
+ };
+
+ struct PendingPostview {
+ uint32_t requestId;
+ std::unique_ptr<std::vector<uint8_t>> postview;
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ int32_t format;
+ };
+
+ enum CallbackType {
+ CALLBACK_TYPE_OPENED = 0,
+ CALLBACK_TYPE_OPENFAILED,
+ CALLBACK_TYPE_FATAL_ERROR,
+ CALLBACK_TYPE_CAPTURE_RESULT,
+ CALLBACK_TYPE_SHUTTER,
+ CALLBACK_TYPE_NEXT_CAPTURE_READY,
+ CALLBACK_TYPE_POSTVIEW,
+ };
+
+ HdrPlusClientListener *mListener;
+
+ std::mutex mCallbackLock;
+
+ // Condition for a new callback. Protected by mCallbackLock.
+ std::condition_variable mCallbackCond;
+ // If exit has been requested. Protected by mCallbackLock.
+ bool mExitRequested;
+
+ // The following variables store pending callbacks. Protected by mCallbackLock.
+ std::unique_ptr<HdrPlusClient> mClient;
+ std::queue<uint32_t> mNextCaptureReadyIds;
+ std::queue<PendingResult> mResults;
+ bool mFatalError;
+ status_t mOpenError;
+ std::queue<std::pair<uint32_t, int64_t>> mShutters;
+ std::queue<PendingPostview> mPostviews;
+
+ // A queue of pending callback types, in the same order as invoked by HDR+ client.
+ // Protected by mCallbackLock.
+ std::queue<CallbackType> mPendingCallbacks;
+};
+
+}; // namespace qcamera
+
+#endif /* __HDRPLUSCLIENTLISTENERHANDLERTHREAD__ */
\ No newline at end of file