Camera: support libhardware camera device 3.6
Add buffer management API support.
Test: VTS to be written. Need Pixel device impl to verify.
Bug: 120986771
Change-Id: Icdbc621f8cd17aa0868d3ac361867c44793a268c
diff --git a/camera/device/3.5/default/CameraDeviceSession.cpp b/camera/device/3.5/default/CameraDeviceSession.cpp
index 963893a..0770f04 100644
--- a/camera/device/3.5/default/CameraDeviceSession.cpp
+++ b/camera/device/3.5/default/CameraDeviceSession.cpp
@@ -15,8 +15,10 @@
*/
#define LOG_TAG "CamDevSession@3.5-impl"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
#include <android/log.h>
+#include <vector>
#include <utils/Trace.h>
#include "CameraDeviceSession.h"
@@ -33,13 +35,26 @@
const sp<V3_2::ICameraDeviceCallback>& callback) :
V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) {
- mHasCallback_3_5 = false;
+ mCallback_3_5 = nullptr;
auto castResult = ICameraDeviceCallback::castFrom(callback);
if (castResult.isOk()) {
sp<ICameraDeviceCallback> callback3_5 = castResult;
if (callback3_5 != nullptr) {
- mHasCallback_3_5 = true;
+ mCallback_3_5 = callback3_5;
+ }
+ }
+
+ if (mCallback_3_5 != nullptr) {
+ camera_metadata_entry bufMgrVersion = mDeviceInfo.find(
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
+ if (bufMgrVersion.count > 0) {
+ mSupportBufMgr = (bufMgrVersion.data.u8[0] ==
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+ if (mSupportBufMgr) {
+ request_stream_buffers = sRequestStreamBuffers;
+ return_stream_buffers = sReturnStreamBuffers;
+ }
}
}
}
@@ -50,14 +65,297 @@
Return<void> CameraDeviceSession::configureStreams_3_5(
const StreamConfiguration& requestedConfiguration,
ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) {
- return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb);
+ configureStreams_3_4_Impl(requestedConfiguration.v3_4, _hidl_cb,
+ requestedConfiguration.streamConfigCounter);
+ return Void();
}
Return<void> CameraDeviceSession::signalStreamFlush(
- const hidl_vec<int32_t>& /*requests*/, uint32_t /*streamConfigCounter*/) {
+ const hidl_vec<int32_t>& streamIds, uint32_t streamConfigCounter) {
+ std::vector<camera3_stream_t*> streams(streamIds.size());
+ {
+ Mutex::Autolock _l(mInflightLock);
+ for (size_t i = 0; i < streamIds.size(); i++) {
+ int32_t id = streamIds[i];
+ if (mStreamMap.count(id) == 0) {
+ ALOGE("%s: unknown streamId %d", __FUNCTION__, id);
+ return Void();
+ }
+ streams[i] = &mStreamMap[id];
+ }
+ }
+ if (mDevice->ops->signal_stream_flush != nullptr) {
+ mDevice->ops->signal_stream_flush(mDevice,
+ streamConfigCounter, streams.size(), streams.data());
+ }
return Void();
}
+Status CameraDeviceSession::importRequest(
+ const CaptureRequest& request,
+ hidl_vec<buffer_handle_t*>& allBufPtrs,
+ hidl_vec<int>& allFences) {
+ if (mSupportBufMgr) {
+ return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true);
+ }
+ return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false);
+}
+
+void CameraDeviceSession::pushBufferId(
+ const buffer_handle_t& buf, uint64_t bufferId, int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+ // emplace will return existing entry if there is one.
+ auto pair = mBufferIdMaps.emplace(streamId, BufferIdMap{});
+ BufferIdMap& bIdMap = pair.first->second;
+ bIdMap[buf] = bufferId;
+}
+
+uint64_t CameraDeviceSession::popBufferId(
+ const buffer_handle_t& buf, int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+ auto streamIt = mBufferIdMaps.find(streamId);
+ if (streamIt == mBufferIdMaps.end()) {
+ return BUFFER_ID_NO_BUFFER;
+ }
+ BufferIdMap& bIdMap = streamIt->second;
+ auto it = bIdMap.find(buf);
+ if (it == bIdMap.end()) {
+ return BUFFER_ID_NO_BUFFER;
+ }
+ uint64_t bufId = it->second;
+ bIdMap.erase(it);
+ if (bIdMap.empty()) {
+ mBufferIdMaps.erase(streamIt);
+ }
+ return bufId;
+}
+
+uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t& buf, int streamId) {
+ if (mSupportBufMgr) {
+ return popBufferId(buf, streamId);
+ }
+ return BUFFER_ID_NO_BUFFER;
+}
+
+Camera3Stream* CameraDeviceSession::getStreamPointer(int32_t streamId) {
+ Mutex::Autolock _l(mInflightLock);
+ if (mStreamMap.count(streamId) == 0) {
+ ALOGE("%s: unknown streamId %d", __FUNCTION__, streamId);
+ return nullptr;
+ }
+ return &mStreamMap[streamId];
+}
+
+void CameraDeviceSession::cleanupInflightBufferFences(
+ std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs) {
+ hidl_vec<int> hFences = fences;
+ cleanupInflightFences(hFences, fences.size());
+ for (auto& p : bufs) {
+ popBufferId(p.first, p.second);
+ }
+}
+
+camera3_buffer_request_status_t CameraDeviceSession::requestStreamBuffers(
+ uint32_t num_buffer_reqs,
+ const camera3_buffer_request_t *buffer_reqs,
+ /*out*/uint32_t *num_returned_buf_reqs,
+ /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) {
+ ATRACE_CALL();
+ *num_returned_buf_reqs = 0;
+ hidl_vec<BufferRequest> hBufReqs(num_buffer_reqs);
+ for (size_t i = 0; i < num_buffer_reqs; i++) {
+ hBufReqs[i].streamId =
+ static_cast<Camera3Stream*>(buffer_reqs[i].stream)->mId;
+ hBufReqs[i].numBuffersRequested = buffer_reqs[i].num_buffers_requested;
+ }
+
+ ATRACE_BEGIN("HIDL requestStreamBuffers");
+ BufferRequestStatus status;
+ hidl_vec<StreamBufferRet> bufRets;
+ auto err = mCallback_3_5->requestStreamBuffers(hBufReqs,
+ [&status, &bufRets]
+ (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) {
+ status = s;
+ bufRets = std::move(rets);
+ });
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+ ATRACE_END();
+
+ if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) {
+ if (bufRets.size() != num_buffer_reqs) {
+ ALOGE("%s: expect %d buffer requests returned, only got %zu",
+ __FUNCTION__, num_buffer_reqs, bufRets.size());
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+
+ for (size_t i = 0; i < num_buffer_reqs; i++) {
+ // maybe we can query all streams in one call to avoid frequent locking device here?
+ Camera3Stream* stream = getStreamPointer(bufRets[i].streamId);
+ if (stream == nullptr) {
+ ALOGE("%s: unknown streamId %d", __FUNCTION__, bufRets[i].streamId);
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+ returned_buf_reqs[i].stream = stream;
+ }
+
+ std::vector<int> importedFences;
+ std::vector<std::pair<buffer_handle_t, int>> importedBuffers;
+ for (size_t i = 0; i < num_buffer_reqs; i++) {
+ int streamId = bufRets[i].streamId;
+ switch (bufRets[i].val.getDiscriminator()) {
+ case StreamBuffersVal::hidl_discriminator::error:
+ returned_buf_reqs[i].num_output_buffers = 0;
+ switch (bufRets[i].val.error()) {
+ case StreamBufferRequestError::NO_BUFFER_AVAILABLE:
+ returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_NO_BUFFER_AVAILABLE;
+ break;
+ case StreamBufferRequestError::MAX_BUFFER_EXCEEDED:
+ returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_MAX_BUFFER_EXCEEDED;
+ break;
+ case StreamBufferRequestError::STREAM_DISCONNECTED:
+ returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_STREAM_DISCONNECTED;
+ break;
+ case StreamBufferRequestError::UNKNOWN_ERROR:
+ returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_UNKNOWN_ERROR;
+ break;
+ default:
+ ALOGE("%s: Unknown StreamBufferRequestError %d",
+ __FUNCTION__, bufRets[i].val.error());
+ cleanupInflightBufferFences(importedFences, importedBuffers);
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+ break;
+ case StreamBuffersVal::hidl_discriminator::buffers: {
+ const hidl_vec<StreamBuffer>& hBufs = bufRets[i].val.buffers();
+ camera3_stream_buffer_t* outBufs = returned_buf_reqs[i].output_buffers;
+ for (size_t b = 0; b < hBufs.size(); b++) {
+ const StreamBuffer& hBuf = hBufs[b];
+ camera3_stream_buffer_t& outBuf = outBufs[b];
+ // maybe add importBuffers API to avoid frequent locking device?
+ Status s = importBuffer(streamId,
+ hBuf.bufferId, hBuf.buffer.getNativeHandle(),
+ /*out*/&(outBuf.buffer),
+ /*allowEmptyBuf*/false);
+ if (s != Status::OK) {
+ ALOGE("%s: import stream %d bufferId %" PRIu64 " failed!",
+ __FUNCTION__, streamId, hBuf.bufferId);
+ cleanupInflightBufferFences(importedFences, importedBuffers);
+ // Buffer import should never fail - restart HAL since something is very
+ // wrong.
+ assert(false);
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+
+ pushBufferId(*(outBuf.buffer), hBuf.bufferId, streamId);
+ importedBuffers.push_back(std::make_pair(*(outBuf.buffer), streamId));
+
+ if (!sHandleImporter.importFence(
+ hBuf.acquireFence,
+ outBuf.acquire_fence)) {
+ ALOGE("%s: stream %d bufferId %" PRIu64 "acquire fence is invalid",
+ __FUNCTION__, streamId, hBuf.bufferId);
+ cleanupInflightBufferFences(importedFences, importedBuffers);
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+ importedFences.push_back(outBuf.acquire_fence);
+ outBuf.stream = returned_buf_reqs[i].stream;
+ outBuf.status = CAMERA3_BUFFER_STATUS_OK;
+ outBuf.release_fence = -1;
+ }
+ returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_OK;
+ } break;
+ default:
+ ALOGE("%s: unknown StreamBuffersVal discrimator!", __FUNCTION__);
+ cleanupInflightBufferFences(importedFences, importedBuffers);
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+ }
+
+ *num_returned_buf_reqs = num_buffer_reqs;
+
+ return (status == BufferRequestStatus::OK) ?
+ CAMERA3_BUF_REQ_OK : CAMERA3_BUF_REQ_FAILED_PARTIAL;
+ }
+
+ switch (status) {
+ case BufferRequestStatus::FAILED_CONFIGURING:
+ return CAMERA3_BUF_REQ_FAILED_CONFIGURING;
+ case BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS:
+ return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS;
+ case BufferRequestStatus::FAILED_UNKNOWN:
+ default:
+ return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+ }
+}
+
+void CameraDeviceSession::returnStreamBuffers(
+ uint32_t num_buffers,
+ const camera3_stream_buffer_t* const* buffers) {
+ ATRACE_CALL();
+ hidl_vec<StreamBuffer> hBufs(num_buffers);
+
+ for (size_t i = 0; i < num_buffers; i++) {
+ hBufs[i].streamId =
+ static_cast<Camera3Stream*>(buffers[i]->stream)->mId;
+ hBufs[i].buffer = nullptr; // use bufferId
+ hBufs[i].bufferId = popBufferId(*(buffers[i]->buffer), hBufs[i].streamId);
+ if (hBufs[i].bufferId == BUFFER_ID_NO_BUFFER) {
+ ALOGE("%s: unknown buffer is returned to stream %d",
+ __FUNCTION__, hBufs[i].streamId);
+ }
+ // ERROR since the buffer is not for application to consume
+ hBufs[i].status = BufferStatus::ERROR;
+ // skip acquire fence since it's of no use to camera service
+ if (buffers[i]->release_fence != -1) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = buffers[i]->release_fence;
+ hBufs[i].releaseFence.setTo(handle, /*shouldOwn*/true);
+ }
+ }
+
+ mCallback_3_5->returnStreamBuffers(hBufs);
+ return;
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+camera3_buffer_request_status_t CameraDeviceSession::sRequestStreamBuffers(
+ const struct camera3_callback_ops *cb,
+ uint32_t num_buffer_reqs,
+ const camera3_buffer_request_t *buffer_reqs,
+ /*out*/uint32_t *num_returned_buf_reqs,
+ /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) {
+ CameraDeviceSession *d =
+ const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+ if (num_buffer_reqs == 0 || buffer_reqs == nullptr || num_returned_buf_reqs == nullptr ||
+ returned_buf_reqs == nullptr) {
+ ALOGE("%s: bad argument: numBufReq %d, bufReqs %p, numRetBufReq %p, retBufReqs %p",
+ __FUNCTION__, num_buffer_reqs, buffer_reqs,
+ num_returned_buf_reqs, returned_buf_reqs);
+ return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS;
+ }
+
+ return d->requestStreamBuffers(num_buffer_reqs, buffer_reqs,
+ num_returned_buf_reqs, returned_buf_reqs);
+}
+
+void CameraDeviceSession::sReturnStreamBuffers(
+ const struct camera3_callback_ops *cb,
+ uint32_t num_buffers,
+ const camera3_stream_buffer_t* const* buffers) {
+ CameraDeviceSession *d =
+ const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+ d->returnStreamBuffers(num_buffers, buffers);
+}
+
} // namespace implementation
} // namespace V3_5
} // namespace device