Merge "Add fuzzer for EVS HAL"
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index f58a599..3e8b715 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -24,24 +24,6 @@
"liblog",
"libutils",
"libhardware",
- "android.hardware.audio@2.0",
- "android.hardware.audio@4.0",
- "android.hardware.audio@5.0",
- "android.hardware.audio@6.0",
- "android.hardware.audio.common@2.0",
- "android.hardware.audio.common@4.0",
- "android.hardware.audio.common@5.0",
- "android.hardware.audio.common@6.0",
- "android.hardware.audio.effect@2.0",
- "android.hardware.audio.effect@4.0",
- "android.hardware.audio.effect@5.0",
- "android.hardware.audio.effect@6.0",
- "android.hardware.bluetooth.a2dp@1.0",
- "android.hardware.bluetooth.audio@2.0",
- "android.hardware.soundtrigger@2.0",
- "android.hardware.soundtrigger@2.1",
- "android.hardware.soundtrigger@2.2",
- "android.hardware.soundtrigger@2.3",
],
}
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 00bcb19..8fa4918 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -16,20 +16,9 @@
#define LOG_TAG "audiohalservice"
-#include <android/hardware/audio/2.0/IDevicesFactory.h>
-#include <android/hardware/audio/4.0/IDevicesFactory.h>
-#include <android/hardware/audio/5.0/IDevicesFactory.h>
-#include <android/hardware/audio/6.0/IDevicesFactory.h>
-#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/6.0/IEffectsFactory.h>
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
-#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
-#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
+#include <string>
+#include <vector>
+
#include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
@@ -39,13 +28,20 @@
using namespace android::hardware;
using android::OK;
+using InterfacesList = std::vector<std::string>;
+
/** Try to register the provided factories in the provided order.
* If any registers successfully, do not register any other and return true.
* If all fail, return false.
*/
-template <class... Factories>
-bool registerPassthroughServiceImplementations() {
- return ((registerPassthroughServiceImplementation<Factories>() != OK) && ...);
+template <class Iter>
+static bool registerPassthroughServiceImplementations(Iter first, Iter last) {
+ for (; first != last; ++first) {
+ if (registerPassthroughServiceImplementation(*first) == OK) {
+ return true;
+ }
+ }
+ return false;
}
int main(int /* argc */, char* /* argv */ []) {
@@ -62,36 +58,58 @@
}
configureRpcThreadpool(16, true /*callerWillJoin*/);
- // Keep versions on a separate line for easier parsing
+ // Automatic formatting tries to compact the lines, making them less readable
// clang-format off
- LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
- audio::V6_0::IDevicesFactory,
- audio::V5_0::IDevicesFactory,
- audio::V4_0::IDevicesFactory,
- audio::V2_0::IDevicesFactory>()),
- "Could not register audio core API");
+ const std::vector<InterfacesList> mandatoryInterfaces = {
+ {
+ "Audio Core API",
+ "android.hardware.audio@6.0::IDevicesFactory",
+ "android.hardware.audio@5.0::IDevicesFactory",
+ "android.hardware.audio@4.0::IDevicesFactory",
+ "android.hardware.audio@2.0::IDevicesFactory"
+ },
+ {
+ "Audio Effect API",
+ "android.hardware.audio.effect@6.0::IEffectsFactory",
+ "android.hardware.audio.effect@5.0::IEffectsFactory",
+ "android.hardware.audio.effect@4.0::IEffectsFactory",
+ "android.hardware.audio.effect@2.0::IEffectsFactory",
+ }
+ };
- LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
- audio::effect::V6_0::IEffectsFactory,
- audio::effect::V5_0::IEffectsFactory,
- audio::effect::V4_0::IEffectsFactory,
- audio::effect::V2_0::IEffectsFactory>()),
- "Could not register audio effect API");
+ const std::vector<InterfacesList> optionalInterfaces = {
+ {
+ "Soundtrigger API",
+ "android.hardware.soundtrigger@2.3::ISoundTriggerHw",
+ "android.hardware.soundtrigger@2.2::ISoundTriggerHw",
+ "android.hardware.soundtrigger@2.1::ISoundTriggerHw",
+ "android.hardware.soundtrigger@2.0::ISoundTriggerHw",
+ },
+ {
+ "Bluetooth Audio API",
+ "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory"
+ },
+ // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
+ {
+ "Bluetooth Audio Offload API",
+ "android.hardware.a2dp@1.0::IBluetoothAudioOffload"
+ }
+ };
// clang-format on
- ALOGW_IF((registerPassthroughServiceImplementations<
- soundtrigger::V2_3::ISoundTriggerHw, soundtrigger::V2_2::ISoundTriggerHw,
- soundtrigger::V2_1::ISoundTriggerHw, soundtrigger::V2_0::ISoundTriggerHw>()),
- "Could not register soundtrigger API");
+ for (const auto& listIter : mandatoryInterfaces) {
+ auto iter = listIter.begin();
+ const std::string& interfaceFamilyName = *iter++;
+ LOG_ALWAYS_FATAL_IF(!registerPassthroughServiceImplementations(iter, listIter.end()),
+ "Could not register %s", interfaceFamilyName.c_str());
+ }
- ALOGW_IF(registerPassthroughServiceImplementations<
- bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(),
- "Could not register Bluetooth audio API");
-
- // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
- ALOGW_IF(registerPassthroughServiceImplementations<
- bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(),
- "Could not register Bluetooth audio offload API");
+ for (const auto& listIter : optionalInterfaces) {
+ auto iter = listIter.begin();
+ const std::string& interfaceFamilyName = *iter++;
+ ALOGW_IF(!registerPassthroughServiceImplementations(iter, listIter.end()),
+ "Could not register %s", interfaceFamilyName.c_str());
+ }
joinRpcThreadpool();
}
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
index 1695821..7752b0e 100644
--- a/automotive/evs/1.1/IEvsEnumerator.hal
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -47,4 +47,11 @@
* configured differently by another client.
*/
openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+
+ /**
+ * Tells whether this is EVS manager or HAL implementation.
+ *
+ * @return result False for EVS manager implementations and true for all others.
+ */
+ isHardware() generates (bool result);
};
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
index 475ec76..ca35dc6 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.h
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -59,6 +59,7 @@
Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
const Stream& streamCfg) override;
+ Return<bool> isHardware() override { return true; }
// Implementation details
EvsEnumerator();
diff --git a/automotive/evs/1.1/default/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h
index 1178da5..84b1697 100644
--- a/automotive/evs/1.1/default/ServiceNames.h
+++ b/automotive/evs/1.1/default/ServiceNames.h
@@ -14,4 +14,4 @@
* limitations under the License.
*/
-const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
+const static char kEnumeratorServiceName[] = "hw/0";
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 4fc4e4c..1a62245 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -117,7 +117,7 @@
pEnumerator = getService<IEvsEnumerator>(service_name);
ASSERT_NE(pEnumerator.get(), nullptr);
- mIsHwModule = !service_name.compare(kEnumeratorName);
+ mIsHwModule = pEnumerator->isHardware();
}
virtual void TearDown() override {
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 9ff0d74..5f86742 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -81,8 +81,6 @@
return locked;
}
-buffer_handle_t sEmptyBuffer = nullptr;
-
} // Anonymous namespace
// Static instances
@@ -119,8 +117,8 @@
std::string make, model;
if (ret < 0) {
ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
- make = "Generic UVC webcam";
- model = "Generic UVC webcam";
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
} else {
// capability.card is UTF-8 encoded
char card[32];
@@ -134,11 +132,11 @@
}
}
if (j == 0 || card[j - 1] != '\0') {
- make = "Generic UVC webcam";
- model = "Generic UVC webcam";
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
} else {
- make = card;
- model = card;
+ mExifMake = card;
+ mExifModel = card;
}
}
@@ -147,7 +145,7 @@
ALOGE("%s: init OutputThread failed!", __FUNCTION__);
return true;
}
- mOutputThread->setExifMakeModel(make, model);
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
status_t status = initDefaultRequests();
if (status != OK) {
@@ -161,7 +159,7 @@
ALOGE("%s: invalid request fmq", __FUNCTION__);
return true;
}
- mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+ mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
kMetadataMsgQueueSize, false /* non blocking */);
if (!mResultMetadataQueue->isValid()) {
ALOGE("%s: invalid result fmq", __FUNCTION__);
@@ -183,7 +181,7 @@
}
void ExternalCameraDeviceSession::initOutputThread() {
- mOutputThread = new OutputThread(this, mCroppingType);
+ mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics);
}
void ExternalCameraDeviceSession::closeOutputThread() {
@@ -518,35 +516,9 @@
uint64_t bufId, buffer_handle_t buf,
/*out*/buffer_handle_t** outBufPtr,
bool allowEmptyBuf) {
-
- if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
- if (allowEmptyBuf) {
- *outBufPtr = &sEmptyBuffer;
- return Status::OK;
- } else {
- ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
- return Status::ILLEGAL_ARGUMENT;
- }
- }
-
- CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
- if (cbs.count(bufId) == 0) {
- if (buf == nullptr) {
- ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
- return Status::ILLEGAL_ARGUMENT;
- }
- // Register a newly seen buffer
- buffer_handle_t importedBuf = buf;
- sHandleImporter.importBuffer(importedBuf);
- if (importedBuf == nullptr) {
- ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
- return Status::INTERNAL_ERROR;
- } else {
- cbs[bufId] = importedBuf;
- }
- }
- *outBufPtr = &cbs[bufId];
- return Status::OK;
+ return importBufferImpl(
+ mCirculatingBuffers, sHandleImporter, streamId,
+ bufId, buf, outBufPtr, allowEmptyBuf);
}
Status ExternalCameraDeviceSession::importRequestLockedImpl(
@@ -791,15 +763,32 @@
//TODO: refactor with processCaptureResult
Status ExternalCameraDeviceSession::processCaptureRequestError(
- const std::shared_ptr<HalRequest>& req) {
+ const std::shared_ptr<HalRequest>& req,
+ /*out*/std::vector<NotifyMsg>* outMsgs,
+ /*out*/std::vector<CaptureResult>* outResults) {
ATRACE_CALL();
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req->frameIn);
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+ enqueueV4l2Frame(v4l2Frame);
- // NotifyShutter
- notifyShutter(req->frameNumber, req->shutterTs);
+ if (outMsgs == nullptr) {
+ notifyShutter(req->frameNumber, req->shutterTs);
+ notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = req->frameNumber;
+ shutter.msg.shutter.timestamp = req->shutterTs;
- notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = req->frameNumber;
+ error.msg.error.errorStreamId = -1;
+ error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
// Fill output buffers
hidl_vec<CaptureResult> results;
@@ -826,16 +815,22 @@
mInflightFrames.erase(req->frameNumber);
}
- // Callback into framework
- invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
- freeReleaseFences(results);
+ if (outResults == nullptr) {
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ freeReleaseFences(results);
+ } else {
+ outResults->push_back(result);
+ }
return Status::OK;
}
Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
ATRACE_CALL();
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req->frameIn);
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+ enqueueV4l2Frame(v4l2Frame);
// NotifyShutter
notifyShutter(req->frameNumber, req->shutterTs);
@@ -923,29 +918,10 @@
mProcessCaptureResultLock.unlock();
}
-void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec<CaptureResult>& results) {
- for (auto& result : results) {
- if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
- native_handle_t* handle = const_cast<native_handle_t*>(
- result.inputBuffer.releaseFence.getNativeHandle());
- native_handle_close(handle);
- native_handle_delete(handle);
- }
- for (auto& buf : result.outputBuffers) {
- if (buf.releaseFence.getNativeHandle() != nullptr) {
- native_handle_t* handle = const_cast<native_handle_t*>(
- buf.releaseFence.getNativeHandle());
- native_handle_close(handle);
- native_handle_delete(handle);
- }
- }
- }
- return;
-}
-
ExternalCameraDeviceSession::OutputThread::OutputThread(
- wp<ExternalCameraDeviceSession> parent,
- CroppingType ct) : mParent(parent), mCroppingType(ct) {}
+ wp<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars) :
+ mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {}
ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
@@ -955,88 +931,6 @@
mExifModel = model;
}
-uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
- const YCbCrLayout& layout) {
- intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
- intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
- if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
- // Interleaved format
- if (layout.cb > layout.cr) {
- return V4L2_PIX_FMT_NV21;
- } else {
- return V4L2_PIX_FMT_NV12;
- }
- } else if (layout.chromaStep == 1) {
- // Planar format
- if (layout.cb > layout.cr) {
- return V4L2_PIX_FMT_YVU420; // YV12
- } else {
- return V4L2_PIX_FMT_YUV420; // YU12
- }
- } else {
- return FLEX_YUV_GENERIC;
- }
-}
-
-int ExternalCameraDeviceSession::OutputThread::getCropRect(
- CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
- if (out == nullptr) {
- ALOGE("%s: out is null", __FUNCTION__);
- return -1;
- }
-
- uint32_t inW = inSize.width;
- uint32_t inH = inSize.height;
- uint32_t outW = outSize.width;
- uint32_t outH = outSize.height;
-
- // Handle special case where aspect ratio is close to input but scaled
- // dimension is slightly larger than input
- float arIn = ASPECT_RATIO(inSize);
- float arOut = ASPECT_RATIO(outSize);
- if (isAspectRatioClose(arIn, arOut)) {
- out->left = 0;
- out->top = 0;
- out->width = inW;
- out->height = inH;
- return 0;
- }
-
- if (ct == VERTICAL) {
- uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
- if (scaledOutH > inH) {
- ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
- __FUNCTION__, outW, outH, inW, inH);
- return -1;
- }
- scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
-
- out->left = 0;
- out->top = ((inH - scaledOutH) / 2) & ~0x1;
- out->width = inW;
- out->height = static_cast<int32_t>(scaledOutH);
- ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
- __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
- } else {
- uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
- if (scaledOutW > inW) {
- ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
- __FUNCTION__, outW, outH, inW, inH);
- return -1;
- }
- scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
-
- out->left = ((inW - scaledOutW) / 2) & ~0x1;
- out->top = 0;
- out->width = static_cast<int32_t>(scaledOutW);
- out->height = inH;
- ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
- __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
- }
-
- return 0;
-}
-
int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
Size inSz = {in->mWidth, in->mHeight};
@@ -1274,265 +1168,6 @@
return 0;
}
-int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
- const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
- int ret = 0;
- switch (format) {
- case V4L2_PIX_FMT_NV21:
- ret = libyuv::I420ToNV21(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cr),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: convert to NV21 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case V4L2_PIX_FMT_NV12:
- ret = libyuv::I420ToNV12(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cb),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: convert to NV12 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case V4L2_PIX_FMT_YVU420: // YV12
- case V4L2_PIX_FMT_YUV420: // YU12
- // TODO: maybe we can speed up here by somehow save this copy?
- ret = libyuv::I420Copy(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cb),
- out.cStride,
- static_cast<uint8_t*>(out.cr),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case FLEX_YUV_GENERIC:
- // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
- ALOGE("%s: unsupported flexible yuv layout"
- " y %p cb %p cr %p y_str %d c_str %d c_step %d",
- __FUNCTION__, out.y, out.cb, out.cr,
- out.yStride, out.cStride, out.chromaStep);
- return -1;
- default:
- ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
- return -1;
- }
- return 0;
-}
-
-int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
- const Size & inSz, const YCbCrLayout& inLayout,
- int jpegQuality, const void *app1Buffer, size_t app1Size,
- void *out, const size_t maxOutSize, size_t &actualCodeSize)
-{
- /* libjpeg is a C library so we use C-style "inheritance" by
- * putting libjpeg's jpeg_destination_mgr first in our custom
- * struct. This allows us to cast jpeg_destination_mgr* to
- * CustomJpegDestMgr* when we get it passed to us in a callback */
- struct CustomJpegDestMgr {
- struct jpeg_destination_mgr mgr;
- JOCTET *mBuffer;
- size_t mBufferSize;
- size_t mEncodedSize;
- bool mSuccess;
- } dmgr;
-
- jpeg_compress_struct cinfo = {};
- jpeg_error_mgr jerr;
-
- /* Initialize error handling with standard callbacks, but
- * then override output_message (to print to ALOG) and
- * error_exit to set a flag and print a message instead
- * of killing the whole process */
- cinfo.err = jpeg_std_error(&jerr);
-
- cinfo.err->output_message = [](j_common_ptr cinfo) {
- char buffer[JMSG_LENGTH_MAX];
-
- /* Create the message */
- (*cinfo->err->format_message)(cinfo, buffer);
- ALOGE("libjpeg error: %s", buffer);
- };
- cinfo.err->error_exit = [](j_common_ptr cinfo) {
- (*cinfo->err->output_message)(cinfo);
- if(cinfo->client_data) {
- auto & dmgr =
- *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
- dmgr.mSuccess = false;
- }
- };
- /* Now that we initialized some callbacks, let's create our compressor */
- jpeg_create_compress(&cinfo);
-
- /* Initialize our destination manager */
- dmgr.mBuffer = static_cast<JOCTET*>(out);
- dmgr.mBufferSize = maxOutSize;
- dmgr.mEncodedSize = 0;
- dmgr.mSuccess = true;
- cinfo.client_data = static_cast<void*>(&dmgr);
-
- /* These lambdas become C-style function pointers and as per C++11 spec
- * may not capture anything */
- dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
- auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
- dmgr.mgr.next_output_byte = dmgr.mBuffer;
- dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
- ALOGV("%s:%d jpeg start: %p [%zu]",
- __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
- };
-
- dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
- ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
- return 0;
- };
-
- dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
- auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
- dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
- ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
- };
- cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
-
- /* We are going to be using JPEG in raw data mode, so we are passing
- * straight subsampled planar YCbCr and it will not touch our pixel
- * data or do any scaling or anything */
- cinfo.image_width = inSz.width;
- cinfo.image_height = inSz.height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_YCbCr;
-
- /* Initialize defaults and then override what we want */
- jpeg_set_defaults(&cinfo);
-
- jpeg_set_quality(&cinfo, jpegQuality, 1);
- jpeg_set_colorspace(&cinfo, JCS_YCbCr);
- cinfo.raw_data_in = 1;
- cinfo.dct_method = JDCT_IFAST;
-
- /* Configure sampling factors. The sampling factor is JPEG subsampling 420
- * because the source format is YUV420. Note that libjpeg sampling factors
- * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
- * 1 V value for each 2 Y values */
- cinfo.comp_info[0].h_samp_factor = 2;
- cinfo.comp_info[0].v_samp_factor = 2;
- cinfo.comp_info[1].h_samp_factor = 1;
- cinfo.comp_info[1].v_samp_factor = 1;
- cinfo.comp_info[2].h_samp_factor = 1;
- cinfo.comp_info[2].v_samp_factor = 1;
-
- /* Let's not hardcode YUV420 in 6 places... 5 was enough */
- int maxVSampFactor = std::max( {
- cinfo.comp_info[0].v_samp_factor,
- cinfo.comp_info[1].v_samp_factor,
- cinfo.comp_info[2].v_samp_factor
- });
- int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
- cinfo.comp_info[1].v_samp_factor;
-
- /* Start the compressor */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Compute our macroblock height, so we can pad our input to be vertically
- * macroblock aligned.
- * TODO: Does it need to be horizontally MCU aligned too? */
-
- size_t mcuV = DCTSIZE*maxVSampFactor;
- size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
-
- /* libjpeg uses arrays of row pointers, which makes it really easy to pad
- * data vertically (unfortunately doesn't help horizontally) */
- std::vector<JSAMPROW> yLines (paddedHeight);
- std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
- std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
-
- uint8_t *py = static_cast<uint8_t*>(inLayout.y);
- uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
- uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
-
- for(uint32_t i = 0; i < paddedHeight; i++)
- {
- /* Once we are in the padding territory we still point to the last line
- * effectively replicating it several times ~ CLAMP_TO_EDGE */
- int li = std::min(i, inSz.height - 1);
- yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
- if(i < paddedHeight / cVSubSampling)
- {
- crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
- cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
- }
- }
-
- /* If APP1 data was passed in, use it */
- if(app1Buffer && app1Size)
- {
- jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
- static_cast<const JOCTET*>(app1Buffer), app1Size);
- }
-
- /* While we still have padded height left to go, keep giving it one
- * macroblock at a time. */
- while (cinfo.next_scanline < cinfo.image_height) {
- const uint32_t batchSize = DCTSIZE * maxVSampFactor;
- const uint32_t nl = cinfo.next_scanline;
- JSAMPARRAY planes[3]{ &yLines[nl],
- &cbLines[nl/cVSubSampling],
- &crLines[nl/cVSubSampling] };
-
- uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
-
- if (done != batchSize) {
- ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
- __FUNCTION__, done, batchSize, cinfo.next_scanline,
- cinfo.image_height);
- return -1;
- }
- }
-
- /* This will flush everything */
- jpeg_finish_compress(&cinfo);
-
- /* Grab the actual code size and set it */
- actualCodeSize = dmgr.mEncodedSize;
-
- return 0;
-}
-
/*
* TODO: There needs to be a mechanism to discover allocated buffer size
* in the HAL.
@@ -1555,25 +1190,9 @@
}
Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
- Size thumbSize { 0, 0 };
- camera_metadata_ro_entry entry =
- mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
- for(uint32_t i = 0; i < entry.count; i += 2) {
- Size sz { static_cast<uint32_t>(entry.data.i32[i]),
- static_cast<uint32_t>(entry.data.i32[i+1]) };
- if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
- thumbSize = sz;
- }
- }
-
- if (thumbSize.width * thumbSize.height == 0) {
- ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
- }
-
- return thumbSize;
+ return getMaxThumbnailResolution(mCameraCharacteristics);
}
-
ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
uint32_t width, uint32_t height) const {
// Constant from camera3.h
@@ -1616,7 +1235,7 @@
int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
HalStreamBuffer &halBuf,
- const std::shared_ptr<HalRequest>& req)
+ const common::V1_0::helper::CameraMetadata& setting)
{
ATRACE_CALL();
int ret;
@@ -1645,17 +1264,17 @@
Size thumbSize;
bool outputThumbnail = true;
- if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_QUALITY);
+ if (setting.exists(ANDROID_JPEG_QUALITY)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_QUALITY);
jpegQuality = entry.data.u8[0];
} else {
return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
}
- if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
thumbQuality = entry.data.u8[0];
} else {
return lfail(
@@ -1663,9 +1282,9 @@
__FUNCTION__);
}
- if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
static_cast<uint32_t>(entry.data.i32[1])
};
@@ -1732,8 +1351,8 @@
/* Combine camera characteristics with request settings to form EXIF
* metadata */
- common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
- meta.append(req->setting);
+ common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+ meta.append(setting);
/* Generate EXIF object */
std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -1838,7 +1457,7 @@
// TODO: see if we can save some computation by converting to YV12 here
uint8_t* inData;
size_t inDataSize;
- if (req->frameIn->map(&inData, &inDataSize) != 0) {
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
lk.unlock();
return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
}
@@ -1899,7 +1518,7 @@
// Gralloc lockYCbCr the buffer
switch (halBuf.format) {
case PixelFormat::BLOB: {
- int ret = createJpegLocked(halBuf, req);
+ int ret = createJpegLocked(halBuf, req->setting);
if(ret != 0) {
lk.unlock();
@@ -1949,8 +1568,8 @@
}
Size sz {halBuf.width, halBuf.height};
- ATRACE_BEGIN("formatConvertLocked");
- ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_BEGIN("formatConvert");
+ ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
ATRACE_END();
if (ret != 0) {
lk.unlock();
@@ -2055,6 +1674,14 @@
return Status::OK;
}
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+ std::lock_guard<std::mutex> lk(mBufferLock);
+ mYu12Frame.clear();
+ mYu12ThumbFrame.clear();
+ mIntermediateBuffers.clear();
+ mBlobBufferSize = 0;
+}
+
Status ExternalCameraDeviceSession::OutputThread::submitRequest(
const std::shared_ptr<HalRequest>& req) {
std::unique_lock<std::mutex> lk(mRequestListLock);
@@ -2090,6 +1717,32 @@
}
}
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+ ATRACE_CALL();
+ std::list<std::shared_ptr<HalRequest>> emptyList;
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return emptyList;
+ }
+
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+ mRequestList.clear();
+ if (mProcessingRequest) {
+ std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+ auto st = mRequestDoneCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+ }
+ }
+ lk.unlock();
+ clearIntermediateBuffers();
+ ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+ return reqs;
+}
+
void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
std::shared_ptr<HalRequest>* out) {
ATRACE_CALL();
@@ -2733,6 +2386,7 @@
return Status::INTERNAL_ERROR;
}
+ mBlobBufferSize = blobBufferSize;
status = mOutputThread->allocateIntermediateBuffers(v4lSize,
mMaxThumbResolution, config.streams, blobBufferSize);
if (status != Status::OK) {
@@ -2916,16 +2570,6 @@
status_t ExternalCameraDeviceSession::fillCaptureResult(
common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
- // android.control
- // For USB camera, we don't know the AE state. Set the state to converged to
- // indicate the frame should be good to use. Then apps don't have to wait the
- // AE state.
- const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
- UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
-
- const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
- UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
-
bool afTrigger = false;
{
std::lock_guard<std::mutex> lk(mAfTriggerLock);
@@ -2951,46 +2595,10 @@
}
UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
- // Set AWB state to converged to indicate the frame should be good to use.
- const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
- UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+ camera_metadata_ro_entry activeArraySize =
+ mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
- UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
- camera_metadata_ro_entry active_array_size =
- mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-
- if (active_array_size.count == 0) {
- ALOGE("%s: cannot find active array size!", __FUNCTION__);
- return -EINVAL;
- }
-
- const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
- UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
-
- // This means pipeline latency of X frame intervals. The maximum number is 4.
- const uint8_t requestPipelineMaxDepth = 4;
- UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
-
- // android.scaler
- const int32_t crop_region[] = {
- active_array_size.data.i32[0], active_array_size.data.i32[1],
- active_array_size.data.i32[2], active_array_size.data.i32[3],
- };
- UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
-
- // android.sensor
- UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1);
-
- // android.statistics
- const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
- UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
-
- const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
- UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
-
- return OK;
+ return fillCaptureResultCommon(md, timestamp, activeArraySize);
}
#undef ARRAY_SIZE
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index e25deff..4a6381e 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -18,10 +18,23 @@
#include <log/log.h>
#include <cmath>
+#include <cstring>
#include <sys/mman.h>
#include <linux/videodev2.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <jpeglib.h>
+
#include "ExternalCameraUtils.h"
+namespace {
+
+buffer_handle_t sEmptyBuffer = nullptr;
+
+} // Anonymous namespace
+
namespace android {
namespace hardware {
namespace camera {
@@ -29,10 +42,13 @@
namespace V3_4 {
namespace implementation {
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) :
+ mWidth(width), mHeight(height), mFourcc(fourcc) {}
+
V4L2Frame::V4L2Frame(
uint32_t w, uint32_t h, uint32_t fourcc,
int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
- mWidth(w), mHeight(h), mFourcc(fourcc),
+ Frame(w, h, fourcc),
mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
@@ -75,9 +91,13 @@
unmap();
}
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ return map(outData, dataSize);
+}
+
AllocatedFrame::AllocatedFrame(
uint32_t w, uint32_t h) :
- mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+ Frame(w, h, V4L2_PIX_FMT_YUV420) {};
AllocatedFrame::~AllocatedFrame() {}
@@ -106,6 +126,17 @@
return 0;
}
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+ YCbCrLayout layout;
+ int ret = allocate(&layout);
+ if (ret != 0) {
+ return ret;
+ }
+ *outData = mData.data();
+ *dataSize = mData.size();
+ return 0;
+}
+
int AllocatedFrame::getLayout(YCbCrLayout* out) {
IMapper::Rect noCrop = {0, 0,
static_cast<int32_t>(mWidth),
@@ -150,8 +181,520 @@
return durationDenominator / static_cast<double>(durationNumerator);
}
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+ /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/HandleImporter& handleImporter,
+ int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) {
+ using ::android::hardware::camera::common::V1_0::Status;
+ if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+ if (allowEmptyBuf) {
+ *outBufPtr = &sEmptyBuffer;
+ return Status::OK;
+ } else {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ CirculatingBuffers& cbs = circulatingBuffers[streamId];
+ if (cbs.count(bufId) == 0) {
+ if (buf == nullptr) {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ // Register a newly seen buffer
+ buffer_handle_t importedBuf = buf;
+ handleImporter.importBuffer(importedBuf);
+ if (importedBuf == nullptr) {
+ ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+ return Status::INTERNAL_ERROR;
+ } else {
+ cbs[bufId] = importedBuf;
+ }
+ }
+ *outBufPtr = &cbs[bufId];
+ return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+ intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+ intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+ if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+ // Interleaved format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_NV21;
+ } else {
+ return V4L2_PIX_FMT_NV12;
+ }
+ } else if (layout.chromaStep == 1) {
+ // Planar format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_YVU420; // YV12
+ } else {
+ return V4L2_PIX_FMT_YUV420; // YU12
+ }
+ } else {
+ return FLEX_YUV_GENERIC;
+ }
+}
+
+int getCropRect(
+ CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+ if (out == nullptr) {
+ ALOGE("%s: out is null", __FUNCTION__);
+ return -1;
+ }
+
+ uint32_t inW = inSize.width;
+ uint32_t inH = inSize.height;
+ uint32_t outW = outSize.width;
+ uint32_t outH = outSize.height;
+
+ // Handle special case where aspect ratio is close to input but scaled
+ // dimension is slightly larger than input
+ float arIn = ASPECT_RATIO(inSize);
+ float arOut = ASPECT_RATIO(outSize);
+ if (isAspectRatioClose(arIn, arOut)) {
+ out->left = 0;
+ out->top = 0;
+ out->width = inW;
+ out->height = inH;
+ return 0;
+ }
+
+ if (ct == VERTICAL) {
+ uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+ if (scaledOutH > inH) {
+ ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+ out->left = 0;
+ out->top = ((inH - scaledOutH) / 2) & ~0x1;
+ out->width = inW;
+ out->height = static_cast<int32_t>(scaledOutH);
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
+ __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
+ } else {
+ uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+ if (scaledOutW > inW) {
+ ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+ out->left = ((inW - scaledOutW) / 2) & ~0x1;
+ out->top = 0;
+ out->width = static_cast<int32_t>(scaledOutW);
+ out->height = inH;
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
+ __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
+ }
+
+ return 0;
+}
+
+int formatConvert(
+ const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+ int ret = 0;
+ switch (format) {
+ case V4L2_PIX_FMT_NV21:
+ ret = libyuv::I420ToNV21(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cr),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: convert to NV21 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_NV12:
+ ret = libyuv::I420ToNV12(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cb),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: convert to NV12 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_YVU420: // YV12
+ case V4L2_PIX_FMT_YUV420: // YU12
+ // TODO: maybe we can speed up here by somehow save this copy?
+ ret = libyuv::I420Copy(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cb),
+ out.cStride,
+ static_cast<uint8_t*>(out.cr),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case FLEX_YUV_GENERIC:
+ // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+ ALOGE("%s: unsupported flexible yuv layout"
+ " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+ __FUNCTION__, out.y, out.cb, out.cr,
+ out.yStride, out.cStride, out.chromaStep);
+ return -1;
+ default:
+ ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+ return -1;
+ }
+ return 0;
+}
+
+int encodeJpegYU12(
+ const Size & inSz, const YCbCrLayout& inLayout,
+ int jpegQuality, const void *app1Buffer, size_t app1Size,
+ void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+ /* libjpeg is a C library so we use C-style "inheritance" by
+ * putting libjpeg's jpeg_destination_mgr first in our custom
+ * struct. This allows us to cast jpeg_destination_mgr* to
+ * CustomJpegDestMgr* when we get it passed to us in a callback */
+ struct CustomJpegDestMgr {
+ struct jpeg_destination_mgr mgr;
+ JOCTET *mBuffer;
+ size_t mBufferSize;
+ size_t mEncodedSize;
+ bool mSuccess;
+ } dmgr;
+
+ jpeg_compress_struct cinfo = {};
+ jpeg_error_mgr jerr;
+
+ /* Initialize error handling with standard callbacks, but
+ * then override output_message (to print to ALOG) and
+ * error_exit to set a flag and print a message instead
+ * of killing the whole process */
+ cinfo.err = jpeg_std_error(&jerr);
+
+ cinfo.err->output_message = [](j_common_ptr cinfo) {
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message)(cinfo, buffer);
+ ALOGE("libjpeg error: %s", buffer);
+ };
+ cinfo.err->error_exit = [](j_common_ptr cinfo) {
+ (*cinfo->err->output_message)(cinfo);
+ if(cinfo->client_data) {
+ auto & dmgr =
+ *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+ dmgr.mSuccess = false;
+ }
+ };
+ /* Now that we initialized some callbacks, let's create our compressor */
+ jpeg_create_compress(&cinfo);
+
+ /* Initialize our destination manager */
+ dmgr.mBuffer = static_cast<JOCTET*>(out);
+ dmgr.mBufferSize = maxOutSize;
+ dmgr.mEncodedSize = 0;
+ dmgr.mSuccess = true;
+ cinfo.client_data = static_cast<void*>(&dmgr);
+
+ /* These lambdas become C-style function pointers and as per C++11 spec
+ * may not capture anything */
+ dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+ auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mgr.next_output_byte = dmgr.mBuffer;
+ dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+ ALOGV("%s:%d jpeg start: %p [%zu]",
+ __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+ };
+
+ dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+ ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+ return 0;
+ };
+
+ dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+ auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+ ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+ };
+ cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+ /* We are going to be using JPEG in raw data mode, so we are passing
+ * straight subsampled planar YCbCr and it will not touch our pixel
+ * data or do any scaling or anything */
+ cinfo.image_width = inSz.width;
+ cinfo.image_height = inSz.height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_YCbCr;
+
+ /* Initialize defaults and then override what we want */
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_set_quality(&cinfo, jpegQuality, 1);
+ jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+ cinfo.raw_data_in = 1;
+ cinfo.dct_method = JDCT_IFAST;
+
+ /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+ * because the source format is YUV420. Note that libjpeg sampling factors
+ * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+ * 1 V value for each 2 Y values */
+ cinfo.comp_info[0].h_samp_factor = 2;
+ cinfo.comp_info[0].v_samp_factor = 2;
+ cinfo.comp_info[1].h_samp_factor = 1;
+ cinfo.comp_info[1].v_samp_factor = 1;
+ cinfo.comp_info[2].h_samp_factor = 1;
+ cinfo.comp_info[2].v_samp_factor = 1;
+
+ /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+ int maxVSampFactor = std::max( {
+ cinfo.comp_info[0].v_samp_factor,
+ cinfo.comp_info[1].v_samp_factor,
+ cinfo.comp_info[2].v_samp_factor
+ });
+ int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+ cinfo.comp_info[1].v_samp_factor;
+
+ /* Start the compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Compute our macroblock height, so we can pad our input to be vertically
+ * macroblock aligned.
+ * TODO: Does it need to be horizontally MCU aligned too? */
+
+ size_t mcuV = DCTSIZE*maxVSampFactor;
+ size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+ /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+ * data vertically (unfortunately doesn't help horizontally) */
+ std::vector<JSAMPROW> yLines (paddedHeight);
+ std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+ std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+ uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+ uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+ uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+ for(uint32_t i = 0; i < paddedHeight; i++)
+ {
+ /* Once we are in the padding territory we still point to the last line
+ * effectively replicating it several times ~ CLAMP_TO_EDGE */
+ int li = std::min(i, inSz.height - 1);
+ yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+ if(i < paddedHeight / cVSubSampling)
+ {
+ crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+ cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+ }
+ }
+
+ /* If APP1 data was passed in, use it */
+ if(app1Buffer && app1Size)
+ {
+ jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+ static_cast<const JOCTET*>(app1Buffer), app1Size);
+ }
+
+ /* While we still have padded height left to go, keep giving it one
+ * macroblock at a time. */
+ while (cinfo.next_scanline < cinfo.image_height) {
+ const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+ const uint32_t nl = cinfo.next_scanline;
+ JSAMPARRAY planes[3]{ &yLines[nl],
+ &cbLines[nl/cVSubSampling],
+ &crLines[nl/cVSubSampling] };
+
+ uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+ if (done != batchSize) {
+ ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+ __FUNCTION__, done, batchSize, cinfo.next_scanline,
+ cinfo.image_height);
+ return -1;
+ }
+ }
+
+ /* This will flush everything */
+ jpeg_finish_compress(&cinfo);
+
+ /* Grab the actual code size and set it */
+ actualCodeSize = dmgr.mEncodedSize;
+
+ return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+ Size thumbSize { 0, 0 };
+ camera_metadata_ro_entry entry =
+ chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+ for(uint32_t i = 0; i < entry.count; i += 2) {
+ Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+ static_cast<uint32_t>(entry.data.i32[i+1]) };
+ if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+ thumbSize = sz;
+ }
+ }
+
+ if (thumbSize.width * thumbSize.height == 0) {
+ ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+ }
+
+ return thumbSize;
+}
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>& results) {
+ for (auto& result : results) {
+ if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ result.inputBuffer.releaseFence.getNativeHandle());
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ for (auto& buf : result.outputBuffers) {
+ if (buf.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ buf.releaseFence.getNativeHandle());
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ }
+ }
+ return;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size) \
+do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+} while (0)
+
+status_t fillCaptureResultCommon(
+ common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize) {
+ if (activeArraySize.count < 4) {
+ ALOGE("%s: cannot find active array size!", __FUNCTION__);
+ return -EINVAL;
+ }
+ // android.control
+ // For USB camera, we don't know the AE state. Set the state to converged to
+ // indicate the frame should be good to use. Then apps don't have to wait the
+ // AE state.
+ const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+ const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+ // Set AWB state to converged to indicate the frame should be good to use.
+ const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+ const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+ const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+ UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+ // This means pipeline latency of X frame intervals. The maximum number is 4.
+ const uint8_t requestPipelineMaxDepth = 4;
+ UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+ // android.scaler
+ const int32_t crop_region[] = {
+ activeArraySize.data.i32[0], activeArraySize.data.i32[1],
+ activeArraySize.data.i32[2], activeArraySize.data.i32[3],
+ };
+ UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+ // android.sensor
+ UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1);
+
+ // android.statistics
+ const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+ UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+ const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+ UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+ return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
} // namespace implementation
} // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn) :
+ Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+ uint8_t* dataIn;
+ size_t dataSize;
+ if (frameIn->getData(&dataIn, &dataSize) != 0) {
+ ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+ return;
+ }
+
+ mData.resize(dataSize);
+ std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ if (outData == nullptr || dataSize == nullptr) {
+ ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+ return -1;
+ }
+
+ *outData = mData.data();
+ *dataSize = mData.size();
+ return 0;
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+} // namespace implementation
+} // namespace V3_6
} // namespace device
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 71b7c17..ecab9cf 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
@@ -84,7 +84,8 @@
using ::android::Mutex;
using ::android::base::unique_fd;
-struct ExternalCameraDeviceSession : public virtual RefBase {
+struct ExternalCameraDeviceSession : public virtual RefBase,
+ public virtual OutputThreadInterface {
ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
const ExternalCameraConfig& cfg,
@@ -110,6 +111,82 @@
static const int kMaxStallStream = 1;
static const uint32_t kMaxBytesPerPixel = 2;
+ class OutputThread : public android::Thread {
+ public:
+ OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+ const common::V1_0::helper::CameraMetadata&);
+ virtual ~OutputThread();
+
+ Status allocateIntermediateBuffers(
+ const Size& v4lSize, const Size& thumbSize,
+ const hidl_vec<Stream>& streams,
+ uint32_t blobBufferSize);
+ Status submitRequest(const std::shared_ptr<HalRequest>&);
+ void flush();
+ void dump(int fd);
+ virtual bool threadLoop() override;
+
+ void setExifMakeModel(const std::string& make, const std::string& model);
+
+ // The remaining request list is returned for offline processing
+ std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+ protected:
+ // Methods to request output buffer in parallel
+ // No-op for device@3.4. Implemented in device@3.5
+ virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
+ virtual int waitForBufferRequestDone(
+ /*out*/std::vector<HalStreamBuffer>*) { return 0; }
+
+ static const int kFlushWaitTimeoutSec = 3; // 3 sec
+ static const int kReqWaitTimeoutMs = 33; // 33ms
+ static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
+
+ void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+ void signalRequestDone();
+
+ int cropAndScaleLocked(
+ sp<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int cropAndScaleThumbLocked(
+ sp<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int createJpegLocked(HalStreamBuffer &halBuf,
+ const common::V1_0::helper::CameraMetadata& settings);
+
+ void clearIntermediateBuffers();
+
+ const wp<OutputThreadInterface> mParent;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+ mutable std::mutex mRequestListLock; // Protect acccess to mRequestList,
+ // mProcessingRequest and mProcessingFrameNumer
+ std::condition_variable mRequestCond; // signaled when a new request is submitted
+ std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+ std::list<std::shared_ptr<HalRequest>> mRequestList;
+ bool mProcessingRequest = false;
+ uint32_t mProcessingFrameNumer = 0;
+
+ // V4L2 frameIn
+ // (MJPG decode)-> mYu12Frame
+ // (Scale)-> mScaledYu12Frames
+ // (Format convert) -> output gralloc frames
+ mutable std::mutex mBufferLock; // Protect access to intermediate buffers
+ sp<AllocatedFrame> mYu12Frame;
+ sp<AllocatedFrame> mYu12ThumbFrame;
+ std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+ std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+ YCbCrLayout mYu12FrameLayout;
+ YCbCrLayout mYu12ThumbFrameLayout;
+ uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
+
+ std::string mExifMake;
+ std::string mExifModel;
+ };
+
protected:
// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
@@ -150,27 +227,22 @@
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
protected:
- struct HalStreamBuffer {
- int32_t streamId;
- uint64_t bufferId;
- uint32_t width;
- uint32_t height;
- PixelFormat format;
- V3_2::BufferUsageFlags usage;
- buffer_handle_t* bufPtr;
- int acquireFence;
- bool fenceTimeout;
- };
+ // Methods from OutputThreadInterface
+ virtual Status importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) override;
- struct HalRequest {
- uint32_t frameNumber;
- common::V1_0::helper::CameraMetadata setting;
- sp<V4L2Frame> frameIn;
- nsecs_t shutterTs;
- std::vector<HalStreamBuffer> buffers;
- };
+ virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
- static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+ virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+ // End of OutputThreadInterface methods
Status constructDefaultRequestSettingsRaw(RequestTemplate type,
V3_2::CameraMetadata *outMetadata);
@@ -219,11 +291,6 @@
// Optional argument for ICameraDeviceSession@3.5 impl
bool allowEmptyBuf = false);
- Status importBuffer(int32_t streamId,
- uint64_t bufId, buffer_handle_t buf,
- /*out*/buffer_handle_t** outBufPtr,
- bool allowEmptyBuf);
-
Status importBufferLocked(int32_t streamId,
uint64_t bufId, buffer_handle_t buf,
/*out*/buffer_handle_t** outBufPtr,
@@ -236,106 +303,15 @@
Status processOneCaptureRequest(const CaptureRequest& request);
- Status processCaptureResult(std::shared_ptr<HalRequest>&);
- Status processCaptureRequestError(const std::shared_ptr<HalRequest>&);
void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
- void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
void invokeProcessCaptureResultCallback(
hidl_vec<CaptureResult> &results, bool tryWriteFmq);
- static void freeReleaseFences(hidl_vec<CaptureResult>&);
Size getMaxJpegResolution() const;
Size getMaxThumbResolution() const;
- ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
- class OutputThread : public android::Thread {
- public:
- OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
- virtual ~OutputThread();
-
- Status allocateIntermediateBuffers(
- const Size& v4lSize, const Size& thumbSize,
- const hidl_vec<Stream>& streams,
- uint32_t blobBufferSize);
- Status submitRequest(const std::shared_ptr<HalRequest>&);
- void flush();
- void dump(int fd);
- virtual bool threadLoop() override;
-
- void setExifMakeModel(const std::string& make, const std::string& model);
-
- protected:
- // Methods to request output buffer in parallel
- // No-op for device@3.4. Implemented in device@3.5
- virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
- virtual int waitForBufferRequestDone(
- /*out*/std::vector<HalStreamBuffer>*) { return 0; }
-
- static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
- static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
- static_cast<uint32_t>('X') << 24;
- // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
- static uint32_t getFourCcFromLayout(const YCbCrLayout&);
- static int getCropRect(
- CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
-
- static const int kFlushWaitTimeoutSec = 3; // 3 sec
- static const int kReqWaitTimeoutMs = 33; // 33ms
- static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
-
- void waitForNextRequest(std::shared_ptr<HalRequest>* out);
- void signalRequestDone();
-
- int cropAndScaleLocked(
- sp<AllocatedFrame>& in, const Size& outSize,
- YCbCrLayout* out);
-
- int cropAndScaleThumbLocked(
- sp<AllocatedFrame>& in, const Size& outSize,
- YCbCrLayout* out);
-
- int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
- Size sz, uint32_t format);
-
- static int encodeJpegYU12(const Size &inSz,
- const YCbCrLayout& inLayout, int jpegQuality,
- const void *app1Buffer, size_t app1Size,
- void *out, size_t maxOutSize,
- size_t &actualCodeSize);
-
- int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr<HalRequest>& req);
-
- const wp<ExternalCameraDeviceSession> mParent;
- const CroppingType mCroppingType;
-
- mutable std::mutex mRequestListLock; // Protect acccess to mRequestList,
- // mProcessingRequest and mProcessingFrameNumer
- std::condition_variable mRequestCond; // signaled when a new request is submitted
- std::condition_variable mRequestDoneCond; // signaled when a request is done processing
- std::list<std::shared_ptr<HalRequest>> mRequestList;
- bool mProcessingRequest = false;
- uint32_t mProcessingFrameNumer = 0;
-
- // V4L2 frameIn
- // (MJPG decode)-> mYu12Frame
- // (Scale)-> mScaledYu12Frames
- // (Format convert) -> output gralloc frames
- mutable std::mutex mBufferLock; // Protect access to intermediate buffers
- sp<AllocatedFrame> mYu12Frame;
- sp<AllocatedFrame> mYu12ThumbFrame;
- std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
- std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
- YCbCrLayout mYu12FrameLayout;
- YCbCrLayout mYu12ThumbFrameLayout;
- uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
-
- std::string mExifMake;
- std::string mExifModel;
- };
-
// Protect (most of) HIDL interface methods from synchronized-entering
mutable Mutex mInterfaceLock;
@@ -381,12 +357,6 @@
std::mutex mInflightFramesLock; // protect mInflightFrames
std::unordered_set<uint32_t> mInflightFrames;
- // buffers currently circulating between HAL and camera service
- // key: bufferId sent via HIDL interface
- // value: imported buffer_handle_t
- // Buffer will be imported during processCaptureRequest and will be freed
- // when the its stream is deleted or camera device session is closed
- typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
// Stream ID -> circulating buffers map
std::map<int, CirculatingBuffers> mCirculatingBuffers;
// Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
@@ -395,6 +365,8 @@
std::mutex mAfTriggerLock; // protect mAfTrigger
bool mAfTrigger = false;
+ uint32_t mBlobBufferSize = 0;
+
static HandleImporter sHandleImporter;
/* Beginning of members not changed after initialize() */
@@ -410,6 +382,9 @@
const Size mMaxThumbResolution;
const Size mMaxJpegResolution;
+
+ std::string mExifMake;
+ std::string mExifModel;
/* End of members not changed after initialize() */
private:
@@ -484,4 +459,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index bd79807..1958fcb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -105,7 +105,7 @@
// Calls into virtual member function. Do not use it in constructor
status_t initCameraCharacteristics();
// Init available capabilities keys
- status_t initAvailableCapabilities(
+ virtual status_t initAvailableCapabilities(
::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
// Init non-device dependent keys
virtual status_t initDefaultCharsKeys(
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 341c622..74f75eb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -17,16 +17,27 @@
#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
+#include <android/hardware/camera/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include <android/hardware/graphics/common/1.0/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <inttypes.h>
#include <mutex>
+#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "tinyxml2.h" // XML parsing
#include "utils/LightRefBase.h"
+#include "utils/Timers.h"
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
namespace android {
namespace hardware {
@@ -113,16 +124,28 @@
std::vector<FrameRate> frameRates;
};
+// A Base class with basic information about a frame
+struct Frame : public VirtualLightRefBase {
+public:
+ Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mFourcc;
+
+ // getData might involve map/allocation
+ virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
-class V4L2Frame : public virtual VirtualLightRefBase {
+class V4L2Frame : public Frame {
public:
V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd,
uint32_t dataSize, uint64_t offset);
~V4L2Frame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc;
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
const int mBufferIndex; // for later enqueue
int map(uint8_t** data, size_t* dataSize);
int unmap();
@@ -137,13 +160,13 @@
// A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
// when generating output images.
-class AllocatedFrame : public virtual VirtualLightRefBase {
+class AllocatedFrame : public Frame {
public:
- AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+ AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now
~AllocatedFrame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc; // Only support YU12 format for now
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
int allocate(YCbCrLayout* out = nullptr);
int getLayout(YCbCrLayout* out);
int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
@@ -165,8 +188,110 @@
bool isAspectRatioClose(float ar1, float ar2);
+struct HalStreamBuffer {
+ int32_t streamId;
+ uint64_t bufferId;
+ uint32_t width;
+ uint32_t height;
+ ::android::hardware::graphics::common::V1_0::PixelFormat format;
+ ::android::hardware::camera::device::V3_2::BufferUsageFlags usage;
+ buffer_handle_t* bufPtr;
+ int acquireFence;
+ bool fenceTimeout;
+};
+
+struct HalRequest {
+ uint32_t frameNumber;
+ common::V1_0::helper::CameraMetadata setting;
+ sp<Frame> frameIn;
+ nsecs_t shutterTs;
+ std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+ /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/HandleImporter& handleImporter,
+ int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf);
+
+static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
+ static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
+ static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize,
+ const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size &inSz,
+ const YCbCrLayout& inLayout, int jpegQuality,
+ const void *app1Buffer, size_t app1Size,
+ void *out, size_t maxOutSize,
+ size_t &actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface : public virtual RefBase {
+ virtual ::android::hardware::camera::common::V1_0::Status importBuffer(
+ int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+ // Callbacks are fired within the method if msgs/results are nullptr.
+ // Otherwise the callbacks will be returned and caller is responsible to
+ // fire the callback later
+ virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError(
+ const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<V3_2::NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<V3_2::CaptureResult>* results = nullptr) = 0;
+
+ virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult(
+ std::shared_ptr<HalRequest>&) = 0;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+};
+
} // namespace implementation
} // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public V3_4::implementation::Frame {
+public:
+ AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn);
+ ~AllocatedV4L2Frame() override;
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+private:
+ std::vector<uint8_t> mData;
+};
+
+} // namespace implementation
+} // namespace V3_6
} // namespace device
} // namespace camera
} // namespace hardware
diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
index 00c1d0d..287ac32 100644
--- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
@@ -80,7 +80,7 @@
ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
- wp<ExternalCameraDeviceSession> parent,
+ wp<OutputThreadInterface> parent,
sp<V3_5::ICameraDeviceCallback> callbacks) :
mParent(parent),
mCallbacks(callbacks) {}
@@ -254,7 +254,8 @@
mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
}
- mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread);
+ mOutputThread = new OutputThread(
+ this, mCroppingType, mCameraCharacteristics, mBufferRequestThread);
}
void ExternalCameraDeviceSession::closeOutputThreadImpl() {
@@ -271,10 +272,11 @@
}
ExternalCameraDeviceSession::OutputThread::OutputThread(
- wp<ExternalCameraDeviceSession> parent,
+ wp<OutputThreadInterface> parent,
CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
sp<BufferRequestThread> bufReqThread) :
- V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct),
+ V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars),
mBufferRequestThread(bufReqThread) {}
ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
index 281f93a..e89ef45 100644
--- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
@@ -72,6 +72,7 @@
using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer;
struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession {
@@ -97,6 +98,62 @@
config, supportedFormats, devCfg);
}
+ class BufferRequestThread : public android::Thread {
+ public:
+ BufferRequestThread(
+ wp<OutputThreadInterface> parent,
+ sp<V3_5::ICameraDeviceCallback> callbacks);
+
+ int requestBufferStart(const std::vector<HalStreamBuffer>&);
+ int waitForBufferRequestDone(
+ /*out*/std::vector<HalStreamBuffer>*);
+
+ virtual bool threadLoop() override;
+
+ private:
+ void waitForNextRequest();
+
+ const wp<OutputThreadInterface> mParent;
+ const sp<V3_5::ICameraDeviceCallback> mCallbacks;
+
+ std::mutex mLock;
+ bool mRequestingBuffer = false;
+
+ std::vector<HalStreamBuffer> mBufferReqs;
+ std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
+ // mHalBufferReqs is not under mLock protection during the HIDL transaction
+ hidl_vec<BufferRequest> mHalBufferReqs;
+
+ // request buffers takes much less time in steady state, but can take much longer
+ // when requesting 1st buffer from a stream.
+ // TODO: consider a separate timeout for new vs. steady state?
+ // TODO: or make sure framework is warming up the pipeline during configure new stream?
+ static const int kReqProcTimeoutMs = 66;
+
+ static const int kReqWaitTimeoutMs = 33;
+ static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec
+ std::condition_variable mRequestCond; // signaled when a new buffer request incoming
+ std::condition_variable mRequestDoneCond; // signaled when a request is done
+ };
+
+ class OutputThread :
+ public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
+ public:
+ // TODO: pass buffer request thread to OutputThread ctor
+ OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+ const common::V1_0::helper::CameraMetadata&,
+ sp<BufferRequestThread> bufReqThread);
+ virtual ~OutputThread();
+
+ protected:
+ // Methods to request output buffer in parallel
+ virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
+ virtual int waitForBufferRequestDone(
+ /*out*/std::vector<HalStreamBuffer>*) override;
+
+ const sp<BufferRequestThread> mBufferRequestThread;
+ };
+
protected:
// Methods from v3.4 and earlier will trampoline to inherited implementation
Return<void> configureStreams_3_5(
@@ -120,63 +177,8 @@
hidl_vec<buffer_handle_t*>& allBufPtrs,
hidl_vec<int>& allFences) override;
- class BufferRequestThread : public android::Thread {
- public:
- BufferRequestThread(
- wp<ExternalCameraDeviceSession> parent,
- sp<V3_5::ICameraDeviceCallback> callbacks);
-
- int requestBufferStart(const std::vector<HalStreamBuffer>&);
- int waitForBufferRequestDone(
- /*out*/std::vector<HalStreamBuffer>*);
-
- virtual bool threadLoop() override;
-
- private:
- void waitForNextRequest();
-
- const wp<ExternalCameraDeviceSession> mParent;
- const sp<V3_5::ICameraDeviceCallback> mCallbacks;
-
- std::mutex mLock;
- bool mRequestingBuffer = false;
-
- std::vector<HalStreamBuffer> mBufferReqs;
- std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
- // mHalBufferReqs is not under mLock protection during the HIDL transaction
- hidl_vec<BufferRequest> mHalBufferReqs;
-
- // request buffers takes much less time in steady state, but can take much longer
- // when requesting 1st buffer from a stream.
- // TODO: consider a separate timeout for new vs. steady state?
- // TODO: or make sure framework is warming up the pipeline during configure new stream?
- static const int kReqProcTimeoutMs = 66;
-
- static const int kReqWaitTimeoutMs = 33;
- static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec
- std::condition_variable mRequestCond; // signaled when a new buffer request incoming
- std::condition_variable mRequestDoneCond; // signaled when a request is done
- };
-
sp<BufferRequestThread> mBufferRequestThread;
- class OutputThread :
- public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
- public:
- // TODO: pass buffer request thread to OutputThread ctor
- OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType,
- sp<BufferRequestThread> bufReqThread);
- virtual ~OutputThread();
-
- protected:
- // Methods to request output buffer in parallel
- virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
- virtual int waitForBufferRequestDone(
- /*out*/std::vector<HalStreamBuffer>*) override;
-
- const sp<BufferRequestThread> mBufferRequestThread;
- };
-
sp<V3_5::ICameraDeviceCallback> mCallback_3_5;
bool mSupportBufMgr;
@@ -270,4 +272,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp
new file mode 100644
index 0000000..a2ddebd
--- /dev/null
+++ b/camera/device/3.6/default/Android.bp
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_library_headers {
+ name: "camera.device@3.6-external-impl_headers",
+ vendor: true,
+ export_include_dirs: ["include/ext_device_v3_6_impl"]
+}
+
+cc_library_shared {
+ name: "camera.device@3.6-external-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ vendor: true,
+ srcs: [
+ "ExternalCameraDevice.cpp",
+ "ExternalCameraDeviceSession.cpp",
+ "ExternalCameraOfflineSession.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libutils",
+ "libcutils",
+ "camera.device@3.2-impl",
+ "camera.device@3.3-impl",
+ "camera.device@3.4-external-impl",
+ "camera.device@3.5-external-impl",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
+ "android.hardware.camera.device@3.6",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata",
+ "libfmq",
+ "libsync",
+ "libyuv",
+ "libjpeg",
+ "libexif",
+ "libtinyxml2"
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+ local_include_dirs: ["include/ext_device_v3_6_impl"],
+ export_shared_lib_headers: [
+ "libfmq",
+ ],
+}
diff --git a/camera/device/3.6/default/ExternalCameraDevice.cpp b/camera/device/3.6/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..244c7dd
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDevice.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "ExtCamDev@3.6"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice_3_6.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDevice::ExternalCameraDevice(
+ const std::string& cameraId, const ExternalCameraConfig& cfg) :
+ V3_5::implementation::ExternalCameraDevice(cameraId, cfg) {}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+sp<V3_4::implementation::ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+ const sp<V3_2::ICameraDeviceCallback>& cb,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd) {
+ return new ExternalCameraDeviceSession(
+ cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+#define UPDATE(tag, data, size) \
+do { \
+ if (metadata->update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return -EINVAL; \
+ } \
+} while (0)
+
+status_t ExternalCameraDevice::initAvailableCapabilities(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+ status_t res =
+ V3_4::implementation::ExternalCameraDevice::initAvailableCapabilities(metadata);
+
+ if (res != OK) {
+ return res;
+ }
+
+ camera_metadata_entry caps = metadata->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ std::vector<uint8_t> availableCapabilities;
+
+ for (size_t i = 0; i < caps.count; i++) {
+ uint8_t capability = caps.data.u8[i];
+ availableCapabilities.push_back(capability);
+ }
+
+ // Add OFFLINE_PROCESSING capability to device 3.6
+ availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING);
+
+ UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ availableCapabilities.data(),
+ availableCapabilities.size());
+
+ return OK;
+}
+
+#undef UPDATE
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..0cc81bb
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "ExtCamDevSsn@3.6"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+ const sp<V3_2::ICameraDeviceCallback>& callback,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd) :
+ V3_5::implementation::ExternalCameraDeviceSession(
+ callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
+
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_6(
+ const StreamConfiguration& requestedConfiguration,
+ ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb) {
+ V3_2::StreamConfiguration config_v32;
+ V3_3::HalStreamConfiguration outStreams_v33;
+ V3_6::HalStreamConfiguration outStreams;
+ const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4;
+ Mutex::Autolock _il(mInterfaceLock);
+
+ config_v32.operationMode = requestedConfiguration_3_4.operationMode;
+ config_v32.streams.resize(requestedConfiguration_3_4.streams.size());
+ uint32_t blobBufferSize = 0;
+ int numStallStream = 0;
+ for (size_t i = 0; i < config_v32.streams.size(); i++) {
+ config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2;
+ if (config_v32.streams[i].format == PixelFormat::BLOB) {
+ blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize;
+ numStallStream++;
+ }
+ }
+
+ // Fail early if there are multiple BLOB streams
+ if (numStallStream > kMaxStallStream) {
+ ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+ kMaxStallStream, numStallStream);
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
+ return Void();
+ }
+
+ Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
+
+ fillOutputStream3_6(outStreams_v33, &outStreams);
+
+ _hidl_cb(status, outStreams);
+ return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::switchToOffline(
+ const hidl_vec<int32_t>& streamsToKeep,
+ ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
+ std::vector<NotifyMsg> msgs;
+ std::vector<CaptureResult> results;
+ CameraOfflineSessionInfo info;
+ sp<ICameraOfflineSession> session;
+
+ Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
+
+ mCallback->notify(msgs);
+ hidl_vec<CaptureResult> hidlResults(std::move(results));
+ invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(hidlResults);
+
+ _hidl_cb(st, info, session);
+ return Void();
+}
+
+void ExternalCameraDeviceSession::fillOutputStream3_6(
+ const V3_3::HalStreamConfiguration& outStreams_v33,
+ /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
+ if (outStreams_v36 == nullptr) {
+ ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ outStreams_v36->streams.resize(outStreams_v33.streams.size());
+ for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
+ outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
+ outStreams_v36->streams[i].supportOffline =
+ supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
+ }
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+ const Stream& stream = mStreamMap[streamId];
+ if (stream.format == PixelFormat::BLOB &&
+ stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
+ return true;
+ }
+ // TODO: support YUV output stream?
+ return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+ std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
+ for (const auto& buffer : halReq->buffers) {
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ return false;
+ }
+ }
+ }
+ // Only drop a request completely if it has no offline output
+ return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/CameraOfflineSessionInfo* info) {
+ if (info == nullptr) {
+ ALOGE("%s: output info must not be null!", __FUNCTION__);
+ return;
+ }
+
+ info->offlineStreams.resize(offlineStreams.size());
+ info->offlineRequests.resize(offlineReqs.size());
+
+ std::unordered_map<int32_t, uint32_t> outstandingBufs(offlineStreams.size());
+ for (const auto streamId : offlineStreams) {
+ outstandingBufs.insert({streamId, 0});
+ }
+ // Fill in offline reqs and count outstanding buffers
+ for (size_t i = 0; i < offlineReqs.size(); i++) {
+ info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+ info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+ for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+ int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+ info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+ outstandingBufs[streamId]++;
+ }
+ }
+
+ for (size_t i = 0; i < offlineStreams.size(); i++) {
+ int32_t streamId = offlineStreams[i];
+ info->offlineStreams[i].id = streamId;
+ info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId];
+ const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+ info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+ size_t bIdx = 0;
+ for (const auto& pair : bufIdMap) {
+ // Fill in bufferId
+ info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+ }
+
+ }
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+ /*out*/std::vector<NotifyMsg>* msgs,
+ /*out*/std::vector<CaptureResult>* results,
+ /*out*/CameraOfflineSessionInfo* info,
+ /*out*/sp<ICameraOfflineSession>* session) {
+ ATRACE_CALL();
+ if (offlineStreams.size() > 1) {
+ ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+ ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
+ msgs, results, info, session);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ msgs->clear();
+ results->clear();
+
+ Mutex::Autolock _il(mInterfaceLock);
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return status;
+ }
+
+ Mutex::Autolock _l(mLock);
+ for (auto streamId : offlineStreams) {
+ if (!supportOfflineLocked(streamId)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ // pause output thread and get all remaining inflight requests
+ auto remainingReqs = mOutputThread->switchToOffline();
+ std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
+
+ // Send out buffer/request error for remaining requests and filter requests
+ // to be handled in offline mode
+ for (auto& halReq : remainingReqs) {
+ bool dropReq = canDropRequest(offlineStreams, halReq);
+ if (dropReq) {
+ // Request is dropped completely. Just send request error and
+ // there is no need to send the request to offline session
+ processCaptureRequestError(halReq, msgs, results);
+ continue;
+ }
+
+ // All requests reach here must have at least one offline stream output
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = halReq->frameNumber;
+ shutter.msg.shutter.timestamp = halReq->shutterTs;
+ msgs->push_back(shutter);
+
+ std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
+ for (const auto& buffer : halReq->buffers) {
+ bool dropBuffer = true;
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ dropBuffer = false;
+ break;
+ }
+ }
+ if (dropBuffer) {
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = halReq->frameNumber;
+ error.msg.error.errorStreamId = buffer.streamId;
+ error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
+ msgs->push_back(error);
+
+ CaptureResult result;
+ result.frameNumber = halReq->frameNumber;
+ result.partialResult = 0; // buffer only result
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(1);
+ result.outputBuffers[0].streamId = buffer.streamId;
+ result.outputBuffers[0].bufferId = buffer.bufferId;
+ result.outputBuffers[0].status = BufferStatus::ERROR;
+ if (buffer.acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = buffer.acquireFence;
+ result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ results->push_back(result);
+ } else {
+ offlineBuffers.push_back(buffer);
+ }
+ }
+ halReq->buffers = offlineBuffers;
+ halReqs.push_back(halReq);
+ }
+
+ // convert hal requests to offline request
+ std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+ for (auto& v4lReq : halReqs) {
+ std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+ halReq->frameNumber = v4lReq->frameNumber;
+ halReq->setting = v4lReq->setting;
+ halReq->shutterTs = v4lReq->shutterTs;
+ halReq->buffers = v4lReq->buffers;
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
+ halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+ offlineReqs.push_back(halReq);
+ // enqueue V4L2 frame
+ enqueueV4l2Frame(v4l2Frame);
+ }
+
+ // Collect buffer caches/streams
+ hidl_vec<Stream> streamInfos;
+ streamInfos.resize(offlineStreams.size());
+ std::map<int, CirculatingBuffers> circulatingBuffers;
+ {
+ Mutex::Autolock _l(mCbsLock);
+ size_t idx = 0;
+ for(auto streamId : offlineStreams) {
+ circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+ mCirculatingBuffers.erase(streamId);
+ streamInfos[idx++] = mStreamMap.at(streamId);
+ mStreamMap.erase(streamId);
+ }
+ }
+
+ fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+
+ // create the offline session object
+ bool afTrigger;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ }
+ sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
+ mCroppingType, mCameraCharacteristics, mCameraId,
+ mExifMake, mExifModel, mBlobBufferSize, afTrigger,
+ streamInfos, offlineReqs, circulatingBuffers);
+
+ bool initFailed = sessionImpl->initialize();
+ if (initFailed) {
+ ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ // cleanup stream and buffer caches
+ {
+ Mutex::Autolock _l(mCbsLock);
+ for(auto pair : mStreamMap) {
+ cleanupBuffersLocked(/*Stream ID*/pair.first);
+ }
+ mCirculatingBuffers.clear();
+ }
+ mStreamMap.clear();
+
+ // update inflight records
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ mInflightFrames.clear();
+ }
+
+ // stop v4l2 streaming
+ if (v4l2StreamOffLocked() !=0) {
+ ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ *session = sessionImpl->getInterface();
+ return Status::OK;
+}
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000..e606fda
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "ExtCamOfflnSsn@3.6"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#include <android/log.h>
+
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+} // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+// static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+using V3_5::implementation::ExternalCameraDeviceSession;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ const std::string& exifMake,
+ const std::string& exifModel,
+ const uint32_t blobBufferSize,
+ const bool afTrigger,
+ const hidl_vec<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers) :
+ mCroppingType(croppingType), mChars(chars), mCameraId(cameraId),
+ mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize),
+ mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs),
+ mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+ close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+ mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
+ kMetadataMsgQueueSize, false /* non blocking */);
+ if (!mResultMetadataQueue->isValid()) {
+ ALOGE("%s: invalid result fmq", __FUNCTION__);
+ return true;
+ }
+ return false;
+}
+
+void ExternalCameraOfflineSession::initOutputThread() {
+ if (mOutputThread != nullptr) {
+ ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+ return;
+ }
+
+ mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread(
+ this, mCallback);
+ mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
+
+ mOutputThread = new OutputThread(this, mCroppingType, mChars,
+ mBufferRequestThread, mOfflineReqs);
+
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+ Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+ Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars);
+ mOutputThread->allocateIntermediateBuffers(
+ inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize);
+
+ mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return false;
+ }
+
+ if (mOfflineReqs.empty()) {
+ ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+ return false;
+ }
+
+ std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+ mOfflineReqs.pop_front();
+
+ auto onDeviceError = [&](auto... args) {
+ ALOGE(args...);
+ parent->notifyError(
+ req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+ signalRequestDone();
+ return false;
+ };
+
+ if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+ return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+ req->frameIn->mFourcc & 0xFF,
+ (req->frameIn->mFourcc >> 8) & 0xFF,
+ (req->frameIn->mFourcc >> 16) & 0xFF,
+ (req->frameIn->mFourcc >> 24) & 0xFF);
+ }
+
+ int res = requestBufferStart(req->buffers);
+ if (res != 0) {
+ ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+ return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+ }
+
+ std::unique_lock<std::mutex> lk(mBufferLock);
+ // Convert input V4L2 frame to YU12 of the same size
+ // TODO: see if we can save some computation by converting to YV12 here
+ uint8_t* inData;
+ size_t inDataSize;
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+ lk.unlock();
+ return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+ }
+
+ // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+ if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+ ATRACE_BEGIN("MJPGtoI420");
+ int res = libyuv::MJPGToI420(
+ inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride,
+ mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight);
+ ATRACE_END();
+
+ if (res != 0) {
+ // For some webcam, the first few V4L2 frames might be malformed...
+ ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ Status st = parent->processCaptureRequestError(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+ }
+ }
+
+ ATRACE_BEGIN("Wait for BufferRequest done");
+ res = waitForBufferRequestDone(&req->buffers);
+ ATRACE_END();
+
+ if (res != 0) {
+ ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+ }
+
+ ALOGV("%s processing new request", __FUNCTION__);
+ const int kSyncWaitTimeoutMs = 500;
+ for (auto& halBuf : req->buffers) {
+ if (*(halBuf.bufPtr) == nullptr) {
+ ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+ halBuf.fenceTimeout = true;
+ } else if (halBuf.acquireFence >= 0) {
+ int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+ if (ret) {
+ halBuf.fenceTimeout = true;
+ } else {
+ ::close(halBuf.acquireFence);
+ halBuf.acquireFence = -1;
+ }
+ }
+
+ if (halBuf.fenceTimeout) {
+ continue;
+ }
+
+ // Gralloc lockYCbCr the buffer
+ switch (halBuf.format) {
+ case PixelFormat::BLOB: {
+ int ret = createJpegLocked(halBuf, req->setting);
+
+ if(ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: createJpegLocked failed with %d",
+ __FUNCTION__, ret);
+ }
+ } break;
+ case PixelFormat::Y16: {
+ void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize);
+
+ std::memcpy(outLayout, inData, inDataSize);
+
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12: {
+ IMapper::Rect outRect {0, 0,
+ static_cast<int32_t>(halBuf.width),
+ static_cast<int32_t>(halBuf.height)};
+ YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+ *(halBuf.bufPtr), halBuf.usage, outRect);
+ ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+ __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+ outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+
+ // Convert to output buffer size/format
+ uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
+ ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__,
+ outputFourcc & 0xFF,
+ (outputFourcc >> 8) & 0xFF,
+ (outputFourcc >> 16) & 0xFF,
+ (outputFourcc >> 24) & 0xFF);
+
+ YCbCrLayout cropAndScaled;
+ ATRACE_BEGIN("cropAndScaleLocked");
+ int ret = cropAndScaleLocked(
+ mYu12Frame,
+ Size { halBuf.width, halBuf.height },
+ &cropAndScaled);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+ }
+
+ Size sz {halBuf.width, halBuf.height};
+ ATRACE_BEGIN("formatConvert");
+ ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+ }
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ default:
+ lk.unlock();
+ return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+ }
+ } // for each buffer
+ mScaledYu12Frames.clear();
+
+ // Don't hold the lock while calling back to parent
+ lk.unlock();
+ Status st = parent->processCaptureResult(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) {
+ Mutex::Autolock _l(mCbsLock);
+ return V3_4::implementation::importBufferImpl(
+ mCirculatingBuffers, sHandleImporter, streamId,
+ bufId, buf, outBufPtr, allowEmptyBuf);
+ return Status::OK;
+};
+
+#define UPDATE(md, tag, data, size) \
+do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+} while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(
+ common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
+ bool afTrigger = false;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+ camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+ if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+ mAfTrigger = afTrigger = true;
+ } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+ mAfTrigger = afTrigger = false;
+ }
+ }
+ }
+
+ // For USB camera, the USB camera handles everything and we don't have control
+ // over AF. We only simply fake the AF metadata based on the request
+ // received here.
+ uint8_t afState;
+ if (afTrigger) {
+ afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+ } else {
+ afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ }
+ UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+ camera_metadata_ro_entry activeArraySize =
+ mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+ return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+#undef UPDATE
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+ ATRACE_CALL();
+ // Fill output buffers
+ hidl_vec<CaptureResult> results;
+ results.resize(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ if (req->buffers[i].fenceTimeout) {
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+ } else {
+ result.outputBuffers[i].status = BufferStatus::OK;
+ // TODO: refactor
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ }
+ }
+
+ // Fill capture result metadata
+ fillCaptureResult(req->setting, req->shutterTs);
+ const camera_metadata_t *rawResult = req->setting.getAndLock();
+ V3_2::implementation::convertToHidl(rawResult, &result.result);
+ req->setting.unlock(rawResult);
+
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(results);
+ return Status::OK;
+};
+
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+ hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ const nsecs_t NS_TO_SECOND = 1000000000;
+ ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+ __FUNCTION__);
+ return;
+ }
+ }
+ if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+ for (CaptureResult &result : results) {
+ if (result.result.size() > 0) {
+ if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+ result.fmqResultSize = result.result.size();
+ result.result.resize(0);
+ } else {
+ ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+ result.fmqResultSize = 0;
+ }
+ } else {
+ result.fmqResultSize = 0;
+ }
+ }
+ }
+ auto status = mCallback->processCaptureResult(results);
+ if (!status.isOk()) {
+ ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__,
+ status.description().c_str());
+ }
+
+ mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+ const std::shared_ptr<HalRequest>& req,
+ /*out*/std::vector<NotifyMsg>* outMsgs,
+ /*out*/std::vector<CaptureResult>* outResults) {
+ ATRACE_CALL();
+
+ if (outMsgs == nullptr) {
+ notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = req->frameNumber;
+ shutter.msg.shutter.timestamp = req->shutterTs;
+
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = req->frameNumber;
+ error.msg.error.errorStreamId = -1;
+ error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
+
+ // Fill output buffers
+ hidl_vec<CaptureResult> results;
+ results.resize(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ }
+
+ if (outResults == nullptr) {
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(results);
+ } else {
+ outResults->push_back(result);
+ }
+ return Status::OK;
+};
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(
+ uint32_t /*width*/, uint32_t /*height*/) const {
+ // Empty implementation here as the jpeg buffer size is passed in by ctor
+ return 0;
+};
+
+void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) {
+ NotifyMsg msg;
+ msg.type = MsgType::ERROR;
+ msg.msg.error.frameNumber = frameNumber;
+ msg.msg.error.errorStreamId = streamId;
+ msg.msg.error.errorCode = ec;
+ mCallback->notify({msg});
+};
+
+Return<void> ExternalCameraOfflineSession::setCallback(const sp<ICameraDeviceCallback>& cb) {
+ Mutex::Autolock _il(mInterfaceLock);
+ if (mCallback != nullptr && cb != nullptr) {
+ ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+ return Void();
+ }
+ mCallback = cb;
+
+ initOutputThread();
+
+ if (mOutputThread == nullptr) {
+ ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+ }
+ return Void();
+}
+
+Return<void> ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) {
+ Mutex::Autolock _il(mInterfaceLock);
+ _hidl_cb(*mResultMetadataQueue->getDesc());
+ return Void();
+}
+
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) {
+ for (auto& pair : mCirculatingBuffers.at(id)) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers[id].clear();
+ mCirculatingBuffers.erase(id);
+}
+
+Return<void> ExternalCameraOfflineSession::close() {
+ Mutex::Autolock _il(mInterfaceLock);
+ {
+ Mutex::Autolock _l(mLock);
+ if (mClosed) {
+ ALOGW("%s: offline session already closed!", __FUNCTION__);
+ return Void();
+ }
+ }
+ if (mBufferRequestThread) {
+ mBufferRequestThread->requestExit();
+ mBufferRequestThread->join();
+ mBufferRequestThread.clear();
+ }
+ if (mOutputThread) {
+ mOutputThread->flush();
+ mOutputThread->requestExit();
+ mOutputThread->join();
+ mOutputThread.clear();
+ }
+
+ Mutex::Autolock _l(mLock);
+ // free all buffers
+ {
+ Mutex::Autolock _cbl(mCbsLock);
+ for(auto stream : mOfflineStreams) {
+ cleanupBuffersLocked(stream.id);
+ }
+ }
+ mCallback.clear();
+ mClosed = true;
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.6/default/OWNERS b/camera/device/3.6/default/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/camera/device/3.6/default/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..db0d9a5
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2020 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+
+struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCameraDeviceSession {
+
+ ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback>&,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd);
+ virtual ~ExternalCameraDeviceSession();
+
+ // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+ // dealing with minor version revs and simultaneous implementation and interface inheritance
+ virtual sp<V3_4::ICameraDeviceSession> getInterface() override {
+ return new TrampolineSessionInterface_3_6(this);
+ }
+
+protected:
+ // Methods from v3.5 and earlier will trampoline to inherited implementation
+ Return<void> configureStreams_3_6(
+ const StreamConfiguration& requestedConfiguration,
+ ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb);
+
+ Return<void> switchToOffline(
+ const hidl_vec<int32_t>& streamsToKeep,
+ ICameraDeviceSession::switchToOffline_cb _hidl_cb);
+
+ void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33,
+ /*out*/V3_6::HalStreamConfiguration* outStreams_v36);
+ bool supportOfflineLocked(int32_t streamId);
+
+ // Main body of switchToOffline. This method does not invoke any callbacks
+ // but instead returns the necessary callbacks in output arguments so callers
+ // can callback later without holding any locks
+ Status switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+ /*out*/std::vector<NotifyMsg>* msgs,
+ /*out*/std::vector<CaptureResult>* results,
+ /*out*/CameraOfflineSessionInfo* info,
+ /*out*/sp<ICameraOfflineSession>* session);
+
+ // Whether a request can be completely dropped when switching to offline
+ bool canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+ std::shared_ptr<V3_4::implementation::HalRequest> halReq);
+
+ void fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/CameraOfflineSessionInfo* info);
+
+private:
+
+ struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession {
+ TrampolineSessionInterface_3_6(sp<ExternalCameraDeviceSession> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> constructDefaultRequestSettings(
+ RequestTemplate type,
+ V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+ return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams(
+ const V3_2::StreamConfiguration& requestedConfiguration,
+ V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+ return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+ const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+ V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+ return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+ }
+
+ virtual Return<void> getCaptureRequestMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<Status> flush() override {
+ return mParent->flush();
+ }
+
+ virtual Return<void> close() override {
+ return mParent->close();
+ }
+
+ virtual Return<void> configureStreams_3_3(
+ const V3_2::StreamConfiguration& requestedConfiguration,
+ configureStreams_3_3_cb _hidl_cb) override {
+ return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_4(
+ const V3_4::StreamConfiguration& requestedConfiguration,
+ configureStreams_3_4_cb _hidl_cb) override {
+ return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+ const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+ ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+ return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_5(
+ const StreamConfiguration& requestedConfiguration,
+ configureStreams_3_5_cb _hidl_cb) override {
+ return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> signalStreamFlush(
+ const hidl_vec<int32_t>& requests,
+ uint32_t streamConfigCounter) override {
+ return mParent->signalStreamFlush(requests, streamConfigCounter);
+ }
+
+ virtual Return<void> isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams,
+ const V3_2::CameraMetadata& newSessionParams,
+ ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override {
+ return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_6(
+ const StreamConfiguration& requestedConfiguration,
+ configureStreams_3_6_cb _hidl_cb) override {
+ return mParent->configureStreams_3_6(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> switchToOffline(
+ const hidl_vec<int32_t>& streamsToKeep,
+ switchToOffline_cb _hidl_cb) override {
+ return mParent->switchToOffline(streamsToKeep, _hidl_cb);
+ }
+
+ private:
+ sp<ExternalCameraDeviceSession> mParent;
+ };
+};
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
new file mode 100644
index 0000000..046c9d8
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+
+#include "ExternalCameraDeviceSession.h"
+#include <../../../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_5::ICameraDevice;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct ExternalCameraDevice : public V3_5::implementation::ExternalCameraDevice {
+
+ // Called by external camera provider HAL.
+ // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+ // be multiple CameraDevice trying to access the same physical camera. Also, provider will have
+ // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+ // camera is detached.
+ ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
+ virtual ~ExternalCameraDevice();
+
+protected:
+ virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession(
+ const sp<V3_2::ICameraDeviceCallback>&,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd) override;
+
+ virtual status_t initAvailableCapabilities(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override;
+};
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000..230b67c
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2020 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+#include <android/hardware/camera/common/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <deque>
+#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include <HandleImporter.h>
+#include <Exif.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_5::BufferRequest;
+using ::android::hardware::camera::device::V3_5::BufferRequestStatus;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers;
+using ::android::hardware::camera::device::V3_4::implementation::HalRequest;
+using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface;
+
+struct ExternalCameraOfflineSession : public virtual RefBase,
+ public virtual OutputThreadInterface {
+
+ ExternalCameraOfflineSession(
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ const std::string& exifMake,
+ const std::string& exifModel,
+ uint32_t blobBufferSize,
+ bool afTrigger,
+ const hidl_vec<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+ bool initialize();
+
+ virtual ~ExternalCameraOfflineSession();
+
+ // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+ // dealing with minor version revs and simultaneous implementation and interface inheritance
+ virtual sp<V3_6::ICameraOfflineSession> getInterface() {
+ return new TrampolineSessionInterface_3_6(this);
+ }
+
+protected:
+
+ // Methods from OutputThreadInterface
+ virtual Status importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) override;
+
+ virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+ virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+ // End of OutputThreadInterface methods
+
+ class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread {
+ public:
+ OutputThread(
+ wp<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
+ sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs) :
+ V3_5::implementation::ExternalCameraDeviceSession::OutputThread(
+ parent, ct, chars, bufReqThread),
+ mOfflineReqs(offlineReqs) {}
+
+ virtual bool threadLoop() override;
+
+ protected:
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+ }; // OutputThread
+
+
+ Return<void> setCallback(const sp<ICameraDeviceCallback>& cb);
+
+ Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb);
+
+ Return<void> close();
+
+ void initOutputThread();
+
+ void invokeProcessCaptureResultCallback(
+ hidl_vec<CaptureResult> &results, bool tryWriteFmq);
+
+ status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+
+ void cleanupBuffersLocked(int id);
+
+ // Protect (most of) HIDL interface methods from synchronized-entering
+ mutable Mutex mInterfaceLock;
+
+ mutable Mutex mLock; // Protect all data members except otherwise noted
+
+ bool mClosed = false;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mChars;
+ const std::string mCameraId;
+ const std::string mExifMake;
+ const std::string mExifModel;
+ const uint32_t mBlobBufferSize;
+
+ std::mutex mAfTriggerLock; // protect mAfTrigger
+ bool mAfTrigger;
+
+ const hidl_vec<Stream> mOfflineStreams;
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+ // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+ mutable Mutex mCbsLock;
+ std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+ static HandleImporter sHandleImporter;
+
+ using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+ std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ // Protect against invokeProcessCaptureResultCallback()
+ Mutex mProcessCaptureResultLock;
+
+ sp<ICameraDeviceCallback> mCallback;
+
+ sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+ sp<OutputThread> mOutputThread;
+private:
+
+ struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession {
+ TrampolineSessionInterface_3_6(sp<ExternalCameraOfflineSession> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> setCallback(const sp<ICameraDeviceCallback>& cb) override {
+ return mParent->setCallback(cb);
+ }
+
+ virtual Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<void> close() override {
+ return mParent->close();
+ }
+
+ private:
+ sp<ExternalCameraOfflineSession> mParent;
+ };
+};
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index 9203b8d..627ddf4 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -49,6 +49,7 @@
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
"android.hardware.camera.device@3.5",
+ "android.hardware.camera.device@3.6",
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
@@ -60,6 +61,7 @@
"camera.device@3.4-impl",
"camera.device@3.5-external-impl",
"camera.device@3.5-impl",
+ "camera.device@3.6-external-impl",
"libcamera_metadata",
"libcutils",
"libhardware",
@@ -73,7 +75,8 @@
],
header_libs: [
"camera.device@3.4-external-impl_headers",
- "camera.device@3.5-external-impl_headers"
+ "camera.device@3.5-external-impl_headers",
+ "camera.device@3.6-external-impl_headers"
],
export_include_dirs: ["."],
}
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index a6fd288..2bfced2 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -26,6 +26,7 @@
#include "ExternalCameraProviderImpl_2_4.h"
#include "ExternalCameraDevice_3_4.h"
#include "ExternalCameraDevice_3_5.h"
+#include "ExternalCameraDevice_3_6.h"
namespace android {
namespace hardware {
@@ -73,6 +74,7 @@
switch(mPreferredHal3MinorVersion) {
case 4:
case 5:
+ case 6:
// OK
break;
default:
@@ -171,6 +173,12 @@
cameraId, mCfg);
break;
}
+ case 6: {
+ ALOGV("Constructing v3.6 external camera device");
+ deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
+ cameraId, mCfg);
+ break;
+ }
default:
ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
@@ -202,7 +210,9 @@
ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
Mutex::Autolock _l(mLock);
std::string deviceName;
- if (mPreferredHal3MinorVersion == 5) {
+ if (mPreferredHal3MinorVersion == 6) {
+ deviceName = std::string("device@3.6/external/") + devName;
+ } else if (mPreferredHal3MinorVersion == 5) {
deviceName = std::string("device@3.5/external/") + devName;
} else {
deviceName = std::string("device@3.4/external/") + devName;
@@ -249,7 +259,9 @@
void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
Mutex::Autolock _l(mLock);
std::string deviceName;
- if (mPreferredHal3MinorVersion == 5) {
+ if (mPreferredHal3MinorVersion == 6) {
+ deviceName = std::string("device@3.6/external/") + devName;
+ } else if (mPreferredHal3MinorVersion == 5) {
deviceName = std::string("device@3.5/external/") + devName;
} else {
deviceName = std::string("device@3.4/external/") + devName;
diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp
index 4563362..67eb7ca 100644
--- a/camera/provider/2.5/default/Android.bp
+++ b/camera/provider/2.5/default/Android.bp
@@ -52,6 +52,8 @@
"android.hardware.camera.provider@2.4-external",
"android.hardware.camera.provider@2.5",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@3.3-impl",
@@ -72,7 +74,8 @@
],
header_libs: [
"camera.device@3.4-external-impl_headers",
- "camera.device@3.5-external-impl_headers"
+ "camera.device@3.5-external-impl_headers",
+ "camera.device@3.6-external-impl_headers"
],
export_include_dirs: ["."],
}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index aac31af..9a8f336 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -45,6 +45,7 @@
<interface>
<name>IEvsEnumerator</name>
<instance>default</instance>
+ <regex-instance>[a-z]+/[0-9]+</regex-instance>
</interface>
</hal>
<hal format="aidl" optional="true">