/* * Copyright (C) 2013-2017 Intel Corporation * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd * * 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 "Camera3Request" #include "LogHelper.h" #include "PerformanceTraces.h" #include "CameraStream.h" #include "Camera3Request.h" #include "PlatformData.h" #include <fcntl.h> NAMESPACE_DECLARATION { /** * \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), mSequenceId(-1) { LOGI("@%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++) { mOutputBufferPool[i] = std::make_shared<CameraBuffer>(); } mInputBuffer = std::make_shared<CameraBuffer>(); mResultBufferAllocated = false; } Camera3Request::~Camera3Request() { LOGI("@%s Destroying request with pointer %p", __FUNCTION__, this); mInitialized = false; if (mResultBufferAllocated) { freePartialResultBuffers(); } } void Camera3Request::dumpSetting() { static unsigned int count = 0; count++; if (gDumpInterval > 1) { if (count % gDumpInterval != 0) { return; } } LOGD("%s:%d: enter", __func__, __LINE__); std::string fileName(gDumpPath); if (CC_UNLIKELY(LogHelper::isDumpTypeEnable(CAMERA_DUMP_META))) { const char intent_val[7][20] = {"CUSTOM", "PREVIEW", "STILL_CAPTURE", "VIDEO_RECORD", "VIDEO_SNAPSHOT", "ZERO_SHUTTER_LAG", "MANUAL"}; camera_metadata_entry_t entry; uint8_t intent = 0; entry = mSettings.find(ANDROID_CONTROL_CAPTURE_INTENT); if (entry.count == 1) { intent = entry.data.u8[0]; } std::string strIntentName = intent_val[intent]; fileName += "dumpmeta_" + std::to_string(mCameraId) + "_" + strIntentName + "_setting_" + std::to_string(mRequestId); LOGI("%s filename is %s", __FUNCTION__, fileName.data()); int fd = open(fileName.data(), O_RDWR | O_CREAT, 0666); if (fd != -1) { mSettings.dump(fd, 2); } else { LOGE("dumpSetting: open failed, errmsg: %s\n", strerror(errno)); } close(fd); } } void Camera3Request::dumpResults() { static unsigned int count = 0; count++; if (gDumpInterval > 1) { if (count % gDumpInterval != 0) { return; } } if (CC_UNLIKELY(LogHelper::isDumpTypeEnable(CAMERA_DUMP_META))) { std::string fileName(gDumpPath); const char intent_val[7][20] = {"CUSTOM", "PREVIEW", "STILL_CAPTURE", "VIDEO_RECORD", "VIDEO_SNAPSHOT", "ZERO_SHUTTER_LAG", "MANUAL"}; camera_metadata_entry_t entry; uint8_t intent = 0; entry = mSettings.find(ANDROID_CONTROL_CAPTURE_INTENT); if (entry.count == 1) { intent = entry.data.u8[0]; } std::string strIntentName = intent_val[intent]; fileName += "dumpmeta_" + std::to_string(mCameraId) + "_" + strIntentName + "_result_" + std::to_string(mRequestId); LOGI("%s filename is %s", __FUNCTION__, fileName.data()); int fd = open(fileName.data(), O_RDWR | O_CREAT, 0666); if (fd != -1) { mPartialResultBuffers[0].metaBuf->dump(fd, 2); } else { LOGE("dumpResult: open failed, errmsg: %s\n", strerror(errno)); } close(fd); } } void Camera3Request::deInit() { std::lock_guard<std::mutex> l(mAccessLock); mOutBuffers.clear(); mInBuffers.clear(); mInStreams.clear(); mOutStreams.clear(); mInitialized = false; mMembers.mSettings.clear(); mSettings.clear(); mOutputBuffers.clear(); mInputBuffer.reset(); mBuffersPerFormat.clear(); CLEAR(mRequest3); } status_t Camera3Request::init(camera3_capture_request* req, IRequestCallback* cb, CameraMetadata &settings, int cameraId) { status_t status = NO_ERROR; PERFORMANCE_HAL_ATRACE_PARAM1("reqId", req->frame_number); LOGD("@%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 (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++) { LOGD("@%s, req, width:%d, stream type:0x%x", __FUNCTION__, buffer->stream->width, buffer->stream->stream_type); mOutputBufferPool[i]->setRequestId(req->frame_number); status = mOutputBufferPool[i]->init(buffer, cameraId); if (status != NO_ERROR) { LOGE("init output buffer fail"); l.unlock(); deInit(); return BAD_VALUE; } mOutputBuffers.push_back(mOutputBufferPool[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; mOutBuffers.push_back(*buffer); mOutBuffers.at(i).release_fence = -1; CameraStream *stream = reinterpret_cast<CameraStream *>(buffer->stream->priv); if (stream) stream->incOutBuffersInHal(); buffer++; } if (req->input_buffer) { if (!mInputBuffer.get()) mInputBuffer = std::make_shared<CameraBuffer>(); status = mInputBuffer->init(req->input_buffer, cameraId); if (status != NO_ERROR) { LOGE("init input buffer fail"); l.unlock(); deInit(); return BAD_VALUE; } mInBuffers.push_back(*(req->input_buffer)); } status = checkInputStreams(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; mError = false; mMetadtaFilled = false; LOGD("<Request %d> camera id %d successfully initialized", mRequestId, mCameraId); return NO_ERROR; } 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 ? mOutBuffers.size() : 0; } /** * getNumberInputBufs() * * returns the number of input buffers that this request has attached. */ unsigned int Camera3Request::getNumberInputBufs() { std::lock_guard<std::mutex> l(mAccessLock); return mInitialized ? mInBuffers.size() : 0; } int Camera3Request::getId() { std::lock_guard<std::mutex> l(mAccessLock); return mInitialized ? mRequestId : -1; } bool Camera3Request::isAnyBufActive() { if(!mInitialized) { ALOGD("@%s not init, return!", __FUNCTION__); return false; } for (auto it : mOutputBuffers) { if(it->isfenceActive() == true) return true; } return false; } int Camera3Request::waitAllBufsSignaled() { PERFORMANCE_ATRACE_CALL(); LOGD("@%s : reqId %d", __FUNCTION__, mRequestId); int ret = 0; for (auto it : mOutputBuffers) { ret = it->fenceWait(); CheckError(ret != 0, ret;, "@%s, wait buffer fence signaled failed for req %d", __FUNCTION__, mRequestId); } LOGD("@%s : done for reqId %d", __FUNCTION__, mRequestId); return ret; } const std::vector<CameraStreamNode*>* Camera3Request::getInputStreams() { return mInitialized ? &mInStreams : nullptr; } const std::vector<CameraStreamNode*>* Camera3Request::getOutputStreams() { return mInitialized ? &mOutStreams : nullptr; } const std::vector<camera3_stream_buffer>* Camera3Request::getOutputBuffers() { std::lock_guard<std::mutex> l(mAccessLock); return mInitialized ? &mOutBuffers : nullptr; } const std::vector<camera3_stream_buffer>* Camera3Request::getInputBuffers() { std::lock_guard<std::mutex> l(mAccessLock); return mInitialized ? &mInBuffers : 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 */ 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; } void Camera3Request::notifyFinalmetaFilled() { std::unique_lock<std::mutex> l(mResultLock); mMetadtaFilled = true; mCondition.notify_all(); } /** * getAndWaitforFilledResults * the final result metadata, check if you really need the final result or * only wants to get the result meta instance. the func now only used * in JpegEncodeTask::readExifInfoFromAndroidResult. */ CameraMetadata* Camera3Request::getAndWaitforFilledResults(unsigned int index) { std::unique_lock<std::mutex> l(mResultLock); if (mMetadtaFilled == false) { if(mCondition.wait_for(l, std::chrono::seconds(1)) == std::cv_status::timeout) { LOGW("@%s %d: request %d wait for CLmetadataFilled timeout", __FUNCTION__, __LINE__, mRequestId); } else { LOGI("@%s %d: request %d wait for CLmetadataFilled ", __FUNCTION__, __LINE__, mRequestId); } } return getPartialResultBuffer(index); } /** * getSettings * * returns the pointer to the read-only metadata buffer with the settings * for this request. */ const 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::checkInputStreams(camera3_capture_request * request3) { camera3_stream_t* stream = nullptr; CameraStreamNode* streamNode = nullptr; if (request3->input_buffer != nullptr) { stream = request3->input_buffer->stream; if (stream->stream_type != CAMERA3_STREAM_INPUT && stream->stream_type != CAMERA3_STREAM_BIDIRECTIONAL) { LOGE("%s: Request %d: Input buffer not from input stream!", __FUNCTION__, request3->frame_number); return BAD_VALUE; } if (stream->priv == nullptr) { LOGE("Input Stream not configured"); return BAD_VALUE; } streamNode = reinterpret_cast<CameraStreamNode *>(stream->priv); mInStreams.push_back(streamNode); } 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(CameraStreamNode *stream, bool warn) { for (size_t i = 0; i< mOutputBuffers.size(); i++) { if (mOutputBuffers[i]->getOwner() == stream) return mOutputBuffers[i]; } if (mInputBuffer != nullptr && mInputBuffer->getOwner() == stream) return mInputBuffer; 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 mInputBuffer != nullptr && buffer.get() == mInputBuffer.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]; LOGI("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 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_DECLARATION_END