| /* |
| * Copyright (C) 2013-2017 Intel Corporation |
| * |
| * 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 "Request" |
| |
| #include "LogHelper.h" |
| #include "PerformanceTraces.h" |
| #include "CameraStream.h" |
| #include "Camera3Request.h" |
| #include "PlatformData.h" |
| |
| namespace cros { |
| namespace intel { |
| |
| /** |
| * \def RESULT_ENTRY_CAP |
| * Maximum number of metadata entries stored in a result buffer. Used for |
| * memory allocation purposes. |
| */ |
| #define RESULT_ENTRY_CAP 256 |
| /** |
| * \def RESULT_DATA_CAP |
| * Maximum amount of data storage in bytes allocated in result buffers. |
| */ |
| #define RESULT_DATA_CAP 73728 |
| |
| Camera3Request::Camera3Request(): |
| mCallback(nullptr), |
| mRequestId(0), |
| mCameraId(-1), |
| mSeqenceId(-1), |
| mHasInBuf(false), |
| mShouldSwapWidthHeight(false) |
| { |
| LOG1("@%s Creating request with pointer %p", __FUNCTION__, this); |
| deInit(); |
| /** |
| * Allocate the CameraBuffer objects that will be recycled for each request |
| * Since CameraBuf is refCounted the objects will be deleted when the Request |
| * is destroyed. No need to manually delete them |
| * These Camerabuffer objects are mere wrappers that will be filled when |
| * we initialize the Request object |
| */ |
| for (int i = 0; i < MAX_NUMBER_OUTPUT_STREAMS; i++) { |
| mOutCamBufPool[i] = std::make_shared<CameraBuffer>(); |
| } |
| |
| mInCamBuf = std::make_shared<CameraBuffer>(); |
| mResultBufferAllocated = false; |
| } |
| |
| Camera3Request::~Camera3Request() |
| { |
| LOG1("@%s Destroying request with pointer %p", __FUNCTION__, this); |
| mInitialized = false; |
| if (mResultBufferAllocated) { |
| freePartialResultBuffers(); |
| } |
| } |
| |
| void |
| Camera3Request::deInit() |
| { |
| std::lock_guard<std::mutex> l(mAccessLock); |
| mOutBufs.clear(); |
| mHasInBuf = false; |
| mInStream = nullptr; |
| mOutStreams.clear(); |
| mInitialized = false; |
| mMembers.mSettings.clear(); |
| mSettings.clear(); |
| mOutCamBufs.clear(); |
| mInCamBuf.reset(new CameraBuffer); |
| mBuffersPerFormat.clear(); |
| CLEAR(mRequest3); |
| } |
| |
| status_t |
| Camera3Request::init(camera3_capture_request* req, |
| IRequestCallback* cb, |
| android::CameraMetadata &settings, int cameraId) |
| { |
| status_t status = NO_ERROR; |
| PERFORMANCE_HAL_ATRACE_PARAM1("reqId", req->frame_number); |
| LOG2("@%s req, framenum:%d, inputbuf:%p, outnum:%d, outputbuf:%p", |
| __FUNCTION__, req->frame_number, req->input_buffer, |
| req->num_output_buffers, req->output_buffers); |
| if (req->input_buffer) { |
| camera3_stream_t* s = req->input_buffer->stream; |
| LOG2("@%s req, input stream, width:%d, height:%d, format:%d, stream_type:%d, usage:%d", |
| __FUNCTION__, s->width, s->height, s->format, s->stream_type, s->usage); |
| } |
| |
| if (CC_UNLIKELY(cb == nullptr)) { |
| LOGE("@%s: Invalid callback object", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| /** |
| * clean everything before we start |
| */ |
| deInit(); |
| |
| /** |
| * initialize the partial metadata result buffers |
| */ |
| status = initPartialResultBuffers(cameraId); |
| if (CC_UNLIKELY(status != NO_ERROR)) { |
| LOGE("@%s: failed to initialize partial results", __FUNCTION__); |
| return NO_INIT; |
| } |
| const camera3_stream_buffer * buffer = req->output_buffers; |
| |
| if (CC_UNLIKELY(req->num_output_buffers > MAX_NUMBER_OUTPUT_STREAMS)) { |
| LOGE("Too many output buffers for this request %dm max is %d", |
| req->num_output_buffers, MAX_NUMBER_OUTPUT_STREAMS); |
| return BAD_VALUE; |
| } |
| |
| std::unique_lock<std::mutex> l(mAccessLock); |
| |
| for (uint32_t i = 0; i < req->num_output_buffers; i++) { |
| LOG2("@%s, req, width:%d, stream type:0x%x", __FUNCTION__, |
| buffer->stream->width, |
| buffer->stream->stream_type); |
| |
| status = mOutCamBufPool[i]->init(buffer, cameraId); |
| if (status != NO_ERROR) { |
| LOGE("init output buffer fail"); |
| l.unlock(); |
| deInit(); |
| return BAD_VALUE; |
| } |
| mOutCamBufs.push_back(mOutCamBufPool[i]); |
| |
| /* |
| * Keep track of the number buffers per format |
| */ |
| std::map<int, int>::const_iterator it; |
| it = mBuffersPerFormat.find(buffer->stream->format); |
| if (it == mBuffersPerFormat.end()) { |
| mBuffersPerFormat.insert(std::pair<int, int>(buffer->stream->format, 0)); |
| } |
| |
| int typeCount = mBuffersPerFormat.at(buffer->stream->format); |
| mBuffersPerFormat.at(buffer->stream->format) = ++typeCount; |
| |
| mOutBufs.push_back(*buffer); |
| mOutBufs.at(i).release_fence = -1; |
| |
| CameraStream *stream = reinterpret_cast<CameraStream *>(buffer->stream->priv); |
| if (stream) |
| stream->incOutBuffersInHal(); |
| |
| buffer++; |
| } |
| |
| if (req->input_buffer) { |
| status = mInCamBuf->init(req->input_buffer, cameraId); |
| if (status != NO_ERROR) { |
| LOGE("init input buffer fail"); |
| l.unlock(); |
| deInit(); |
| return BAD_VALUE; |
| } |
| mHasInBuf = true; |
| mInBuf = *req->input_buffer; |
| } |
| |
| status = checkInputStream(req); |
| status |= checkOutputStreams(req); |
| if (status != NO_ERROR) { |
| LOGE("error with the request's buffers"); |
| l.unlock(); |
| deInit(); |
| return BAD_VALUE; |
| } |
| |
| mRequestId = req->frame_number; |
| mCameraId = cameraId; |
| mRequest3 = *req; |
| mCallback = cb; |
| mSettings = settings; // Read only setting metadata buffer |
| mInitialized = true; |
| |
| camera_metadata_entry_t entry = mSettings.find(ANDROID_JPEG_ORIENTATION); |
| mShouldSwapWidthHeight = entry.count > 0 && entry.data.i32[0] % 180 == 90; |
| |
| LOG2("<Request %d> camera id %d successfully initialized", mRequestId, mCameraId); |
| return NO_ERROR; |
| } |
| |
| bool Camera3Request::shouldSwapWidthHeight() const |
| { |
| return mShouldSwapWidthHeight; |
| } |
| |
| int Camera3Request::getBufferCountOfFormat(int format) const |
| { |
| std::map<int, int>::const_iterator it; |
| |
| it = mBuffersPerFormat.find(format); |
| if (it == mBuffersPerFormat.end()) { |
| return 0; |
| } |
| |
| return it->second; |
| } |
| |
| /** |
| * getNumberOutputBufs() |
| * |
| * returns the number of output buffers that this request has attached. |
| * This determines how many buffers need to be returned to the client |
| */ |
| unsigned int |
| Camera3Request::getNumberOutputBufs() |
| { |
| std::lock_guard<std::mutex> l(mAccessLock); |
| return mInitialized ? mOutBufs.size() : 0; |
| } |
| |
| /** |
| * hasInputBuf() |
| * |
| * returns true if it has input buffer. |
| */ |
| bool |
| Camera3Request::hasInputBuf() |
| { |
| std::lock_guard<std::mutex> l(mAccessLock); |
| return mInitialized && mHasInBuf; |
| } |
| |
| int |
| Camera3Request::getId() |
| { |
| std::lock_guard<std::mutex> l(mAccessLock); |
| return mInitialized ? mRequestId : -1; |
| } |
| |
| const CameraStream* |
| Camera3Request::getInputStream() |
| { |
| return mInitialized ? mInStream : nullptr; |
| } |
| |
| const std::vector<CameraStream*>* |
| Camera3Request::getOutputStreams() |
| { |
| return mInitialized ? &mOutStreams : nullptr; |
| } |
| |
| const std::vector<camera3_stream_buffer>* |
| Camera3Request::getOutputBuffers() |
| { |
| std::lock_guard<std::mutex> l(mAccessLock); |
| return mInitialized ? &mOutBufs : nullptr; |
| } |
| |
| const camera3_stream_buffer* |
| Camera3Request::getInputBuffer() |
| { |
| std::lock_guard<std::mutex> l(mAccessLock); |
| return (mInitialized && mHasInBuf) ? &mInBuf : nullptr; |
| } |
| |
| /** |
| * getPartialResultBuffer |
| * |
| * PSL implementations that produce metadata buffers in several chunks will |
| * call this method to acquire its own metadata buffer. Coordination on |
| * the usage of those buffers is responsibility of the PSL |
| */ |
| android::CameraMetadata* |
| Camera3Request::getPartialResultBuffer(unsigned int index) |
| { |
| if (CC_UNLIKELY(mPartialResultBuffers.empty() || |
| (index > mPartialResultBuffers.size()-1))) { |
| LOGE("Requesting a partial buffer that does not exist"); |
| return nullptr; |
| } |
| |
| return mPartialResultBuffers[index].metaBuf; |
| } |
| |
| /** |
| * getSettings |
| * |
| * returns the pointer to the read-only metadata buffer with the settings |
| * for this request. |
| */ |
| const android::CameraMetadata* |
| Camera3Request::getSettings() const |
| { |
| return mInitialized? &mSettings : nullptr; |
| } |
| |
| /****************************************************************************** |
| * PRIVATE PARTS |
| *****************************************************************************/ |
| |
| /** |
| * Check that the input buffers are associated to a known input stream |
| * A known input stream is the one that the private field |
| * is initialized with a pointer to the corresponding CameraStream object |
| */ |
| status_t |
| Camera3Request::checkInputStream(camera3_capture_request* request3) |
| { |
| if (request3 == nullptr) return NO_ERROR; |
| if (request3->input_buffer == nullptr) return NO_ERROR; |
| |
| camera3_stream_t* stream = request3->input_buffer->stream; |
| CheckError(!stream, BAD_VALUE, |
| "%s: Request %d: stream is nullptr!", __FUNCTION__, request3->frame_number); |
| |
| if (stream->stream_type != CAMERA3_STREAM_INPUT && |
| stream->stream_type != CAMERA3_STREAM_BIDIRECTIONAL) { |
| LOGE("%s: Request %d: wrong type:%d", |
| __FUNCTION__, request3->frame_number, stream->stream_type); |
| return BAD_VALUE; |
| } |
| if (stream->priv == nullptr) { |
| LOGE("%s: Request %d: stream is unconfigured", __FUNCTION__, request3->frame_number); |
| return BAD_VALUE; |
| } |
| |
| mInStream = static_cast<CameraStream*>(stream->priv); |
| |
| return NO_ERROR; |
| } |
| |
| /** |
| * findBuffer |
| * return a buffer associated with the stream passes as parameter |
| * in this request |
| * \param stream: CameraStream that we want to find buffers for |
| * \param warn boolean indicating if warning should be printed, if not found |
| * \return: sp to the CameraBuffer object |
| */ |
| std::shared_ptr<CameraBuffer> |
| Camera3Request::findBuffer(const CameraStream* stream, bool warn) |
| { |
| for (size_t i = 0; i< mOutCamBufs.size(); i++) { |
| if (mOutCamBufs[i]->getOwner() == stream) { |
| return mOutCamBufs[i]; |
| } |
| } |
| if (mInCamBuf != nullptr && mInCamBuf->getOwner() == stream) { |
| return mInCamBuf; |
| } |
| |
| if (warn) |
| LOGW("could not find requested buffer. invalid stream?"); |
| |
| return nullptr; |
| } |
| |
| /** |
| * Check whether the aBuffer is an input buffer for the request |
| */ |
| bool |
| Camera3Request::isInputBuffer(std::shared_ptr<CameraBuffer> buffer) |
| { |
| return mInCamBuf != nullptr && buffer.get() == mInCamBuf.get(); |
| } |
| |
| /** |
| * Check that the output buffers belong to a known stream |
| */ |
| status_t |
| Camera3Request::checkOutputStreams(camera3_capture_request* request3) |
| { |
| camera3_stream_t* stream = nullptr; |
| CameraStream* s = nullptr; |
| const camera3_stream_buffer * buffer = request3->output_buffers; |
| |
| for (uint32_t j = 0; j < request3->num_output_buffers; j++) { |
| stream = buffer->stream; |
| if (stream->priv == nullptr) { |
| LOGE("%s no output stream.", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| s = (CameraStream *)stream->priv; |
| CameraStream* tmpStream = nullptr; |
| unsigned int i = 0; |
| bool hasFlag = false; |
| for (i = 0; i < mOutStreams.size(); i++) { |
| tmpStream = static_cast<CameraStream*>(mOutStreams.at(i)); |
| if (tmpStream == s) { |
| hasFlag = true; |
| break; |
| } |
| if (s->width()*s->height() > tmpStream->width()*tmpStream->height()) { |
| mOutStreams.insert(mOutStreams.begin() + i, s); |
| break; |
| } else if ((s->width()*s->height() == tmpStream->width()*tmpStream->height()) |
| && (s->seqNo() < tmpStream->seqNo())) { |
| mOutStreams.insert(mOutStreams.begin() + i, s); |
| break; |
| } |
| } |
| if ((tmpStream == nullptr || i == mOutStreams.size()) && !hasFlag) |
| mOutStreams.push_back(s); |
| buffer++; |
| } |
| return NO_ERROR; |
| } |
| |
| /** |
| * initPartialResultBuffers |
| * |
| * Initialize the buffers that will store the partial results for each request |
| * The initialization has 2 phases: |
| * - Allocation: this is done only once in the lifetime of the request |
| * - Reset: this is done for all initialization. It means to clear the buffers |
| * where the result metadata is stored. |
| * The number of partial results is PSL specific and is queried via PlatformData |
| * Different cameraId may use different PSL |
| */ |
| status_t |
| Camera3Request::initPartialResultBuffers(int cameraId) |
| { |
| status_t status = NO_ERROR; |
| |
| if (CC_UNLIKELY(!mResultBufferAllocated)) { |
| int partialBufferCount = PlatformData::getPartialMetadataCount(cameraId); |
| status = allocatePartialResultBuffers(partialBufferCount); |
| if (CC_UNLIKELY(status != NO_ERROR)) { |
| return status; |
| } |
| } |
| // Reset the metadata buffers |
| camera_metadata_t *m; |
| for (unsigned int i = 0; i < mPartialResultBuffers.size(); i++) { |
| if (mPartialResultBuffers[i].baseBuf != nullptr) { |
| m = mPartialResultBuffers.at(i).metaBuf->release(); |
| /** |
| * It may happen that a PSL may resize the result buffer if the |
| * originally allocated is not big enough. Check for it |
| */ |
| if (CC_UNLIKELY(m != mPartialResultBuffers[i].baseBuf)) { |
| if (m == nullptr) { |
| LOGE("Cannot get metadata from result buffers."); |
| return UNKNOWN_ERROR; |
| } |
| LOGW("PSL resized result buffer (%d) in request %p", i, this); |
| reAllocateResultBuffer(m, i); |
| } |
| |
| memset(mPartialResultBuffers[i].baseBuf, 0 , |
| mPartialResultBuffers[i].size); |
| |
| /* This should not fail since it worked first time when we |
| * allocated */ |
| m = place_camera_metadata(mPartialResultBuffers[i].baseBuf, |
| mPartialResultBuffers[i].size, |
| mPartialResultBuffers[i].entryCap, |
| mPartialResultBuffers[i].dataCap); |
| mPartialResultBuffers.at(i).metaBuf->acquire(m); |
| } |
| } |
| return status; |
| } |
| |
| /** |
| * reAllocateResultBuffer |
| * |
| * In situations when the PSL needs to re-size the result buffer we need to |
| * re-allocate the result buffer to regain the ownership of the memory |
| * In that case we free the metadata buffer allocated by the framework during |
| * resize and we re-allocate it ourselves. |
| * |
| * \param m[IN]: metadata buffer allocated by the framework |
| * \param index[IN]: index in the mPartialResultBuffer vector. |
| */ |
| void Camera3Request::reAllocateResultBuffer(camera_metadata_t* m, int index) |
| { |
| MemoryManagedMetadata &mmdata = mPartialResultBuffers.at(index); |
| |
| mmdata.size = get_camera_metadata_size(m); |
| mmdata.dataCap = get_camera_metadata_data_capacity(m); |
| mmdata.entryCap = get_camera_metadata_entry_capacity(m); |
| free_camera_metadata(m); |
| if (mmdata.baseBuf) { |
| delete [] reinterpret_cast<char*>(mmdata.baseBuf); |
| } |
| mmdata.baseBuf = (void*) new char[mmdata.size]; |
| LOG2("Need to resize meta result buffers to %zu entry cap %d, data cap %d" |
| ,mmdata.size, mmdata.entryCap, mmdata.dataCap); |
| } |
| |
| /* |
| * allocatePartialResultBuffers |
| * Allocates the raw buffers that will be used to store the result metadata |
| * buffers. The memory of these metadata buffers is managed by this class |
| * so that we do not need to re-allocate the buffers for each request |
| * |
| * This allows us to clean the metadata buffer without having to re-allocate. |
| */ |
| status_t |
| Camera3Request::allocatePartialResultBuffers(int partialResultCount) |
| { |
| MemoryManagedMetadata mmdata; |
| size_t bufferSize = calculate_camera_metadata_size(RESULT_ENTRY_CAP, |
| RESULT_DATA_CAP); |
| for (int i = 0; i < partialResultCount; i++) { |
| CLEAR(mmdata); |
| camera_metadata_t *m; |
| mmdata.baseBuf = (void*) new char[bufferSize]; |
| |
| m = place_camera_metadata(mmdata.baseBuf, bufferSize, RESULT_ENTRY_CAP, |
| RESULT_DATA_CAP); |
| if (m == nullptr) { |
| LOGE("Failed to allocate memory for result metadata buffer"); |
| goto bailout; |
| } |
| mmdata.metaBuf = new android::CameraMetadata(m); |
| mmdata.size = bufferSize; |
| mmdata.entryCap = RESULT_ENTRY_CAP; |
| mmdata.dataCap = RESULT_DATA_CAP; |
| mPartialResultBuffers.push_back(mmdata); |
| } |
| |
| mResultBufferAllocated = true; |
| return NO_ERROR; |
| |
| bailout: |
| freePartialResultBuffers(); |
| return NO_MEMORY; |
| } |
| |
| void |
| Camera3Request::freePartialResultBuffers(void) |
| { |
| for (unsigned int i = 0; i < mPartialResultBuffers.size(); i++) { |
| if (mPartialResultBuffers[i].baseBuf != nullptr) { |
| mPartialResultBuffers[i].metaBuf->release(); |
| delete[] reinterpret_cast<char*>(mPartialResultBuffers[i].baseBuf); |
| delete mPartialResultBuffers[i].metaBuf; |
| } |
| } |
| mPartialResultBuffers.clear(); |
| mResultBufferAllocated = false; |
| } |
| |
| } /* namespace intel */ |
| } /* namespace cros */ |